From 9d93982b04bd58bf87eaa261fbbc5f9e4ee22c60 Mon Sep 17 00:00:00 2001 From: Thijmen de Gooijer Date: Fri, 7 Aug 2009 08:16:16 +0000 Subject: [PATCH] Initial import. This version is somewhere around 0.1.9, or as Martin put it "this should be a fairly current version". TDG --- README.MULTIPLAYER | 68 + include/XPMPMultiplayer.h | 471 +++++ include/XPMPPlaneRenderer.h | 34 + png.h | 3283 +++++++++++++++++++++++++++++++++++ pngconf.h | 1348 ++++++++++++++ src/BitmapUtils.cpp | 977 +++++++++++ src/BitmapUtils.h | 169 ++ src/CSLLoaderThread.cpp | 101 ++ src/CSLLoaderThread.h | 41 + src/Interpolation.h | 58 + src/Interpolation.i | 113 ++ src/PlatformUtils.h | 124 ++ src/PlatformUtils.lin.cpp | 81 + src/PlatformUtils.mac.cpp | 337 ++++ src/PlatformUtils.win.cpp | 262 +++ src/TexUtils.cpp | 247 +++ src/TexUtils.h | 30 + src/XOGLUtils.cpp | 152 ++ src/XOGLUtils.h | 74 + src/XObjDefs.cpp | 84 + src/XObjDefs.h | 112 ++ src/XObjReadWrite.cpp | 411 +++++ src/XObjReadWrite.h | 31 + src/XPMPMultiplayer.cpp | 500 ++++++ src/XPMPMultiplayerCSL.cpp | 957 ++++++++++ src/XPMPMultiplayerCSL.h | 107 ++ src/XPMPMultiplayerObj.cpp | 845 +++++++++ src/XPMPMultiplayerObj.h | 54 + src/XPMPMultiplayerVars.cpp | 42 + src/XPMPMultiplayerVars.h | 183 ++ src/XPMPPlaneRenderer.cpp | 576 ++++++ src/XUtils.cpp | 605 +++++++ src/XUtils.h | 130 ++ zconf.h | 279 +++ zlib.h | 893 ++++++++++ 35 files changed, 13779 insertions(+) create mode 100644 README.MULTIPLAYER create mode 100644 include/XPMPMultiplayer.h create mode 100644 include/XPMPPlaneRenderer.h create mode 100644 png.h create mode 100644 pngconf.h create mode 100644 src/BitmapUtils.cpp create mode 100644 src/BitmapUtils.h create mode 100644 src/CSLLoaderThread.cpp create mode 100644 src/CSLLoaderThread.h create mode 100644 src/Interpolation.h create mode 100644 src/Interpolation.i create mode 100644 src/PlatformUtils.h create mode 100644 src/PlatformUtils.lin.cpp create mode 100644 src/PlatformUtils.mac.cpp create mode 100644 src/PlatformUtils.win.cpp create mode 100644 src/TexUtils.cpp create mode 100644 src/TexUtils.h create mode 100644 src/XOGLUtils.cpp create mode 100644 src/XOGLUtils.h create mode 100644 src/XObjDefs.cpp create mode 100644 src/XObjDefs.h create mode 100644 src/XObjReadWrite.cpp create mode 100644 src/XObjReadWrite.h create mode 100644 src/XPMPMultiplayer.cpp create mode 100644 src/XPMPMultiplayerCSL.cpp create mode 100644 src/XPMPMultiplayerCSL.h create mode 100644 src/XPMPMultiplayerObj.cpp create mode 100644 src/XPMPMultiplayerObj.h create mode 100644 src/XPMPMultiplayerVars.cpp create mode 100644 src/XPMPMultiplayerVars.h create mode 100644 src/XPMPPlaneRenderer.cpp create mode 100644 src/XUtils.cpp create mode 100644 src/XUtils.h create mode 100644 zconf.h create mode 100644 zlib.h diff --git a/README.MULTIPLAYER b/README.MULTIPLAYER new file mode 100644 index 000000000..e75d46ff7 --- /dev/null +++ b/README.MULTIPLAYER @@ -0,0 +1,68 @@ +Copyright (c) 2006, Ben Supnik and Chris Serio. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +****************************************************************************** + XSQUAWKBOX MULTIPLAYER ENGINE - README +****************************************************************************** + +Revision History + 3/14/05 - Initial draft + +INTRO + +This snippet of code is the XSB multiplayer engine, that is, the code +responsible for visualizing planes. It is provided totally as-is with +no guarantees of working or being rmotely useful. + +Two files, XPLMMultiplayer.cpp and XPLMPlaneRenderer.cpp implement the +lib. You must include XPLMMultiplayer.h to use it, and provide a text file +with your plugin to config multiplayer. + +HISTORY + +PATH NAMES AND CROSS-PLATFORM CODE + +Paths for XPMP are always "native". This means: + +- Backslash separators on Windows. +- Forward slash separators on Macintosh and Linux. +- For Macintosh (which has both "HFS" and "Posix" style paths) posix paths + are used. + +Clients initializing the library are responsible for passing paths in these +formats. (Macintosh clients can convert from HFS to Posix using the routine +HFS2PosixPath, which internally uses CFURL for the conversion.) + +The X-Plane SDK uses native paths, but on Macintosh uses HFS paths. XPMP +on Mac converts paths from HFS to Posix at all points of interaction with +the SDK. + +The paths in some X-Plane formats like OBJ can often have any directory +separator. These paths are always partial paths; XPMP converts them to +native separators when they are read in. + +Therefore the following rules should be followed when using/modifying XPMP: + +- Always pass native paths to the lib and expect native paths out. +- When getting file paths from external sources (like OBJ files) make them + native immediately. +- Mac only: In the lib wrap any SDK call with HFS->Posix conversion if + needed. \ No newline at end of file diff --git a/include/XPMPMultiplayer.h b/include/XPMPMultiplayer.h new file mode 100644 index 000000000..7723bf9b2 --- /dev/null +++ b/include/XPMPMultiplayer.h @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2004, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _XPLMMultiplayer_h_ +#define _XPLMMultiplayer_h_ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************************ + * X-PLANE MULTIPLAYER + ************************************************************************************/ + +/* + Multiplayer - THEORY OF OPERATION + + The multiplayer API allows plug-ins to control aircraft visible to other plug-ins and + the user via x-plane. It effectively provides glue between a series of observers + that wish to render or in other ways act upon those planes. + + A plug-in can control zero or more planes, and zero or more plug-ins can control planes. + However, each plane is controlled by exactly one plug-in. A plug-in thus dynamically + allocates planes to control. A plug-in registers a callback which is used to pull + information. The plug-in may decide to not return information or state that that + information is unchanged. + + A plug-in can also read the current aircrafts or any of their data. Aircraft data is + cached to guarantee minimum computing of data. + + Each 'kind' of data has an enumeration and corresponding structure.*/ + + +/************************************************************************************ + * PLANE DATA TYPES + ************************************************************************************/ + +/* + * XPMPPosition_t + * + * This data structure contains the basic position info for an aircraft. + * Lat and lon are the position of the aircraft in the world. They are double-precision to + * provide reasonably precise positioning anywhere. + * Elevation is in feet above mean sea level. + * + * Pitch, roll, and heading define the aircraft's orientation. Heading is in degrees, positive + * is clockwise from north. Pitch is the number of degrees, positive is nose up, and roll + * is positive equals roll right. + * + * Note that there is no notion of aircraft velocity or acceleration; you will be queried for + * your position every rendering frame. Higher level APIs can use velocity and acceleration. + * + */ +typedef struct { + long size; + double lat; + double lon; + double elevation; + float pitch; + float roll; + float heading; +} XPMPPlanePosition_t; + + +/* + * XPMPLightStatus + * + * This enum defines the settings for the lights bitfield in XPMPPlaneSurfaces_t + * + * The upper 16 bit of the light code (timeOffset) should be initialized only once + * with a random number by the application. This number will be used to have strobes + * flashing at different times. + */ +union xpmp_LightStatus { + unsigned int lightFlags; + struct { + unsigned int timeOffset : 16; + + unsigned int landLights : 1; + unsigned int bcnLights : 1; + unsigned int strbLights : 1; + unsigned int navLights : 1; + + unsigned int flashPattern : 4; + }; +}; + +/* + * Light flash patterns + */ +enum { + xpmp_Lights_Pattern_Default = 0, // Jets: one strobe flash, short beacon (-*---*---*---) + xpmp_Lights_Pattern_EADS = 1, // Airbus+EADS: strobe flashes twice (-*-*-----*-*--), short beacon + xpmp_Lights_Pattern_GA = 2 // GA: one strobe flash, long beacon (-*--------*---) +}; + + +/* + * XPMPPlaneSurfaces_t + * + * This data structure will contain information about the external physical configuration of the plane, + * things you would notice if you are seeing it from outside. This includes flap position, gear position, + * etc. + * + * Lights is a 32 bit field with flags as defined in XPMPLightStatus + * + */ +typedef struct { + long size; + float gearPosition; + float flapRatio; + float spoilerRatio; + float speedBrakeRatio; + float slatRatio; + float wingSweep; + float thrust; + float yolkPitch; + float yolkHeading; + float yolkRoll; + xpmp_LightStatus lights; +} XPMPPlaneSurfaces_t; + + +/* + * XPMPTransponderMode + * + * These enumerations define the way the transponder of a given plane is operating. + * + */ +enum { + xpmpTransponderMode_Standby, + xpmpTransponderMode_Mode3A, + xpmpTransponderMode_ModeC, + xpmpTransponderMode_ModeC_Low, + xpmpTransponderMode_ModeC_Ident +}; +typedef int XPMPTransponderMode; + +/* + * XPMPPlaneRadar_t + * + * This structure defines information about an aircraft visible to radar. Eventually it can include + * information about radar profiles, stealth technology, radar jamming, etc. + * + */ +typedef struct { + long size; + long code; + XPMPTransponderMode mode; +} XPMPPlaneRadar_t; + +/* + * XPMPPlaneData + * + * This enum defines the different categories of aircraft information we can query about. + * + */ +enum { + xpmpDataType_Position = 1L << 1, + xpmpDataType_Surfaces = 1L << 2, + xpmpDataType_Radar = 1L << 3 +}; +typedef int XPMPPlaneDataType; + +/* + * XPMPPlaneCallbackResult + * + * This definfes the different responses to asking for information. + * + */ +enum { + xpmpData_Unavailable = 0, /* The information has never been specified. */ + xpmpData_Unchanged = 1, /* The information from the last time the plug-in was aksed. */ + xpmpData_NewData = 2 /* The information has changed this sim cycle. */ +}; +typedef int XPMPPlaneCallbackResult; + +/* + * XPMPPlaneID + * + * This is a unique ID for an aircraft created by a plug-in. + * + */ +typedef void * XPMPPlaneID; + +/************************************************************************************ + * PLANE CREATION API + ************************************************************************************/ + +/* + * XPMPPlaneData_f + * + * This is the aircraft data providing function. It is called no more than once per sim + * cycle per data type by the plug-in manager to get data about your plane. The data passed + * in is a pointer to one of the above structures. The function specifies the datatype, and the + * last data you provided is passed in. + * + */ +typedef XPMPPlaneCallbackResult (* XPMPPlaneData_f)( + XPMPPlaneID inPlane, + XPMPPlaneDataType inDataType, + void * ioData, + void * inRefcon); + +/* + * XPMPMultiplayerInit + * + * This routine initializes the multiplayer library. + * + * inPlaneList is a ptr to a fully qualified file name that is a text file of ICAO -> model + * mappings. The xsb_aircraft.txt file can be used as a template. (Please note: other + * XSB files are NOT necessary and are not necessarily available under open source license.) + * + * inDoc8643 is the path to the ICAO document 8643, available at + * http://www.icao.int/anb/ais/TxtFiles/Doc8643.txt. This file lists all aircraft types + * with their manufacturer, ICAO equipment code and aircraft category. + * + * The two prefs funcs each take an ini section and key and return a value and also take + * a default. The renderer uses them for configuration. Currently the following keys are + * needed: + * + * section key type default description + * planes full_distance float 3.0 + * planes max_full_count int 50 + * + * The return value is a string indicating any problem that may have gone wrong in a human-readable + * form, or an empty string if initalizatoin was okay. + * + * Call this once from your XPluginStart routine. + * + */ +const char * XPMPMultiplayerInit( + const char * inCSLFolder, + const char * inRelatedPath, + const char * inTexturePath, + const char * inDoc8643, + const char * inDefaltICAO, + int (* inIntPrefsFunc)(const char *, const char *, int), + float (* inFloatPrefsFunc)(const char *, const char *, float)); + +/* + * XPMPMultiplayerEnable + * + * Enable drawing of multiplayer planes. Call this once from your XPluginEnable routine to + * grab multiplayer; an empty string is returned on success, or a human-readable error message + * otherwise. + * + */ +const char * XPMPMultiplayerEnable(void); + +/* + * XPMPLoadPlanesIfNecessary + * + * This routine checks what planes are loaded and loads any that we didn't get. + * Call it after you oare enabled if it isn't the first time to set up models. + * + */ +void XPMPLoadPlanesIfNecessary(void); + +/* + * XPMPCreatePlane + * + * This function creates a new plane for a plug-in and returns it. Pass in an ICAO aircraft ID code, + * a livery string and a data function for fetching dynamic information. + * + */ + XPMPPlaneID XPMPCreatePlane( + const char * inICAOCode, + const char * inAirline, + const char * inLivery, + XPMPPlaneData_f inDataFunc, + void * inRefcon); + +/* + * XPMPDestroyPlane + * + * This function deallocates a created aircraft. + * + */ + void XPMPDestroyPlane(XPMPPlaneID); + +/* + * XPMPChangePlaneModel + * + * This routine lets you change an aircraft's model. This can be useful if a remote + * player changes planes or new information comes over the network asynchronously. + * + */ + void XPMPChangePlaneModel( + XPMPPlaneID inPlaneID, + const char * inICAOCode, + const char * inAirline, + const char * inLivery); + +/* + * XPMPSetDefaultPlaneICAO + * + * This routine controls what ICAO is used as a backup search criteria for a not-found plane. + * + */ +void XPMPSetDefaultPlaneICAO( + const char * inICAO); + +/************************************************************************************ + * PLANE OBSERVATION API + ************************************************************************************/ + +/* + * XPMPPlaneNotification + * + * These are the various notifications you receive when you register a notifier + * function. + * + */ +enum { + xpmp_PlaneNotification_Created = 1, + xpmp_PlaneNotification_ModelChanged = 2, + xpmp_PlaneNotification_Destroyed = 3 +}; +typedef int XPMPPlaneNotification; + +/* + * XPMPPlaneNotifier_f + * + * You can pass a notifier to find out when a plane is created or destroyed or other + * data changes. + * + */ +typedef void (* XPMPPlaneNotifier_f)( + XPMPPlaneID inPlaneID, + XPMPPlaneNotification inNotification, + void * inRefcon); + +/* + * XPMPCountPlanes + * + * This function returns the number of planes in existence. + * + */ + long XPMPCountPlanes(void); + +/* + * XPMPGetNthPlane + * + * This function returns the plane ID of the Nth plane. + * + */ + XPMPPlaneID XPMPGetNthPlane( + long index); + + +/* + * XPMPGetPlaneICAOAndLivery + * + * Given a plane, this function returns optionally its ICAO code or livery. Pass string buffers + * or NULL if you do not want the information. + * + */ + void XPMPGetPlaneICAOAndLivery( + XPMPPlaneID inPlane, + char * outICAOCode, // Can be NULL + char * outLivery); // Can be NULL + +/* + * XPMPRegisterPlaneCreateDestroyFunc + * + * This function registers a notifier functionfor obeserving planes being created and destroyed. + * + */ + void XPMPRegisterPlaneNotifierFunc( + XPMPPlaneNotifier_f inFunc, + void * inRefcon); + +/* + * XPMPUnregisterPlaneCreateDestroyFunc + * + * This function canceles a registration for a notifier functionfor obeserving + * planes being created and destroyed. + */ + void XPMPUnregisterPlaneNotifierFunc( + XPMPPlaneNotifier_f inFunc, + void * inRefcon); + +/* + * XPMPGetPlaneData + * + * This function fetches specific data about a plane in the sim. Pass in a plane ID, a data type + * and a pointer to a struct for the data. The struct's size field must be filled in! The data + * will be returned if possible, as well as the sim cycle the data is from, or 0 if the data could not + * be fetched. + * + */ + int XPMPGetPlaneData( + XPMPPlaneID inPlane, + XPMPPlaneDataType inDataType, + void * outData); + +/* + * XPMPIsICAOValid + * + * This functions searches through our global vector of valid ICAO codes and returns true if there + * was a match and false if there wasn't. + * + */ + bool XPMPIsICAOValid( + const char * inICAO); + +/************************************************************************************ + * PLANE RENDERING API + ************************************************************************************/ + +/* + * XPMPRenderPlanes_f + * + * You can register a callback to draw planes yourself. If you do this, the XPMP will not + * draw multiplayer planes out the cockpit window; do it yourself! Use the data access API + * to get plane info and then draw them. You are responsible for all planes. + * + */ +typedef void (* XPMPRenderPlanes_f)( + void * inRef); + +/* + * XPMPSetPlaneRenderer + * + * This function setse the plane renderer. You can pass NULL for the function to restore + * the default renderer. + * + */ + void XPMPSetPlaneRenderer( + XPMPRenderPlanes_f inRenderer, + void * inRef); + +/* + * XPMPDumpOneCycle + * + * This causes the plane renderer implementation to dump debug info to the error.out for one + * cycle after it is called - useful for figuring out why your models don't look right. + * + */ +void XPMPDumpOneCycle(void); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/include/XPMPPlaneRenderer.h b/include/XPMPPlaneRenderer.h new file mode 100644 index 000000000..f19e0dc95 --- /dev/null +++ b/include/XPMPPlaneRenderer.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef XPLMPLANERENDERER_H +#define XPLMPLANERENDERER_H + +// Theoretically you can plug in your own plane-rendering +// function (although in practice this isn't real useful. +// These functions do "the drawing" once per frame. + +void XPMPInitDefaultPlaneRenderer(void); +void XPMPDefaultPlaneRenderer(void); + +#endif \ No newline at end of file diff --git a/png.h b/png.h new file mode 100644 index 000000000..f059910e6 --- /dev/null +++ b/png.h @@ -0,0 +1,3283 @@ +/* png.h - header file for PNG reference library + * + * libpng version 1.2.5 - October 3, 2002 + * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.2.5 - October 3, 2002: Glenn + * See also "Contributing Authors", below. + * + * Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + * 1.0.8rc1 1 10008 2.1.0.8rc1 + * 1.0.8 1 10008 2.1.0.8 + * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + * 1.0.9rc1 1 10009 2.1.0.9rc1 + * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + * 1.0.9rc2 1 10009 2.1.0.9rc2 + * 1.0.9 1 10009 2.1.0.9 + * 1.0.10beta1 1 10010 2.1.0.10beta1 + * 1.0.10rc1 1 10010 2.1.0.10rc1 + * 1.0.10 1 10010 2.1.0.10 + * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + * 1.0.11rc1 1 10011 2.1.0.11rc1 + * 1.0.11 1 10011 2.1.0.11 + * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + * 1.0.12rc1 2 10012 2.1.0.12rc1 + * 1.0.12 2 10012 2.1.0.12 + * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) + * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + * 1.2.0rc1 3 10200 3.1.2.0rc1 + * 1.2.0 3 10200 3.1.2.0 + * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 + * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + * 1.2.1 3 10201 3.1.2.1 + * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + * 1.0.13 10 10013 10.so.0.1.0.13 + * 1.2.2 12 10202 12.so.0.1.2.2 + * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + * 1.2.3 12 10203 12.so.0.1.2.3 + * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 + * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + * 1.0.14 10 10014 10.so.0.1.0.14 + * 1.2.4 13 10204 12.so.0.1.2.4 + * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 + * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 + * 1.0.15 10 10015 10.so.0.1.0.15 + * 1.2.5 13 10205 12.so.0.1.2.5 + * + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng.txt or libpng.3 for more information. The PNG specification + * is available as RFC 2083 + * and as a W3C Recommendation + */ + +/* + * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + * + * If you modify libpng you may insert additional notices immediately following + * this sentence. + * + * libpng versions 1.0.7, July 1, 2000, through 1.2.5, October 3, 2002, are + * Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are + * distributed according to the same disclaimer and license as libpng-1.0.6 + * with the following individuals added to the list of Contributing Authors + * + * Simon-Pierre Cadieux + * Eric S. Raymond + * Gilles Vollant + * + * and with the following additions to the disclaimer: + * + * There is no warranty against interference with your enjoyment of the + * library or against infringement. There is no warranty that our + * efforts or the library will fulfill any of your particular purposes + * or needs. This library is provided with all faults, and the entire + * risk of satisfactory quality, performance, accuracy, and effort is with + * the user. + * + * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are + * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson + * Distributed according to the same disclaimer and license as libpng-0.96, + * with the following individuals added to the list of Contributing Authors: + * + * Tom Lane + * Glenn Randers-Pehrson + * Willem van Schaik + * + * libpng versions 0.89, June 1996, through 0.96, May 1997, are + * Copyright (c) 1996, 1997 Andreas Dilger + * Distributed according to the same disclaimer and license as libpng-0.88, + * with the following individuals added to the list of Contributing Authors: + * + * John Bowler + * Kevin Bracey + * Sam Bushell + * Magnus Holmgren + * Greg Roelofs + * Tom Tanner + * + * libpng versions 0.5, May 1995, through 0.88, January 1996, are + * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + * + * For the purposes of this copyright and license, "Contributing Authors" + * is defined as the following set of individuals: + * + * Andreas Dilger + * Dave Martindale + * Guy Eric Schalnat + * Paul Schmidt + * Tim Wegner + * + * The PNG Reference Library is supplied "AS IS". The Contributing Authors + * and Group 42, Inc. disclaim all warranties, expressed or implied, + * including, without limitation, the warranties of merchantability and of + * fitness for any purpose. The Contributing Authors and Group 42, Inc. + * assume no liability for direct, indirect, incidental, special, exemplary, + * or consequential damages, which may result from the use of the PNG + * Reference Library, even if advised of the possibility of such damage. + * + * Permission is hereby granted to use, copy, modify, and distribute this + * source code, or portions hereof, for any purpose, without fee, subject + * to the following restrictions: + * + * 1. The origin of this source code must not be misrepresented. + * + * 2. Altered versions must be plainly marked as such and + * must not be misrepresented as being the original source. + * + * 3. This Copyright notice may not be removed or altered from + * any source or altered source distribution. + * + * The Contributing Authors and Group 42, Inc. specifically permit, without + * fee, and encourage the use of this source code as a component to + * supporting the PNG file format in commercial products. If you use this + * source code in a product, acknowledgment is not required but would be + * appreciated. + */ + +/* + * A "png_get_copyright" function is available, for convenient use in "about" + * boxes and the like: + * + * printf("%s",png_get_copyright(NULL)); + * + * Also, the PNG logo (in PNG format, of course) is supplied in the + * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + */ + +/* + * Libpng is OSI Certified Open Source Software. OSI Certified is a + * certification mark of the Open Source Initiative. + */ + +/* + * The contributing authors would like to thank all those who helped + * with testing, bug fixes, and patience. This wouldn't have been + * possible without all of you. + * + * Thanks to Frank J. T. Wojcik for helping with the documentation. + */ + +/* + * Y2K compliance in libpng: + * ========================= + * + * October 3, 2002 + * + * Since the PNG Development group is an ad-hoc body, we can't make + * an official declaration. + * + * This is your unofficial assurance that libpng from version 0.71 and + * upward through 1.2.5 are Y2K compliant. It is my belief that earlier + * versions were also Y2K compliant. + * + * Libpng only has three year fields. One is a 2-byte unsigned integer + * that will hold years up to 65535. The other two hold the date in text + * format, and will hold years up to 9999. + * + * The integer is + * "png_uint_16 year" in png_time_struct. + * + * The strings are + * "png_charp time_buffer" in png_struct and + * "near_time_buffer", which is a local character string in png.c. + * + * There are seven time-related functions: + * png.c: png_convert_to_rfc_1123() in png.c + * (formerly png_convert_to_rfc_1152() in error) + * png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c + * png_convert_from_time_t() in pngwrite.c + * png_get_tIME() in pngget.c + * png_handle_tIME() in pngrutil.c, called in pngread.c + * png_set_tIME() in pngset.c + * png_write_tIME() in pngwutil.c, called in pngwrite.c + * + * All handle dates properly in a Y2K environment. The + * png_convert_from_time_t() function calls gmtime() to convert from system + * clock time, which returns (year - 1900), which we properly convert to + * the full 4-digit year. There is a possibility that applications using + * libpng are not passing 4-digit years into the png_convert_to_rfc_1123() + * function, or that they are incorrectly passing only a 2-digit year + * instead of "year - 1900" into the png_convert_from_struct_tm() function, + * but this is not under our control. The libpng documentation has always + * stated that it works with 4-digit years, and the APIs have been + * documented as such. + * + * The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned + * integer to hold the year, and can hold years as large as 65535. + * + * zlib, upon which libpng depends, is also Y2K compliant. It contains + * no date-related code. + * + * Glenn Randers-Pehrson + * libpng maintainer + * PNG Development Group + */ + +#ifndef PNG_H +#define PNG_H + +/* This is not the place to learn how to use libpng. The file libpng.txt + * describes how to use libpng, and the file example.c summarizes it + * with some code on which to build. This file is useful for looking + * at the actual function definitions and structure components. + */ + +/* Version information for png.h - this should match the version in png.c */ +#define PNG_LIBPNG_VER_STRING "1.2.5" + +#define PNG_LIBPNG_VER_SONUM 0 +#define PNG_LIBPNG_VER_DLLNUM %DLLNUM% + +/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ +#define PNG_LIBPNG_VER_MAJOR 1 +#define PNG_LIBPNG_VER_MINOR 2 +#define PNG_LIBPNG_VER_RELEASE 5 +/* This should match the numeric part of the final component of + * PNG_LIBPNG_VER_STRING, omitting any leading zero: */ + +#define PNG_LIBPNG_VER_BUILD 0 + +#define PNG_LIBPNG_BUILD_ALPHA 1 +#define PNG_LIBPNG_BUILD_BETA 2 +#define PNG_LIBPNG_BUILD_RC 3 +#define PNG_LIBPNG_BUILD_STABLE 4 +#define PNG_LIBPNG_BUILD_TYPEMASK 7 +#define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with STABLE only */ +#define PNG_LIBPNG_BUILD_TYPE 4 + +/* Careful here. At one time, Guy wanted to use 082, but that would be octal. + * We must not include leading zeros. + * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only + * version 1.0.0 was mis-numbered 100 instead of 10000). From + * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ +#define PNG_LIBPNG_VER 10205 /* 1.2.5 */ + +#ifndef PNG_VERSION_INFO_ONLY + +/* include the compression library's header */ +#include "zlib.h" + +/* include all user configurable info, including optional assembler routines */ +#include "pngconf.h" + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* This file is arranged in several sections. The first section contains + * structure and type definitions. The second section contains the external + * library functions, while the third has the internal library functions, + * which applications aren't expected to use directly. + */ + +#ifndef PNG_NO_TYPECAST_NULL +#define int_p_NULL (int *)NULL +#define png_bytep_NULL (png_bytep)NULL +#define png_bytepp_NULL (png_bytepp)NULL +#define png_doublep_NULL (png_doublep)NULL +#define png_error_ptr_NULL (png_error_ptr)NULL +#define png_flush_ptr_NULL (png_flush_ptr)NULL +#define png_free_ptr_NULL (png_free_ptr)NULL +#define png_infopp_NULL (png_infopp)NULL +#define png_malloc_ptr_NULL (png_malloc_ptr)NULL +#define png_read_status_ptr_NULL (png_read_status_ptr)NULL +#define png_rw_ptr_NULL (png_rw_ptr)NULL +#define png_structp_NULL (png_structp)NULL +#define png_uint_16p_NULL (png_uint_16p)NULL +#define png_voidp_NULL (png_voidp)NULL +#define png_write_status_ptr_NULL (png_write_status_ptr)NULL +#else +#define int_p_NULL NULL +#define png_bytep_NULL NULL +#define png_bytepp_NULL NULL +#define png_doublep_NULL NULL +#define png_error_ptr_NULL NULL +#define png_flush_ptr_NULL NULL +#define png_free_ptr_NULL NULL +#define png_infopp_NULL NULL +#define png_malloc_ptr_NULL NULL +#define png_read_status_ptr_NULL NULL +#define png_rw_ptr_NULL NULL +#define png_structp_NULL NULL +#define png_uint_16p_NULL NULL +#define png_voidp_NULL NULL +#define png_write_status_ptr_NULL NULL +#endif + +/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */ +#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) +/* Version information for C files, stored in png.c. This had better match + * the version above. + */ +#ifdef PNG_USE_GLOBAL_ARRAYS +PNG_EXPORT_VAR (const char) png_libpng_ver[18]; + /* need room for 99.99.99beta99z */ +#else +#define png_libpng_ver png_get_header_ver(NULL) +#endif + +#ifdef PNG_USE_GLOBAL_ARRAYS +/* This was removed in version 1.0.5c */ +/* Structures to facilitate easy interlacing. See png.c for more details */ +PNG_EXPORT_VAR (const int FARDATA) png_pass_start[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_inc[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_ystart[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_yinc[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_mask[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_dsp_mask[7]; +#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW +PNG_EXPORT_VAR (const int FARDATA) png_pass_width[7]; +#endif +/* This isn't currently used. If you need it, see png.c for more details. +PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7]; +*/ +#endif + +#endif /* PNG_NO_EXTERN */ + +/* Three color definitions. The order of the red, green, and blue, (and the + * exact size) is not important, although the size of the fields need to + * be png_byte or png_uint_16 (as defined below). + */ +typedef struct png_color_struct +{ + png_byte red; + png_byte green; + png_byte blue; +} png_color; +typedef png_color FAR * png_colorp; +typedef png_color FAR * FAR * png_colorpp; + +typedef struct png_color_16_struct +{ + png_byte index; /* used for palette files */ + png_uint_16 red; /* for use in red green blue files */ + png_uint_16 green; + png_uint_16 blue; + png_uint_16 gray; /* for use in grayscale files */ +} png_color_16; +typedef png_color_16 FAR * png_color_16p; +typedef png_color_16 FAR * FAR * png_color_16pp; + +typedef struct png_color_8_struct +{ + png_byte red; /* for use in red green blue files */ + png_byte green; + png_byte blue; + png_byte gray; /* for use in grayscale files */ + png_byte alpha; /* for alpha channel files */ +} png_color_8; +typedef png_color_8 FAR * png_color_8p; +typedef png_color_8 FAR * FAR * png_color_8pp; + +/* + * The following two structures are used for the in-core representation + * of sPLT chunks. + */ +typedef struct png_sPLT_entry_struct +{ + png_uint_16 red; + png_uint_16 green; + png_uint_16 blue; + png_uint_16 alpha; + png_uint_16 frequency; +} png_sPLT_entry; +typedef png_sPLT_entry FAR * png_sPLT_entryp; +typedef png_sPLT_entry FAR * FAR * png_sPLT_entrypp; + +/* When the depth of the sPLT palette is 8 bits, the color and alpha samples + * occupy the LSB of their respective members, and the MSB of each member + * is zero-filled. The frequency member always occupies the full 16 bits. + */ + +typedef struct png_sPLT_struct +{ + png_charp name; /* palette name */ + png_byte depth; /* depth of palette samples */ + png_sPLT_entryp entries; /* palette entries */ + png_int_32 nentries; /* number of palette entries */ +} png_sPLT_t; +typedef png_sPLT_t FAR * png_sPLT_tp; +typedef png_sPLT_t FAR * FAR * png_sPLT_tpp; + +#ifdef PNG_TEXT_SUPPORTED +/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, + * and whether that contents is compressed or not. The "key" field + * points to a regular zero-terminated C string. The "text", "lang", and + * "lang_key" fields can be regular C strings, empty strings, or NULL pointers. + * However, the * structure returned by png_get_text() will always contain + * regular zero-terminated C strings (possibly empty), never NULL pointers, + * so they can be safely used in printf() and other string-handling functions. + */ +typedef struct png_text_struct +{ + int compression; /* compression value: + -1: tEXt, none + 0: zTXt, deflate + 1: iTXt, none + 2: iTXt, deflate */ + png_charp key; /* keyword, 1-79 character description of "text" */ + png_charp text; /* comment, may be an empty string (ie "") + or a NULL pointer */ + png_size_t text_length; /* length of the text string */ +#ifdef PNG_iTXt_SUPPORTED + png_size_t itxt_length; /* length of the itxt string */ + png_charp lang; /* language code, 0-79 characters + or a NULL pointer */ + png_charp lang_key; /* keyword translated UTF-8 string, 0 or more + chars or a NULL pointer */ +#endif +} png_text; +typedef png_text FAR * png_textp; +typedef png_text FAR * FAR * png_textpp; +#endif + +/* Supported compression types for text in PNG files (tEXt, and zTXt). + * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */ +#define PNG_TEXT_COMPRESSION_NONE_WR -3 +#define PNG_TEXT_COMPRESSION_zTXt_WR -2 +#define PNG_TEXT_COMPRESSION_NONE -1 +#define PNG_TEXT_COMPRESSION_zTXt 0 +#define PNG_ITXT_COMPRESSION_NONE 1 +#define PNG_ITXT_COMPRESSION_zTXt 2 +#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ + +/* png_time is a way to hold the time in an machine independent way. + * Two conversions are provided, both from time_t and struct tm. There + * is no portable way to convert to either of these structures, as far + * as I know. If you know of a portable way, send it to me. As a side + * note - PNG has always been Year 2000 compliant! + */ +typedef struct png_time_struct +{ + png_uint_16 year; /* full year, as in, 1995 */ + png_byte month; /* month of year, 1 - 12 */ + png_byte day; /* day of month, 1 - 31 */ + png_byte hour; /* hour of day, 0 - 23 */ + png_byte minute; /* minute of hour, 0 - 59 */ + png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ +} png_time; +typedef png_time FAR * png_timep; +typedef png_time FAR * FAR * png_timepp; + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +/* png_unknown_chunk is a structure to hold queued chunks for which there is + * no specific support. The idea is that we can use this to queue + * up private chunks for output even though the library doesn't actually + * know about their semantics. + */ +typedef struct png_unknown_chunk_t +{ + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* libpng-using applications should NOT directly modify this byte. */ + png_byte location; /* mode of operation at read time */ +} +png_unknown_chunk; +typedef png_unknown_chunk FAR * png_unknown_chunkp; +typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp; +#endif + +/* png_info is a structure that holds the information in a PNG file so + * that the application can find out the characteristics of the image. + * If you are reading the file, this structure will tell you what is + * in the PNG file. If you are writing the file, fill in the information + * you want to put into the PNG file, then call png_write_info(). + * The names chosen should be very close to the PNG specification, so + * consult that document for information about the meaning of each field. + * + * With libpng < 0.95, it was only possible to directly set and read the + * the values in the png_info_struct, which meant that the contents and + * order of the values had to remain fixed. With libpng 0.95 and later, + * however, there are now functions that abstract the contents of + * png_info_struct from the application, so this makes it easier to use + * libpng with dynamic libraries, and even makes it possible to use + * libraries that don't have all of the libpng ancillary chunk-handing + * functionality. + * + * In any case, the order of the parameters in png_info_struct should NOT + * be changed for as long as possible to keep compatibility with applications + * that use the old direct-access method with png_info_struct. + * + * The following members may have allocated storage attached that should be + * cleaned up before the structure is discarded: palette, trans, text, + * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile, + * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these + * are automatically freed when the info structure is deallocated, if they were + * allocated internally by libpng. This behavior can be changed by means + * of the png_data_freer() function. + * + * More allocation details: all the chunk-reading functions that + * change these members go through the corresponding png_set_* + * functions. A function to clear these members is available: see + * png_free_data(). The png_set_* functions do not depend on being + * able to point info structure members to any of the storage they are + * passed (they make their own copies), EXCEPT that the png_set_text + * functions use the same storage passed to them in the text_ptr or + * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns + * functions do not make their own copies. + */ +typedef struct png_info_struct +{ + /* the following are necessary for every PNG file */ + png_uint_32 width; /* width of image in pixels (from IHDR) */ + png_uint_32 height; /* height of image in pixels (from IHDR) */ + png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ + png_uint_32 rowbytes; /* bytes needed to hold an untransformed row */ + png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ + png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ + png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ + png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ + png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ + /* The following three should have been named *_method not *_type */ + png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ + png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ + png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + + /* The following is informational only on read, and not used on writes. */ + png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte spare_byte; /* to align the data, and for future use */ + png_byte signature[8]; /* magic bytes read by libpng from start of file */ + + /* The rest of the data is optional. If you are reading, check the + * valid field to see if the information in these are valid. If you + * are writing, set the valid field to those chunks you want written, + * and initialize the appropriate fields below. + */ + +#if defined(PNG_gAMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + /* The gAMA chunk describes the gamma characteristics of the system + * on which the image was created, normally in the range [1.0, 2.5]. + * Data is valid if (valid & PNG_INFO_gAMA) is non-zero. + */ + float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */ +#endif + +#if defined(PNG_sRGB_SUPPORTED) + /* GR-P, 0.96a */ + /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */ + png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */ +#endif + +#if defined(PNG_TEXT_SUPPORTED) + /* The tEXt, and zTXt chunks contain human-readable textual data in + * uncompressed, compressed, and optionally compressed forms, respectively. + * The data in "text" is an array of pointers to uncompressed, + * null-terminated C strings. Each chunk has a keyword that describes the + * textual data contained in that chunk. Keywords are not required to be + * unique, and the text string may be empty. Any number of text chunks may + * be in an image. + */ + int num_text; /* number of comments read/to write */ + int max_text; /* current size of text array */ + png_textp text; /* array of comments read/to write */ +#endif /* PNG_TEXT_SUPPORTED */ + +#if defined(PNG_tIME_SUPPORTED) + /* The tIME chunk holds the last time the displayed image data was + * modified. See the png_time struct for the contents of this struct. + */ + png_time mod_time; +#endif + +#if defined(PNG_sBIT_SUPPORTED) + /* The sBIT chunk specifies the number of significant high-order bits + * in the pixel data. Values are in the range [1, bit_depth], and are + * only specified for the channels in the pixel data. The contents of + * the low-order bits is not specified. Data is valid if + * (valid & PNG_INFO_sBIT) is non-zero. + */ + png_color_8 sig_bit; /* significant bits in color channels */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ +defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The tRNS chunk supplies transparency data for paletted images and + * other image types that don't need a full alpha channel. There are + * "num_trans" transparency values for a paletted image, stored in the + * same order as the palette colors, starting from index 0. Values + * for the data are in the range [0, 255], ranging from fully transparent + * to fully opaque, respectively. For non-paletted images, there is a + * single color specified that should be treated as fully transparent. + * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. + */ + png_bytep trans; /* transparent values for paletted image */ + png_color_16 trans_values; /* transparent color for non-palette image */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The bKGD chunk gives the suggested image background color if the + * display program does not have its own background color and the image + * is needs to composited onto a background before display. The colors + * in "background" are normally in the same color space/depth as the + * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. + */ + png_color_16 background; +#endif + +#if defined(PNG_oFFs_SUPPORTED) + /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards + * and downwards from the top-left corner of the display, page, or other + * application-specific co-ordinate space. See the PNG_OFFSET_ defines + * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. + */ + png_int_32 x_offset; /* x offset on page */ + png_int_32 y_offset; /* y offset on page */ + png_byte offset_unit_type; /* offset units type */ +#endif + +#if defined(PNG_pHYs_SUPPORTED) + /* The pHYs chunk gives the physical pixel density of the image for + * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ + * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. + */ + png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ + png_uint_32 y_pixels_per_unit; /* vertical pixel density */ + png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ +#endif + +#if defined(PNG_hIST_SUPPORTED) + /* The hIST chunk contains the relative frequency or importance of the + * various palette entries, so that a viewer can intelligently select a + * reduced-color palette, if required. Data is an array of "num_palette" + * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) + * is non-zero. + */ + png_uint_16p hist; +#endif + +#ifdef PNG_cHRM_SUPPORTED + /* The cHRM chunk describes the CIE color characteristics of the monitor + * on which the PNG was created. This data allows the viewer to do gamut + * mapping of the input image to ensure that the viewer sees the same + * colors in the image as the creator. Values are in the range + * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero. + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + float x_white; + float y_white; + float x_red; + float y_red; + float x_green; + float y_green; + float x_blue; + float y_blue; +#endif +#endif + +#if defined(PNG_pCAL_SUPPORTED) + /* The pCAL chunk describes a transformation between the stored pixel + * values and original physical data values used to create the image. + * The integer range [0, 2^bit_depth - 1] maps to the floating-point + * range given by [pcal_X0, pcal_X1], and are further transformed by a + * (possibly non-linear) transformation function given by "pcal_type" + * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ + * defines below, and the PNG-Group's PNG extensions document for a + * complete description of the transformations and how they should be + * implemented, and for a description of the ASCII parameter strings. + * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. + */ + png_charp pcal_purpose; /* pCAL chunk description string */ + png_int_32 pcal_X0; /* minimum value */ + png_int_32 pcal_X1; /* maximum value */ + png_charp pcal_units; /* Latin-1 string giving physical units */ + png_charpp pcal_params; /* ASCII strings containing parameter values */ + png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ + png_byte pcal_nparams; /* number of parameters given in pcal_params */ +#endif + +/* New members added in libpng-1.0.6 */ +#ifdef PNG_FREE_ME_SUPPORTED + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + /* storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + png_size_t unknown_chunks_num; +#endif + +#if defined(PNG_iCCP_SUPPORTED) + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_charp iccp_profile; /* International Color Consortium profile data */ + /* Note to maintainer: should be png_bytep */ + png_uint_32 iccp_proflen; /* ICC profile data length */ + png_byte iccp_compression; /* Always zero */ +#endif + +#if defined(PNG_sPLT_SUPPORTED) + /* data on sPLT chunks (there may be more than one). */ + png_sPLT_tp splt_palettes; + png_uint_32 splt_palettes_num; +#endif + +#if defined(PNG_sCAL_SUPPORTED) + /* The sCAL chunk describes the actual physical dimensions of the + * subject matter of the graphic. The chunk contains a unit specification + * a byte value, and two ASCII strings representing floating-point + * values. The values are width and height corresponsing to one pixel + * in the image. This external representation is converted to double + * here. Data values are valid if (valid & PNG_INFO_sCAL) is non-zero. + */ + png_byte scal_unit; /* unit of physical scale */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + double scal_pixel_width; /* width of one pixel */ + double scal_pixel_height; /* height of one pixel */ +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ +#endif +#endif + +#if defined(PNG_INFO_IMAGE_SUPPORTED) + /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) non-zero */ + /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ + png_bytepp row_pointers; /* the image bits */ +#endif + +#if defined(PNG_FIXED_POINT_SUPPORTED) && defined(PNG_gAMA_SUPPORTED) + png_fixed_point int_gamma; /* gamma of image, if (valid & PNG_INFO_gAMA) */ +#endif + +#if defined(PNG_cHRM_SUPPORTED) && defined(PNG_FIXED_POINT_SUPPORTED) + png_fixed_point int_x_white; + png_fixed_point int_y_white; + png_fixed_point int_x_red; + png_fixed_point int_y_red; + png_fixed_point int_x_green; + png_fixed_point int_y_green; + png_fixed_point int_x_blue; + png_fixed_point int_y_blue; +#endif + +} png_info; + +typedef png_info FAR * png_infop; +typedef png_info FAR * FAR * png_infopp; + +/* Maximum positive integer used in PNG is (2^31)-1 */ +#define PNG_MAX_UINT ((png_uint_32)0x7fffffffL) + +/* These describe the color_type field in png_info. */ +/* color type masks */ +#define PNG_COLOR_MASK_PALETTE 1 +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 + +/* color types. Note that not all combinations are legal */ +#define PNG_COLOR_TYPE_GRAY 0 +#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) +#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) +#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) +#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) +/* aliases */ +#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA +#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA + +/* This is for compression type. PNG 1.0-1.2 only define the single type. */ +#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ +#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE + +/* This is for filter type. PNG 1.0-1.2 only define the single type. */ +#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ +#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ +#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE + +/* These are for the interlacing type. These values should NOT be changed. */ +#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ +#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ +#define PNG_INTERLACE_LAST 2 /* Not a valid value */ + +/* These are for the oFFs chunk. These values should NOT be changed. */ +#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */ +#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */ +#define PNG_OFFSET_LAST 2 /* Not a valid value */ + +/* These are for the pCAL chunk. These values should NOT be changed. */ +#define PNG_EQUATION_LINEAR 0 /* Linear transformation */ +#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */ +#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */ +#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ +#define PNG_EQUATION_LAST 4 /* Not a valid value */ + +/* These are for the sCAL chunk. These values should NOT be changed. */ +#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ +#define PNG_SCALE_METER 1 /* meters per pixel */ +#define PNG_SCALE_RADIAN 2 /* radians per pixel */ +#define PNG_SCALE_LAST 3 /* Not a valid value */ + +/* These are for the pHYs chunk. These values should NOT be changed. */ +#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ +#define PNG_RESOLUTION_METER 1 /* pixels/meter */ +#define PNG_RESOLUTION_LAST 2 /* Not a valid value */ + +/* These are for the sRGB chunk. These values should NOT be changed. */ +#define PNG_sRGB_INTENT_PERCEPTUAL 0 +#define PNG_sRGB_INTENT_RELATIVE 1 +#define PNG_sRGB_INTENT_SATURATION 2 +#define PNG_sRGB_INTENT_ABSOLUTE 3 +#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */ + +/* This is for text chunks */ +#define PNG_KEYWORD_MAX_LENGTH 79 + +/* Maximum number of entries in PLTE/sPLT/tRNS arrays */ +#define PNG_MAX_PALETTE_LENGTH 256 + +/* These determine if an ancillary chunk's data has been successfully read + * from the PNG header, or if the application has filled in the corresponding + * data in the info_struct to be written into the output file. The values + * of the PNG_INFO_ defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001 +#define PNG_INFO_sBIT 0x0002 +#define PNG_INFO_cHRM 0x0004 +#define PNG_INFO_PLTE 0x0008 +#define PNG_INFO_tRNS 0x0010 +#define PNG_INFO_bKGD 0x0020 +#define PNG_INFO_hIST 0x0040 +#define PNG_INFO_pHYs 0x0080 +#define PNG_INFO_oFFs 0x0100 +#define PNG_INFO_tIME 0x0200 +#define PNG_INFO_pCAL 0x0400 +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_uint_32 rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info FAR * png_row_infop; +typedef png_row_info FAR * FAR * png_row_infopp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. + */ +typedef struct png_struct_def png_struct; +typedef png_struct FAR * png_structp; + +typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); +typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t)); +typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp)); +typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32, + int)); +typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp, + png_row_infop, png_bytep)); +#endif + +#if defined(PNG_USER_CHUNKS_SUPPORTED) +typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp)); +#endif +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* WRITE only */ + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t)); +typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp)); + +/* The structure that holds the information to read and write PNG files. + * The only people who need to care about what is inside of this are the + * people who will be modifying the library for their own special needs. + * It should NOT be accessed directly by an application, except to store + * the jmp_buf. + */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmpbuf; /* used in png_error */ +#endif + png_error_ptr error_fn; /* function for printing errors and aborting */ + png_error_ptr warning_fn; /* function for printing warnings */ + png_voidp error_ptr; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn; /* function for writing output data */ + png_rw_ptr read_data_fn; /* function for reading input data */ + png_voidp io_ptr; /* ptr to application struct for I/O functions */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + png_user_transform_ptr read_user_transform_fn; /* user read transform */ +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_user_transform_ptr write_user_transform_fn; /* user write transform */ +#endif + +/* These were added in libpng-1.0.2 */ +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_voidp user_transform_ptr; /* user supplied struct for user transform */ + png_byte user_transform_depth; /* bit depth of user transformed pixels */ + png_byte user_transform_channels; /* channels in user transformed pixels */ +#endif +#endif + + png_uint_32 mode; /* tells us where we are in the PNG file */ + png_uint_32 flags; /* flags indicating various things to libpng */ + png_uint_32 transformations; /* which transformations to perform */ + + z_stream zstream; /* pointer to decompression structure (below) */ + png_bytep zbuf; /* buffer for zlib */ + png_size_t zbuf_size; /* size of zbuf */ + int zlib_level; /* holds zlib compression level */ + int zlib_method; /* holds zlib compression method */ + int zlib_window_bits; /* holds zlib compression window bits */ + int zlib_mem_level; /* holds zlib compression memory level */ + int zlib_strategy; /* holds zlib compression strategy */ + + png_uint_32 width; /* width of image in pixels */ + png_uint_32 height; /* height of image in pixels */ + png_uint_32 num_rows; /* number of rows in current pass */ + png_uint_32 usr_width; /* width of row at start of write */ + png_uint_32 rowbytes; /* size of row in bytes */ + png_uint_32 irowbytes; /* size of current interlaced row in bytes */ + png_uint_32 iwidth; /* width of current interlaced row in pixels */ + png_uint_32 row_number; /* current row in interlace pass */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row */ + png_bytep row_buf; /* buffer to save current (unfiltered) row */ + png_bytep sub_row; /* buffer to save "sub" row when filtering */ + png_bytep up_row; /* buffer to save "up" row when filtering */ + png_bytep avg_row; /* buffer to save "avg" row when filtering */ + png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ + png_row_info row_info; /* used for transformation routines */ + + png_uint_32 idat_size; /* current IDAT size for read */ + png_uint_32 crc; /* current chunk CRC value */ + png_colorp palette; /* palette from the input file */ + png_uint_16 num_palette; /* number of color entries in palette */ + png_uint_16 num_trans; /* number of transparency values */ + png_byte chunk_name[5]; /* null-terminated name of current chunk */ + png_byte compression; /* file compression type (always 0) */ + png_byte filter; /* file filter type (always 0) */ + png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + png_byte pass; /* current interlace pass (0 - 6) */ + png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ + png_byte color_type; /* color type of file */ + png_byte bit_depth; /* bit depth of file */ + png_byte usr_bit_depth; /* bit depth of users row */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ + png_byte usr_channels; /* channels at start of write */ + png_byte sig_bytes; /* magic bytes read/written from start of file */ + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +#ifdef PNG_LEGACY_SUPPORTED + png_byte filler; /* filler byte for pixel expansion */ +#else + png_uint_16 filler; /* filler bytes for pixel expansion */ +#endif +#endif + +#if defined(PNG_bKGD_SUPPORTED) + png_byte background_gamma_type; +# ifdef PNG_FLOATING_POINT_SUPPORTED + float background_gamma; +# endif + png_color_16 background; /* background color in screen gamma space */ +#if defined(PNG_READ_GAMMA_SUPPORTED) + png_color_16 background_1; /* background normalized to gamma 1.0 */ +#endif +#endif /* PNG_bKGD_SUPPORTED */ + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_flush_ptr output_flush_fn;/* Function for flushing output */ + png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows; /* number of rows written since last flush */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + int gamma_shift; /* number of "insignificant" bits 16-bit gamma */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + float gamma; /* file gamma value */ + float screen_gamma; /* screen gamma value (display_exponent) */ +#endif +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_bytep gamma_from_1; /* converts from 1.0 to screen */ + png_bytep gamma_to_1; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ + png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) + png_color_8 sig_bit; /* significant bits in each available channel */ +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift; /* shift for significant bit tranformation */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ + || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans; /* transparency values for paletted files */ + png_color_16 trans_values; /* transparency values for non-paletted files */ +#endif + + png_read_status_ptr read_row_fn; /* called after each row is decoded */ + png_write_status_ptr write_row_fn; /* called after each row is encoded */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn; /* called after header data fully read */ + png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */ + png_progressive_end_ptr end_fn; /* called after image is complete */ + png_bytep save_buffer_ptr; /* current location in save_buffer */ + png_bytep save_buffer; /* buffer for previously read data */ + png_bytep current_buffer_ptr; /* current location in current_buffer */ + png_bytep current_buffer; /* buffer for recently used data */ + png_uint_32 push_length; /* size of current input chunk */ + png_uint_32 skip_length; /* bytes to skip in input data */ + png_size_t save_buffer_size; /* amount of data now in save_buffer */ + png_size_t save_buffer_max; /* total size of save_buffer */ + png_size_t buffer_size; /* total amount of available input data */ + png_size_t current_buffer_size; /* amount of data now in current_buffer */ + int process_mode; /* what push library is currently doing */ + int cur_palette; /* current push library palette index */ + +# if defined(PNG_TEXT_SUPPORTED) + png_size_t current_text_size; /* current size of text input data */ + png_size_t current_text_left; /* how much text left to read in input */ + png_charp current_text; /* current text chunk buffer */ + png_charp current_text_ptr; /* current location in current_text */ +# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */ + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* for the Borland special 64K segment handler */ + png_bytepp offset_table_ptr; + png_bytep offset_table; + png_uint_16 offset_table_number; + png_uint_16 offset_table_count; + png_uint_16 offset_table_count_free; +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) + png_bytep palette_lookup; /* lookup table for dithering */ + png_bytep dither_index; /* index translation for palette files */ +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED) + png_uint_16p hist; /* histogram */ +#endif + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + png_byte heuristic_method; /* heuristic for row filter selection */ + png_byte num_prev_filters; /* number of weights for previous rows */ + png_bytep prev_filters; /* filter type(s) of previous row(s) */ + png_uint_16p filter_weights; /* weight(s) for previous line(s) */ + png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ + png_uint_16p filter_costs; /* relative filter calculation cost */ + png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ +#endif + +#if defined(PNG_TIME_RFC1123_SUPPORTED) + png_charp time_buffer; /* String to hold RFC 1123 time text */ +#endif + +/* New members added in libpng-1.0.6 */ + +#ifdef PNG_FREE_ME_SUPPORTED + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ +#endif + +#if defined(PNG_USER_CHUNKS_SUPPORTED) + png_voidp user_chunk_ptr; + png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + int num_chunk_list; + png_bytep chunk_list; +#endif + +/* New members added in libpng-1.0.3 */ +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_byte rgb_to_gray_status; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff; + png_uint_16 rgb_to_gray_green_coeff; + png_uint_16 rgb_to_gray_blue_coeff; +#endif + +/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ + defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* changed from png_byte to png_uint_32 at version 1.2.0 */ +#ifdef PNG_1_0_X + png_byte mng_features_permitted; +#else + png_uint_32 mng_features_permitted; +#endif /* PNG_1_0_X */ +#endif + +/* New member added in libpng-1.0.7 */ +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_fixed_point int_gamma; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) + png_byte filter_type; +#endif + +#if defined(PNG_1_0_X) || (defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)) +/* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */ + png_uint_32 row_buf_size; +#endif + +/* New members added in libpng-1.2.0 */ +#if !defined(PNG_1_0_X) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) + png_byte mmx_bitdepth_threshold; + png_uint_32 mmx_rowbytes_threshold; + png_uint_32 asm_flags; +#endif + +/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ +#ifdef PNG_USER_MEM_SUPPORTED + png_voidp mem_ptr; /* user supplied struct for mem functions */ + png_malloc_ptr malloc_fn; /* function for allocating memory */ + png_free_ptr free_fn; /* function for freeing memory */ +#endif + +/* New member added in libpng-1.0.13 and 1.2.0 */ + png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ + +#if defined(PNG_READ_DITHER_SUPPORTED) +/* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep dither_sort; /* working sort array */ + png_bytep index_to_palette; /* where the original index currently is */ + /* in the palette */ + png_bytep palette_to_index; /* which original index points to this */ + /* palette color */ +#endif + +}; + + +/* This prevents a compiler error in png.c if png.c and png.h are both at + version 1.2.5 + */ +typedef png_structp version_1_2_5; + +typedef png_struct FAR * FAR * png_structpp; + +/* Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + */ + +/* Returns the version number of the library */ +extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void)); + +/* Tell lib we have already handled the first magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr, + int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (ie return non-zero). + */ +extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, + png_size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). + */ +extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num)); + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +extern PNG_EXPORT(png_structp,png_create_read_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)); + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +extern PNG_EXPORT(png_structp,png_create_write_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)); + +extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size) + PNGARG((png_structp png_ptr)); + +extern PNG_EXPORT(void,png_set_compression_buffer_size) + PNGARG((png_structp png_ptr, png_uint_32 size)); + +/* Reset the compression stream */ +extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr)); + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +extern PNG_EXPORT(png_structp,png_create_read_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +extern PNG_EXPORT(png_structp,png_create_write_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +#endif + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_bytep data, png_size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr)); + +/* Allocate and initialize the info structure */ +extern PNG_EXPORT(png_infop,png_create_info_struct) + PNGARG((png_structp png_ptr)); + +/* Initialize the info structure (old interface - DEPRECATED) */ +extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr)); +#undef png_info_init +#define png_info_init(info_ptr) png_info_init_3(&info_ptr, sizeof(png_info)); +extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr, + png_size_t png_info_struct_size)); + +/* Writes all the PNG information before the image. */ +extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* read the information before the actual image data. */ +extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#if defined(PNG_TIME_RFC1123_SUPPORTED) +extern PNG_EXPORT(png_charp,png_convert_to_rfc1123) + PNGARG((png_structp png_ptr, png_timep ptime)); +#endif + +#if !defined(_WIN32_WCE) +/* "time.h" functions are not supported on WindowsCE */ +#if defined(PNG_WRITE_tIME_SUPPORTED) +/* convert from a struct tm to png_time */ +extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime, + struct tm FAR * ttime)); + +/* convert from time_t to png_time. Uses gmtime() */ +extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime, + time_t ttime)); +#endif /* PNG_WRITE_tIME_SUPPORTED */ +#endif /* _WIN32_WCE */ + +#if defined(PNG_READ_EXPAND_SUPPORTED) +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +/* Expand the grayscale to 24-bit RGB if necessary. */ +extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +/* Reduce RGB to grayscale. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, + int error_action, double red, double green )); +#endif +extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green )); +extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp + png_ptr)); +#endif + +extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth, + png_colorp palette)); + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 24-bit RGB images. */ +extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +#define PNG_FILLER_BEFORE 0 +#define PNG_FILLER_AFTER 1 +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr, + png_color_8p true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. */ +extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) +/* Handle alpha and tRNS by replacing with a background color. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)); +#endif +#define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +#define PNG_BACKGROUND_GAMMA_SCREEN 1 +#define PNG_BACKGROUND_GAMMA_FILE 2 +#define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +/* strip the second byte of information from a 16-bit depth file. */ +extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +/* Turn on dithering, and reduce the palette to the number of colors available. */ +extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_uint_16p histogram, int full_dither)); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) +/* Handle gamma correction. Screen_gamma=(display_exponent) */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, + double screen_gamma, double default_file_gamma)); +#endif +#endif + +#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */ +/* Deprecated and will be removed. Use png_permit_mng_features() instead. */ +extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr, + int empty_plte_permitted)); +#endif + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +/* Set how many lines between output flushes - 0 for no flushing */ +extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr)); +#endif + +/* optional update palette with requested transformations */ +extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr)); + +/* optional call to update the users info structure */ +extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* read one or more rows of image data. */ +extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); + +/* read a row of data. */ +extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr, + png_bytep row, + png_bytep display_row)); + +/* read the whole image into memory at once. */ +extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr, + png_bytepp image)); + +/* write a row of image data */ +extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr, + png_bytep row)); + +/* write a few rows of image data */ +extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_uint_32 num_rows)); + +/* write the image data */ +extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, + png_bytepp image)); + +/* writes the end of the PNG file. */ +extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* read the end of the PNG file. */ +extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* free any memory associated with the png_info_struct */ +extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr, + png_infopp info_ptr_ptr)); + +/* free any memory associated with the png_struct and the png_info_structs */ +extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp + png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* free all memory used by the read (old method - NOT DLL EXPORTED) */ +extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr, + png_infop end_info_ptr)); + +/* free any memory associated with the png_struct and the png_info_structs */ +extern PNG_EXPORT(void,png_destroy_write_struct) + PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); + +/* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ +extern void png_write_destroy PNGARG((png_structp png_ptr)); + +/* set the libpng method of handling chunk CRC errors */ +extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, + int crit_action, int ancil_action)); + +/* Values for png_set_crc_action() to say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explination of the compression functions. + */ + +/* set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, + int filters)); + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */ +/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ + * defines, either the default (minimum-sum-of-absolute-differences), or + * the experimental method (weighted-minimum-sum-of-absolute-differences). + * + * Weights are factors >= 1.0, indicating how important it is to keep the + * filter type consistent between rows. Larger numbers mean the current + * filter is that many times as likely to be the same as the "num_weights" + * previous filters. This is cumulative for each previous row with a weight. + * There needs to be "num_weights" values in "filter_weights", or it can be + * NULL if the weights aren't being specified. Weights have no influence on + * the selection of the first row filter. Well chosen weights can (in theory) + * improve the compression for a given image. + * + * Costs are factors >= 1.0 indicating the relative decoding costs of a + * filter type. Higher costs indicate more decoding expense, and are + * therefore less likely to be selected over a filter with lower computational + * costs. There needs to be a value in "filter_costs" for each valid filter + * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't + * setting the costs. Costs try to improve the speed of decompression without + * unduly increasing the compressed image size. + * + * A negative weight or cost indicates the default value is to be used, and + * values in the range [0.0, 1.0) indicate the value is to remain unchanged. + * The default values for both weights and costs are currently 1.0, but may + * change if good general weighting/cost heuristics can be found. If both + * the weights and costs are set to 1.0, this degenerates the WEIGHTED method + * to the UNWEIGHTED method, but with added encoding time/computation. + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, + int heuristic_method, int num_weights, png_doublep filter_weights, + png_doublep filter_costs)); +#endif +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +/* Heuristic used for row filter selection. These defines should NOT be + * changed. + */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer caclulations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr, + int level)); + +extern PNG_EXPORT(void,png_set_compression_mem_level) + PNGARG((png_structp png_ptr, int mem_level)); + +extern PNG_EXPORT(void,png_set_compression_strategy) + PNGARG((png_structp png_ptr, int strategy)); + +extern PNG_EXPORT(void,png_set_compression_window_bits) + PNGARG((png_structp png_ptr, int window_bits)); + +extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr, + int method)); + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng.txt for + * more information. + */ + +#if !defined(PNG_NO_STDIO) +/* Initialize the input/output for the PNG file to the default functions. */ +extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + */ +extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr)); + +extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr, + png_read_status_ptr read_row_fn)); + +extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr read_user_transform_fn)); +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr write_user_transform_fn)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp + png_ptr, png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr) + PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp + png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr, + png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn)); + +/* returns the user pointer associated with the push read functions */ +extern PNG_EXPORT(png_voidp,png_get_progressive_ptr) + PNGARG((png_structp png_ptr)); + +/* function to be called when data becomes available */ +extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep buffer, png_size_t buffer_size)); + +/* function that combines rows. Not very much different than the + * png_combine_row() call. Is this even used????? + */ +extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr, + png_bytep old_row, png_bytep new_row)); +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, + png_uint_32 size)); + +#if defined(PNG_1_0_X) +# define png_malloc_warn png_malloc +#else +/* Added at libpng version 1.2.4 */ +extern PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr, + png_uint_32 size)); +#endif + +/* frees a pointer allocated by png_malloc() */ +extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); + +#if defined(PNG_1_0_X) +/* Function to allocate memory for zlib. */ +extern PNG_EXPORT(voidpf,png_zalloc) PNGARG((voidpf png_ptr, uInt items, + uInt size)); + +/* Function to free memory for zlib */ +extern PNG_EXPORT(void,png_zfree) PNGARG((voidpf png_ptr, voidpf ptr)); +#endif + +/* Free data that was allocated internally */ +extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 free_me, int num)); +#ifdef PNG_FREE_ME_SUPPORTED +/* Reassign responsibility for freeing existing data, whether allocated + * by libpng or by the application */ +extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, + png_infop info_ptr, int freer, png_uint_32 mask)); +#endif +/* assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008 +#define PNG_FREE_ICCP 0x0010 +#define PNG_FREE_SPLT 0x0020 +#define PNG_FREE_ROWS 0x0040 +#define PNG_FREE_PCAL 0x0080 +#define PNG_FREE_SCAL 0x0100 +#define PNG_FREE_UNKN 0x0200 +#define PNG_FREE_LIST 0x0400 +#define PNG_FREE_PLTE 0x1000 +#define PNG_FREE_TRNS 0x2000 +#define PNG_FREE_TEXT 0x4000 +#define PNG_FREE_ALL 0x7fff +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr, + png_uint_32 size)); +extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr, + png_voidp ptr)); +#endif + +extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr, + png_voidp s1, png_voidp s2, png_uint_32 size)); + +extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr, + png_voidp s1, int value, png_uint_32 size)); + +#if defined(USE_FAR_KEYWORD) /* memory model conversion function */ +extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr, + int check)); +#endif /* USE_FAR_KEYWORD */ + +/* Fatal error in PNG image of libpng - can't continue */ +extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)); + +/* The same, but the chunk name is prepended to the error string. */ +extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr, + png_const_charp error_message)); + +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +/* Non-fatal error in libpng, chunk name is prepended to message. */ +extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr, + png_const_charp warning_message)); + +/* The png_set_ functions are for storing values in the png_info_struct. + * Similarly, the png_get_ calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_ functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr, +png_infop info_ptr, png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +/* Returns row_pointers, which is an array of pointers to scanlines that was +returned from png_read_png(). */ +extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr, +png_infop info_ptr)); +/* Set row_pointers, which is an array of pointers to scanlines for use +by png_write_png(). */ +extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image height in pixels. */ +extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image bit_depth. */ +extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image color_type. */ +extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image filter_type. */ +extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image interlace_type. */ +extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image compression_type. */ +extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +#endif + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +/* Returns pointer to signature string read from PNG header */ +extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#if defined(PNG_bKGD_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p *background)); +#endif + +#if defined(PNG_bKGD_SUPPORTED) +extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p background)); +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point + *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point + *int_blue_x, png_fixed_point *int_blue_y)); +#endif +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double white_x, double white_y, double red_x, + double red_y, double green_x, double green_y, double blue_x, double blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *file_gamma)); +#endif +extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_file_gamma)); +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double file_gamma)); +#endif +extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_file_gamma)); +#endif + +#if defined(PNG_hIST_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p *hist)); +#endif + +#if defined(PNG_hIST_SUPPORTED) +extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p hist)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#if defined(PNG_oFFs_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); +#endif + +#if defined(PNG_oFFs_SUPPORTED) +extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); +#endif + +#if defined(PNG_pCAL_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, + int *type, int *nparams, png_charp *units, png_charpp *params)); +#endif + +#if defined(PNG_pCAL_SUPPORTED) +extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_charp units, png_charpp params)); +#endif + +#if defined(PNG_pHYs_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +#endif + +#if defined(PNG_pHYs_SUPPORTED) +extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp *palette, int *num_palette)); + +extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp palette, int num_palette)); + +#if defined(PNG_sBIT_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p *sig_bit)); +#endif + +#if defined(PNG_sBIT_SUPPORTED) +extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p sig_bit)); +#endif + +#if defined(PNG_sRGB_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *intent)); +#endif + +#if defined(PNG_sRGB_SUPPORTED) +extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +#endif + +#if defined(PNG_iCCP_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen)); + /* Note to maintainer: profile should be png_bytepp */ +#endif + +#if defined(PNG_iCCP_SUPPORTED) +extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#if defined(PNG_sPLT_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tpp entries)); +#endif + +#if defined(PNG_sPLT_SUPPORTED) +extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries)); +#endif + +#if defined(PNG_TEXT_SUPPORTED) +/* png_get_text also returns the number of text chunks in *num_text */ +extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +/* + * Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#if defined(PNG_TEXT_SUPPORTED) +extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); +#endif + +#if defined(PNG_tIME_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep *mod_time)); +#endif + +#if defined(PNG_tIME_SUPPORTED) +extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep mod_time)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep *trans, int *num_trans, + png_color_16p *trans_values)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep trans, int num_trans, + png_color_16p trans_values)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +#endif + +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, double *width, double *height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); +#endif +#endif +#endif /* PNG_sCAL_SUPPORTED */ + +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, double width, double height)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, png_charp swidth, png_charp sheight)); +#endif +#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +/* provide a list of chunks and how they are to be handled, if the built-in + handling or default unknown chunk handling is not desired. Any chunks not + listed will be handled in the default manner. The IHDR and IEND chunks + must not be listed. + keep = 0: follow default behavour + = 1: do not keep + = 2: keep only if safe-to-copy + = 3: keep even if unsafe-to-copy +*/ +extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp + png_ptr, int keep, png_bytep chunk_list, int num_chunks)); +extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); +extern PNG_EXPORT(void, png_set_unknown_chunk_location) + PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); +extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp + png_ptr, png_infop info_ptr, png_unknown_chunkpp entries)); +#endif +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep + chunk_name)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + If you need to turn it off for a chunk that your application has freed, + you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */ +extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, + png_infop info_ptr, int mask)); + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +/* The "params" pointer is currently not used and is for future expansion. */ +extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +#endif + +/* Define PNG_DEBUG at compile time for debugging information. Higher + * numbers for PNG_DEBUG mean more debugging information. This has + * only been added since version 0.95 so it is not implemented throughout + * libpng yet, but more support will be added as needed. + */ +#ifdef PNG_DEBUG +#if (PNG_DEBUG > 0) +#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +#include +#if (PNG_DEBUG > 1) +#define png_debug(l,m) _RPT0(_CRT_WARN,m) +#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m,p1) +#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m,p1,p2) +#endif +#else /* PNG_DEBUG_FILE || !_MSC_VER */ +#ifndef PNG_DEBUG_FILE +#define PNG_DEBUG_FILE stderr +#endif /* PNG_DEBUG_FILE */ +#if (PNG_DEBUG > 1) +#define png_debug(l,m) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ +} +#define png_debug1(l,m,p1) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ +} +#define png_debug2(l,m,p1,p2) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ +} +#endif /* (PNG_DEBUG > 1) */ +#endif /* _MSC_VER */ +#endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +#define png_debug(l, m) +#endif +#ifndef png_debug1 +#define png_debug1(l, m, p1) +#endif +#ifndef png_debug2 +#define png_debug2(l, m, p1, p2) +#endif + +extern PNG_EXPORT(png_bytep,png_sig_bytes) PNGARG((void)); + +extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp + png_ptr, png_uint_32 mng_features_permitted)); +#endif + +/* Added to version 1.2.0 */ +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */ +#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */ +#define PNG_ASM_FLAG_MMX_READ_COMBINE_ROW 0x04 +#define PNG_ASM_FLAG_MMX_READ_INTERLACE 0x08 +#define PNG_ASM_FLAG_MMX_READ_FILTER_SUB 0x10 +#define PNG_ASM_FLAG_MMX_READ_FILTER_UP 0x20 +#define PNG_ASM_FLAG_MMX_READ_FILTER_AVG 0x40 +#define PNG_ASM_FLAG_MMX_READ_FILTER_PAETH 0x80 +#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */ + +#define PNG_MMX_READ_FLAGS ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ + | PNG_ASM_FLAG_MMX_READ_INTERLACE \ + | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ + | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ + | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ + | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ) +#define PNG_MMX_WRITE_FLAGS ( 0 ) + +#define PNG_MMX_FLAGS ( PNG_ASM_FLAG_MMX_SUPPORT_COMPILED \ + | PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU \ + | PNG_MMX_READ_FLAGS \ + | PNG_MMX_WRITE_FLAGS ) + +#define PNG_SELECT_READ 1 +#define PNG_SELECT_WRITE 2 + + +#if !defined(PNG_1_0_X) +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_mmx_flagmask) + PNGARG((int flag_select, int *compilerID)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_asm_flagmask) + PNGARG((int flag_select)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_asm_flags) + PNGARG((png_structp png_ptr)); + +/* pngget.c */ +extern PNG_EXPORT(png_byte,png_get_mmx_bitdepth_threshold) + PNGARG((png_structp png_ptr)); + +/* pngget.c */ +extern PNG_EXPORT(png_uint_32,png_get_mmx_rowbytes_threshold) + PNGARG((png_structp png_ptr)); + +/* pngset.c */ +extern PNG_EXPORT(void,png_set_asm_flags) + PNGARG((png_structp png_ptr, png_uint_32 asm_flags)); + +/* pngset.c */ +extern PNG_EXPORT(void,png_set_mmx_thresholds) + PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold, + png_uint_32 mmx_rowbytes_threshold)); + +#endif /* PNG_1_0_X */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + +#if !defined(PNG_1_0_X) +/* png.c, pnggccrd.c, or pngvcrd.c */ +extern PNG_EXPORT(int,png_mmx_support) PNGARG((void)); + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp + png_ptr, png_uint_32 strip_mode)); +#endif +#endif /* PNG_1_0_X */ + +/* Maintainer: Put new public prototypes here ^, in libpng.3, and project defs */ + +#define PNG_HEADER_VERSION_STRING \ + " libpng version 1.2.5 - October 3, 2002 (header)\n" + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 - \ + (png_uint_16)(alpha)) + (png_uint_16)128); \ + (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } + +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(png_uint_32)(65535L - \ + (png_uint_32)(alpha)) + (png_uint_32)32768L); \ + (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + +#else /* standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + (png_uint_16)127) / 255) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \ + (png_uint_32)32767) / (png_uint_32)65535L) + +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ + +/* These next functions are used internally in the code. They generally + * shouldn't be used unless you are writing code to add or replace some + * functionality in libpng. More information about most functions can + * be found in the files where the functions are located. + */ + +#if defined(PNG_INTERNAL) + +/* Various modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. + */ +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_HAVE_IDAT 0x04 +#define PNG_AFTER_IDAT 0x08 +#define PNG_HAVE_IEND 0x10 +#define PNG_HAVE_gAMA 0x20 +#define PNG_HAVE_cHRM 0x40 +#define PNG_HAVE_sRGB 0x80 +#define PNG_HAVE_CHUNK_HEADER 0x100 +#define PNG_WROTE_tIME 0x200 +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 +#define PNG_BACKGROUND_IS_GRAY 0x800 +#define PNG_HAVE_PNG_SIGNATURE 0x1000 + +/* flags for the transformations the PNG library does on the image data */ +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_DITHER 0x0040 +#define PNG_BACKGROUND 0x0080 +#define PNG_BACKGROUND_EXPAND 0x0100 + /* 0x0200 unused */ +#define PNG_16_TO_8 0x0400 +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000L +#define PNG_PACKSWAP 0x10000L +#define PNG_SWAP_ALPHA 0x20000L +#define PNG_STRIP_ALPHA 0x40000L +#define PNG_INVERT_ALPHA 0x80000L +#define PNG_USER_TRANSFORM 0x100000L +#define PNG_RGB_TO_GRAY_ERR 0x200000L +#define PNG_RGB_TO_GRAY_WARN 0x400000L +#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ + +/* flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* Scaling factor for filter heuristic weighting calculations */ +#define PNG_WEIGHT_SHIFT 8 +#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) +#define PNG_COST_SHIFT 3 +#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) + +/* flags for the png_ptr->flags rather than declaring a byte for each one */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 +#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002 +#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004 +#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008 +#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010 +#define PNG_FLAG_ZLIB_FINISHED 0x0020 +#define PNG_FLAG_ROW_INIT 0x0040 +#define PNG_FLAG_FILLER_AFTER 0x0080 +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 +#define PNG_FLAG_FREE_PLTE 0x1000 +#define PNG_FLAG_FREE_TRNS 0x2000 +#define PNG_FLAG_FREE_HIST 0x4000 +#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L +#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L +#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L + +/* For use in png_set_keep_unknown, png_handle_as_unknown */ +#define HANDLE_CHUNK_AS_DEFAULT 0 +#define HANDLE_CHUNK_NEVER 1 +#define HANDLE_CHUNK_IF_SAFE 2 +#define HANDLE_CHUNK_ALWAYS 3 + +#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ + PNG_FLAG_CRC_ANCILLARY_NOWARN) + +#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ + PNG_FLAG_CRC_CRITICAL_IGNORE) + +#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ + PNG_FLAG_CRC_CRITICAL_MASK) + +/* save typing and make code easier to understand */ +#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ + abs((int)((c1).green) - (int)((c2).green)) + \ + abs((int)((c1).blue) - (int)((c2).blue))) + +/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */ +#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) +/* place to hold the signature string for a PNG file. */ +#ifdef PNG_USE_GLOBAL_ARRAYS + PNG_EXPORT_VAR (const png_byte FARDATA) png_sig[8]; +#else +#define png_sig png_sig_bytes(NULL) +#endif +#endif /* PNG_NO_EXTERN */ + +/* Constant strings for known chunk types. If you need to add a chunk, + * define the name here, and add an invocation of the macro in png.c and + * wherever it's needed. + */ +#define PNG_IHDR const png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'} +#define PNG_IDAT const png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'} +#define PNG_IEND const png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'} +#define PNG_PLTE const png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'} +#define PNG_bKGD const png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'} +#define PNG_cHRM const png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'} +#define PNG_gAMA const png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'} +#define PNG_hIST const png_byte png_hIST[5] = {104, 73, 83, 84, '\0'} +#define PNG_iCCP const png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'} +#define PNG_iTXt const png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'} +#define PNG_oFFs const png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'} +#define PNG_pCAL const png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'} +#define PNG_sCAL const png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'} +#define PNG_pHYs const png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'} +#define PNG_sBIT const png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'} +#define PNG_sPLT const png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'} +#define PNG_sRGB const png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'} +#define PNG_tEXt const png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'} +#define PNG_tIME const png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} +#define PNG_tRNS const png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} +#define PNG_zTXt const png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} + +#ifdef PNG_USE_GLOBAL_ARRAYS +PNG_EXPORT_VAR (const png_byte FARDATA) png_IHDR[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_IDAT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_IEND[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_PLTE[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_bKGD[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_cHRM[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_gAMA[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_hIST[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_iCCP[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_iTXt[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_oFFs[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_pCAL[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sCAL[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_pHYs[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sBIT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sPLT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sRGB[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tEXt[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tIME[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5]; +#endif /* PNG_USE_GLOBAL_ARRAYS */ + + +/* Inline macros to do direct reads of bytes from the input buffer. These + * require that you are using an architecture that uses PNG byte ordering + * (MSB first) and supports unaligned data storage. I think that PowerPC + * in big-endian mode and 680x0 are the only ones that will support this. + * The x86 line of processors definitely do not. The png_get_int_32() + * routine also assumes we are using two's complement format for negative + * values, which is almost certainly true. + */ +#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED) +# if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED) +# define png_get_int_32(buf) ( *((png_int_32p) (buf))) +# endif +# define png_get_uint_32(buf) ( *((png_uint_32p) (buf))) +# define png_get_uint_16(buf) ( *((png_uint_16p) (buf))) +#else +# if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED) +PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf)); +# endif +PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf)); +PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf)); +#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */ + +/* Initialize png_ptr struct for reading, and allocate any other memory. + * (old interface - DEPRECATED - use png_create_read_struct instead). + */ +extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr)); +#undef png_read_init +#define png_read_init(png_ptr) png_read_init_3(&png_ptr, \ + PNG_LIBPNG_VER_STRING, sizeof(png_struct)); +extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); + +/* Initialize png_ptr struct for writing, and allocate any other memory. + * (old interface - DEPRECATED - use png_create_write_struct instead). + */ +extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr)); +#undef png_write_init +#define png_write_init(png_ptr) png_write_init_3(&png_ptr, \ + PNG_LIBPNG_VER_STRING, sizeof(png_struct)); +extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); + +/* Allocate memory for an internal libpng struct */ +PNG_EXTERN png_voidp png_create_struct PNGARG((int type)); + +/* Free memory from internal libpng struct */ +PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); + +PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr + malloc_fn, png_voidp mem_ptr)); +PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, + png_free_ptr free_fn, png_voidp mem_ptr)); + +/* Free any memory that info_ptr points to and reset struct. */ +PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#ifndef PNG_1_0_X +/* Function to allocate memory for zlib. */ +PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size)); + +/* Function to free memory for zlib */ +PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); + +/* Next four functions are used internally as callbacks. PNGAPI is required + * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. */ + +PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)); +#endif + +PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +#if !defined(PNG_NO_STDIO) +PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)); +#endif +#endif +#else /* PNG_1_0_X */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)); +#endif +#endif /* PNG_1_0_X */ + +/* Reset the CRC variable */ +PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); + +/* Write the "data" buffer to whatever output you are using. */ +PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +/* Read data from whatever input you are using into the "data" buffer */ +PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +/* Read bytes into buf, and update png_ptr->crc */ +PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, + png_size_t length)); + +/* Decompress data in a chunk that uses compression */ +#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ + defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) +PNG_EXTERN png_charp png_decompress_chunk PNGARG((png_structp png_ptr, + int comp_type, png_charp chunkdata, png_size_t chunklength, + png_size_t prefix_length, png_size_t *data_length)); +#endif + +/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ +PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip)); + +/* Read the CRC from the file and compare it to the libpng calculated CRC */ +PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)); + +/* Calculate the CRC over a section of data. Note that we are only + * passing a maximum of 64K on systems that have this as a memory limit, + * since this is the maximum buffer size we can specify. + */ +PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, + png_size_t length)); + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); +#endif + + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). + * The only currently known PNG chunks that use signed numbers are + * the ancillary extension chunks, oFFs and pCAL. + */ +PNG_EXTERN void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i)); + +#if defined(PNG_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED) +PNG_EXTERN void png_save_int_32 PNGARG((png_bytep buf, png_int_32 i)); +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +PNG_EXTERN void png_save_uint_16 PNGARG((png_bytep buf, unsigned int i)); + +/* simple function to write the signature */ +PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr)); + +/* write various chunks */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. + */ +PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, + png_uint_32 height, + int bit_depth, int color_type, int compression_method, int filter_method, + int interlace_method)); + +PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, + png_uint_32 num_pal)); + +PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); + +#if defined(PNG_WRITE_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point + file_gamma)); +#endif +#endif + +#if defined(PNG_WRITE_sBIT_SUPPORTED) +PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, + int color_type)); +#endif + +#if defined(PNG_WRITE_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, + double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif + +#if defined(PNG_WRITE_sRGB_SUPPORTED) +PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, + int intent)); +#endif + +#if defined(PNG_WRITE_iCCP_SUPPORTED) +PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, + png_charp name, int compression_type, + png_charp profile, int proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#if defined(PNG_WRITE_sPLT_SUPPORTED) +PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, + png_sPLT_tp palette)); +#endif + +#if defined(PNG_WRITE_tRNS_SUPPORTED) +PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, + png_color_16p values, int number, int color_type)); +#endif + +#if defined(PNG_WRITE_bKGD_SUPPORTED) +PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, + png_color_16p values, int color_type)); +#endif + +#if defined(PNG_WRITE_hIST_SUPPORTED) +PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, + int num_hist)); +#endif + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, + png_charp key, png_charpp new_key)); +#endif + +#if defined(PNG_WRITE_tEXt_SUPPORTED) +PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len)); +#endif + +#if defined(PNG_WRITE_zTXt_SUPPORTED) +PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len, int compression)); +#endif + +#if defined(PNG_WRITE_iTXt_SUPPORTED) +PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, + int compression, png_charp key, png_charp lang, png_charp lang_key, + png_charp text)); +#endif + +#if defined(PNG_TEXT_SUPPORTED) /* Added at version 1.0.14 and 1.2.4 */ +PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); +#endif + +#if defined(PNG_WRITE_oFFs_SUPPORTED) +PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type)); +#endif + +#if defined(PNG_WRITE_pCAL_SUPPORTED) +PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, + png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params)); +#endif + +#if defined(PNG_WRITE_pHYs_SUPPORTED) +PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type)); +#endif + +#if defined(PNG_WRITE_tIME_SUPPORTED) +PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, + png_timep mod_time)); +#endif + +#if defined(PNG_WRITE_sCAL_SUPPORTED) +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) +PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, + int unit, double width, double height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, + int unit, png_charp width, png_charp height)); +#endif +#endif +#endif + +/* Called when finished processing a row of data */ +PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); + +/* Internal use only. Called before first row of data */ +PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); + +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr)); +#endif + +/* combine a row of data, dealing with alpha, etc. if requested */ +PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, + int mask)); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) +/* expand an interlaced row */ +/* OLD pre-1.0.9 interface: +PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations)); + */ +PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)); +#endif + +/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ + +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* grab pixels out of a row for an interlaced pass */ +PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass)); +#endif + +/* unfilter a row */ +PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, + png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter)); + +/* Choose the best filter to use and filter the row data */ +PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, + png_row_infop row_info)); + +/* Write out the filtered row. */ +PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, + png_bytep filtered_row)); +/* finish a row while reading, dealing with interlacing passes, etc. */ +PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); + +/* initialize the row buffers, etc. */ +PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); +/* optional call to update the users info structure */ +PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* these are the functions that do the transformations */ +#if defined(PNG_READ_FILLER_SUPPORTED) +PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 filler, png_uint_32 flags)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 flags)); +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) +PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop + row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) +PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) +PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p sig_bits)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info, + png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup)); + +# if defined(PNG_CORRECT_PALETTE_SUPPORTED) +PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette)); +# endif +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_WRITE_PACK_SUPPORTED) +PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 bit_depth)); +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) +PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p bit_depth)); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background, + png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift)); +#else +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background)); +#endif +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift)); +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) +PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, + png_bytep row, png_colorp palette, png_bytep trans, int num_trans)); +PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, + png_bytep row, png_color_16p trans_value)); +#endif + +/* The following decodes the appropriate chunks, and does error correction, + * then calls the appropriate callback for the chunk if it is valid. + */ + +/* decode the IHDR chunk */ +PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); + +#if defined(PNG_READ_bKGD_SUPPORTED) +PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_cHRM_SUPPORTED) +PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_gAMA_SUPPORTED) +PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_hIST_SUPPORTED) +PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_iCCP_SUPPORTED) +extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#if defined(PNG_READ_iTXt_SUPPORTED) +PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_oFFs_SUPPORTED) +PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_pCAL_SUPPORTED) +PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_pHYs_SUPPORTED) +PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sBIT_SUPPORTED) +PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sCAL_SUPPORTED) +PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sPLT_SUPPORTED) +extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#if defined(PNG_READ_sRGB_SUPPORTED) +PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tEXt_SUPPORTED) +PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tIME_SUPPORTED) +PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tRNS_SUPPORTED) +PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_zTXt_SUPPORTED) +PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); + +PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, + png_bytep chunk_name)); + +/* handle the transformations for reading and writing */ +PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr)); + +PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, + png_uint_32 length)); +PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row)); +PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr)); +#if defined(PNG_READ_tEXt_SUPPORTED) +PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) +PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) +PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +/* png.c */ /* PRIVATE */ +PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr)); +#endif +/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ + +#endif /* PNG_INTERNAL */ + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* do not put anything past this line */ +#endif /* PNG_H */ diff --git a/pngconf.h b/pngconf.h new file mode 100644 index 000000000..4a425dd1a --- /dev/null +++ b/pngconf.h @@ -0,0 +1,1348 @@ +/* pngconf.h - machine configurable file for libpng + * + * libpng 1.2.5 - October 3, 2002 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2002 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +/* Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +/* This is the size of the compression buffer, and thus the size of + * an IDAT chunk. Make this whatever size you feel is best for your + * machine. One of these will be allocated per png_struct. When this + * is full, it writes the data to the disk, and does some other + * calculations. Making this an extremely small size will slow + * the library down, but you may want to experiment to determine + * where it becomes significant, if you are concerned with memory + * usage. Note that zlib allocates at least 32Kb also. For readers, + * this describes the size of the buffer available to read the data in. + * Unless this gets smaller than the size of a row (compressed), + * it should not make much difference how big this is. + */ + +#ifndef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 8192 +#endif + +/* Enable if you want a write-only libpng */ + +#ifndef PNG_NO_READ_SUPPORTED +# define PNG_READ_SUPPORTED +#endif + +/* Enable if you want a read-only libpng */ + +#ifndef PNG_NO_WRITE_SUPPORTED +# define PNG_WRITE_SUPPORTED +#endif + +/* Enabled by default in 1.2.0. You can disable this if you don't need to + support PNGs that are embedded in MNG datastreams */ +#if !defined(PNG_1_0_X) && !defined(PNG_NO_MNG_FEATURES) +# ifndef PNG_MNG_FEATURES_SUPPORTED +# define PNG_MNG_FEATURES_SUPPORTED +# endif +#endif + +#ifndef PNG_NO_FLOATING_POINT_SUPPORTED +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FLOATING_POINT_SUPPORTED +# endif +#endif + +/* If you are running on a machine where you cannot allocate more + * than 64K of memory at once, uncomment this. While libpng will not + * normally need that much memory in a chunk (unless you load up a very + * large file), zlib needs to know how big of a chunk it can use, and + * libpng thus makes sure to check any memory allocation to verify it + * will fit into memory. +#define PNG_MAX_MALLOC_64K + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +/* Special munging to support doing things the 'cygwin' way: + * 'Normal' png-on-win32 defines/defaults: + * PNG_BUILD_DLL -- building dll + * PNG_USE_DLL -- building an application, linking to dll + * (no define) -- building static library, or building an + * application and linking to the static lib + * 'Cygwin' defines/defaults: + * PNG_BUILD_DLL -- (ignored) building the dll + * (no define) -- (ignored) building an application, linking to the dll + * PNG_STATIC -- (ignored) building the static lib, or building an + * application that links to the static lib. + * ALL_STATIC -- (ignored) building various static libs, or building an + * application that links to the static libs. + * Thus, + * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and + * this bit of #ifdefs will define the 'correct' config variables based on + * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but + * unnecessary. + * + * Also, the precedence order is: + * ALL_STATIC (since we can't #undef something outside our namespace) + * PNG_BUILD_DLL + * PNG_STATIC + * (nothing) == PNG_USE_DLL + * + * CYGWIN (2002-01-20): The preceding is now obsolete. With the advent + * of auto-import in binutils, we no longer need to worry about + * __declspec(dllexport) / __declspec(dllimport) and friends. Therefore, + * we don't need to worry about PNG_STATIC or ALL_STATIC when it comes + * to __declspec() stuff. However, we DO need to worry about + * PNG_BUILD_DLL and PNG_STATIC because those change some defaults + * such as CONSOLE_IO and whether GLOBAL_ARRAYS are allowed. + */ +#if defined(__CYGWIN__) +# if defined(ALL_STATIC) +# if defined(PNG_BUILD_DLL) +# undef PNG_BUILD_DLL +# endif +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if defined(PNG_DLL) +# undef PNG_DLL +# endif +# if !defined(PNG_STATIC) +# define PNG_STATIC +# endif +# else +# if defined (PNG_BUILD_DLL) +# if defined(PNG_STATIC) +# undef PNG_STATIC +# endif +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if !defined(PNG_DLL) +# define PNG_DLL +# endif +# else +# if defined(PNG_STATIC) +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if defined(PNG_DLL) +# undef PNG_DLL +# endif +# else +# if !defined(PNG_USE_DLL) +# define PNG_USE_DLL +# endif +# if !defined(PNG_DLL) +# define PNG_DLL +# endif +# endif +# endif +# endif +#endif + +/* This protects us against compilers that run on a windowing system + * and thus don't have or would rather us not use the stdio types: + * stdin, stdout, and stderr. The only one currently used is stderr + * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will + * prevent these from being compiled and used. #defining PNG_NO_STDIO + * will also prevent these, plus will prevent the entire set of stdio + * macros and functions (FILE *, printf, etc.) from being compiled and used, + * unless (PNG_DEBUG > 0) has been #defined. + * + * #define PNG_NO_CONSOLE_IO + * #define PNG_NO_STDIO + */ + +#if defined(_WIN32_WCE) +# include + /* Console I/O functions are not supported on WindowsCE */ +# define PNG_NO_CONSOLE_IO +# ifdef PNG_DEBUG +# undef PNG_DEBUG +# endif +#endif + +#ifdef PNG_BUILD_DLL +# ifndef PNG_CONSOLE_IO_SUPPORTED +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# endif +#endif + +# ifdef PNG_NO_STDIO +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# include +# endif +# endif +# else +# if !defined(_WIN32_WCE) +/* "stdio.h" functions are not supported on WindowsCE */ +# include +# endif +# endif + +/* This macro protects us against machines that don't have function + * prototypes (ie K&R style headers). If your compiler does not handle + * function prototypes, define this macro and use the included ansi2knr. + * I've always been able to use _NO_PROTO as the indicator, but you may + * need to drag the empty declaration out in front of here, or change the + * ifdef to suit your own needs. + */ +#ifndef PNGARG + +#ifdef OF /* zlib prototype munger */ +# define PNGARG(arglist) OF(arglist) +#else + +#ifdef _NO_PROTO +# define PNGARG(arglist) () +# ifndef PNG_TYPECAST_NULL +# define PNG_TYPECAST_NULL +# endif +#else +# define PNGARG(arglist) arglist +#endif /* _NO_PROTO */ + +#endif /* OF */ + +#endif /* PNGARG */ + +/* Try to determine if we are compiling on a Mac. Note that testing for + * just __MWERKS__ is not good enough, because the Codewarrior is now used + * on non-Mac platforms. + */ +#ifndef MACOS +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) +# define MACOS +# endif +#endif + +/* enough people need this for various reasons to include it here */ +#if !defined(MACOS) && !defined(RISCOS) && !defined(_WIN32_WCE) +# include +#endif + +#if !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED) +# define PNG_SETJMP_SUPPORTED +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This is an attempt to force a single setjmp behaviour on Linux. If + * the X config stuff didn't define _BSD_SOURCE we wouldn't need this. + */ + +# ifdef __linux__ +# ifdef _BSD_SOURCE +# define PNG_SAVE_BSD_SOURCE +# undef _BSD_SOURCE +# endif +# ifdef _SETJMP_H + __png.h__ already includes setjmp.h; + __dont__ include it again.; +# endif +# endif /* __linux__ */ + + /* include setjmp.h for error handling */ +# include + +# ifdef __linux__ +# ifdef PNG_SAVE_BSD_SOURCE +# define _BSD_SOURCE +# undef PNG_SAVE_BSD_SOURCE +# endif +# endif /* __linux__ */ +#endif /* PNG_SETJMP_SUPPORTED */ + +#ifdef BSD +# include +#else +# include +#endif + +/* Other defines for things like memory and the like can go here. */ +#ifdef PNG_INTERNAL + +#include + +/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which + * aren't usually used outside the library (as far as I know), so it is + * debatable if they should be exported at all. In the future, when it is + * possible to have run-time registry of chunk-handling functions, some of + * these will be made available again. +#define PNG_EXTERN extern + */ +#define PNG_EXTERN + +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ + +#if defined(PNG_FLOATING_POINT_SUPPORTED) +# if defined(MACOS) + /* We need to check that hasn't already been included earlier + * as it seems it doesn't agree with , yet we should really use + * if possible. + */ +# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) +# include +# endif +# else +# include +# endif +# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ +# include +# endif +#endif + +/* Codewarrior on NT has linking problems without this. */ +#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) +# define PNG_ALWAYS_EXTERN +#endif + +/* For some reason, Borland C++ defines memcmp, etc. in mem.h, not + * stdlib.h like it should (I think). Or perhaps this is a C++ + * "feature"? + */ +#ifdef __TURBOC__ +# include +# include "alloc.h" +#endif + +#if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \ + defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__)) +# include +#endif + +/* This controls how fine the dithering gets. As this allocates + * a largish chunk of memory (32K), those who are not as concerned + * with dithering quality can decrease some or all of these. + */ +#ifndef PNG_DITHER_RED_BITS +# define PNG_DITHER_RED_BITS 5 +#endif +#ifndef PNG_DITHER_GREEN_BITS +# define PNG_DITHER_GREEN_BITS 5 +#endif +#ifndef PNG_DITHER_BLUE_BITS +# define PNG_DITHER_BLUE_BITS 5 +#endif + +/* This controls how fine the gamma correction becomes when you + * are only interested in 8 bits anyway. Increasing this value + * results in more memory being used, and more pow() functions + * being called to fill in the gamma tables. Don't set this value + * less then 8, and even that may not work (I haven't tested it). + */ + +#ifndef PNG_MAX_GAMMA_8 +# define PNG_MAX_GAMMA_8 11 +#endif + +/* This controls how much a difference in gamma we can tolerate before + * we actually start doing gamma conversion. + */ +#ifndef PNG_GAMMA_THRESHOLD +# define PNG_GAMMA_THRESHOLD 0.05 +#endif + +#endif /* PNG_INTERNAL */ + +/* The following uses const char * instead of char * for error + * and warning message functions, so some compilers won't complain. + * If you do not want to use const, define PNG_NO_CONST here. + */ + +#ifndef PNG_NO_CONST +# define PNG_CONST const +#else +# define PNG_CONST +#endif + +/* The following defines give you the ability to remove code from the + * library that you will not be using. I wish I could figure out how to + * automate this, but I can't do that without making it seriously hard + * on the users. So if you are not using an ability, change the #define + * to and #undef, and that part of the library will not be compiled. If + * your linker can't find a function, you may want to make sure the + * ability is defined here. Some of these depend upon some others being + * defined. I haven't figured out all the interactions here, so you may + * have to experiment awhile to get everything to compile. If you are + * creating or using a shared library, you probably shouldn't touch this, + * as it will affect the size of the structures, and this will cause bad + * things to happen if the library and/or application ever change. + */ + +/* Any features you will not be using can be undef'ed here */ + +/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user + * to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS + * on the compile line, then pick and choose which ones to define without + * having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED + * if you only want to have a png-compliant reader/writer but don't need + * any of the extra transformations. This saves about 80 kbytes in a + * typical installation of the library. (PNG_NO_* form added in version + * 1.0.1c, for consistency) + */ + +/* The size of the png_text structure changed in libpng-1.0.6 when + * iTXt is supported. It is turned off by default, to support old apps + * that malloc the png_text structure instead of calling png_set_text() + * and letting libpng malloc it. It will be turned on by default in + * libpng-1.3.0. + */ + +#ifndef PNG_iTXt_SUPPORTED +# if !defined(PNG_READ_iTXt_SUPPORTED) && !defined(PNG_NO_READ_iTXt) +# define PNG_NO_READ_iTXt +# endif +# if !defined(PNG_WRITE_iTXt_SUPPORTED) && !defined(PNG_NO_WRITE_iTXt) +# define PNG_NO_WRITE_iTXt +# endif +#endif + +/* The following support, added after version 1.0.0, can be turned off here en + * masse by defining PNG_LEGACY_SUPPORTED in case you need binary compatibility + * with old applications that require the length of png_struct and png_info + * to remain unchanged. + */ + +#ifdef PNG_LEGACY_SUPPORTED +# define PNG_NO_FREE_ME +# define PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_NO_READ_USER_CHUNKS +# define PNG_NO_READ_iCCP +# define PNG_NO_WRITE_iCCP +# define PNG_NO_READ_iTXt +# define PNG_NO_WRITE_iTXt +# define PNG_NO_READ_sCAL +# define PNG_NO_WRITE_sCAL +# define PNG_NO_READ_sPLT +# define PNG_NO_WRITE_sPLT +# define PNG_NO_INFO_IMAGE +# define PNG_NO_READ_RGB_TO_GRAY +# define PNG_NO_READ_USER_TRANSFORM +# define PNG_NO_WRITE_USER_TRANSFORM +# define PNG_NO_USER_MEM +# define PNG_NO_READ_EMPTY_PLTE +# define PNG_NO_MNG_FEATURES +# define PNG_NO_FIXED_POINT_SUPPORTED +#endif + +/* Ignore attempt to turn off both floating and fixed point support */ +#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \ + !defined(PNG_NO_FIXED_POINT_SUPPORTED) +# define PNG_FIXED_POINT_SUPPORTED +#endif + +#ifndef PNG_NO_FREE_ME +# define PNG_FREE_ME_SUPPORTED +#endif + +#if defined(PNG_READ_SUPPORTED) + +#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_TRANSFORMS) +# define PNG_READ_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_READ_EXPAND +# define PNG_READ_EXPAND_SUPPORTED +# endif +# ifndef PNG_NO_READ_SHIFT +# define PNG_READ_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACK +# define PNG_READ_PACK_SUPPORTED +# endif +# ifndef PNG_NO_READ_BGR +# define PNG_READ_BGR_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP +# define PNG_READ_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACKSWAP +# define PNG_READ_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT +# define PNG_READ_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_READ_DITHER +# define PNG_READ_DITHER_SUPPORTED +# endif +# ifndef PNG_NO_READ_BACKGROUND +# define PNG_READ_BACKGROUND_SUPPORTED +# endif +# ifndef PNG_NO_READ_16_TO_8 +# define PNG_READ_16_TO_8_SUPPORTED +# endif +# ifndef PNG_NO_READ_FILLER +# define PNG_READ_FILLER_SUPPORTED +# endif +# ifndef PNG_NO_READ_GAMMA +# define PNG_READ_GAMMA_SUPPORTED +# endif +# ifndef PNG_NO_READ_GRAY_TO_RGB +# define PNG_READ_GRAY_TO_RGB_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP_ALPHA +# define PNG_READ_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT_ALPHA +# define PNG_READ_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_STRIP_ALPHA +# define PNG_READ_STRIP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_USER_TRANSFORM +# define PNG_READ_USER_TRANSFORM_SUPPORTED +# endif +# ifndef PNG_NO_READ_RGB_TO_GRAY +# define PNG_READ_RGB_TO_GRAY_SUPPORTED +# endif +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +#if !defined(PNG_NO_PROGRESSIVE_READ) && \ + !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */ +# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */ +#endif /* about interlacing capability! You'll */ + /* still have interlacing unless you change the following line: */ + +#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */ + +#ifndef PNG_NO_READ_COMPOSITE_NODIV +# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */ +# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */ +# endif +#endif + +/* Deprecated, will be removed from version 2.0.0. + Use PNG_MNG_FEATURES_SUPPORTED instead. */ +#ifndef PNG_NO_READ_EMPTY_PLTE +# define PNG_READ_EMPTY_PLTE_SUPPORTED +#endif + +#endif /* PNG_READ_SUPPORTED */ + +#if defined(PNG_WRITE_SUPPORTED) + +# if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_TRANSFORMS) +# define PNG_WRITE_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_WRITE_SHIFT +# define PNG_WRITE_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACK +# define PNG_WRITE_PACK_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_BGR +# define PNG_WRITE_BGR_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_SWAP +# define PNG_WRITE_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACKSWAP +# define PNG_WRITE_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT +# define PNG_WRITE_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_FILLER +# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */ +# endif +# ifndef PNG_NO_WRITE_SWAP_ALPHA +# define PNG_WRITE_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT_ALPHA +# define PNG_WRITE_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_USER_TRANSFORM +# define PNG_WRITE_USER_TRANSFORM_SUPPORTED +# endif +#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +# ifndef PNG_NO_USER_TRANSFORM_PTR +# define PNG_USER_TRANSFORM_PTR_SUPPORTED +# endif +#endif + +#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant + encoders, but can cause trouble + if left undefined */ + +#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) +# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#endif + +#ifndef PNG_1_0_X +#ifndef PNG_NO_ERROR_NUMBERS +#define PNG_ERROR_NUMBERS_SUPPORTED +#endif +#endif /* PNG_1_0_X */ + +#ifndef PNG_NO_WRITE_FLUSH +# define PNG_WRITE_FLUSH_SUPPORTED +#endif + +/* Deprecated, see PNG_MNG_FEATURES_SUPPORTED, above */ +#ifndef PNG_NO_WRITE_EMPTY_PLTE +# define PNG_WRITE_EMPTY_PLTE_SUPPORTED +#endif + +#endif /* PNG_WRITE_SUPPORTED */ + +#ifndef PNG_NO_STDIO +# define PNG_TIME_RFC1123_SUPPORTED +#endif + +/* This adds extra functions in pngget.c for accessing data from the + * info pointer (added in version 0.99) + * png_get_image_width() + * png_get_image_height() + * png_get_bit_depth() + * png_get_color_type() + * png_get_compression_type() + * png_get_filter_type() + * png_get_interlace_type() + * png_get_pixel_aspect_ratio() + * png_get_pixels_per_meter() + * png_get_x_offset_pixels() + * png_get_y_offset_pixels() + * png_get_x_offset_microns() + * png_get_y_offset_microns() + */ +#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED) +# define PNG_EASY_ACCESS_SUPPORTED +#endif + +/* PNG_ASSEMBLER_CODE was enabled by default in version 1.2.0 + even when PNG_USE_PNGVCRD or PNG_USE_PNGGCCRD is not defined */ +#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE) +# ifndef PNG_ASSEMBLER_CODE_SUPPORTED +# define PNG_ASSEMBLER_CODE_SUPPORTED +# endif +# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) +# define PNG_MMX_CODE_SUPPORTED +# endif +#endif + +/* If you are sure that you don't need thread safety and you are compiling + with PNG_USE_PNGCCRD for an MMX application, you can define this for + faster execution. See pnggccrd.c. +#define PNG_THREAD_UNSAFE_OK +*/ + +#if !defined(PNG_1_0_X) +#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED) +# define PNG_USER_MEM_SUPPORTED +#endif +#endif /* PNG_1_0_X */ + +/* These are currently experimental features, define them if you want */ + +/* very little testing */ +/* +#ifdef PNG_READ_SUPPORTED +# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# endif +#endif +*/ + +/* This is only for PowerPC big-endian and 680x0 systems */ +/* some testing */ +/* +#ifdef PNG_READ_SUPPORTED +# ifndef PNG_PNG_READ_BIG_ENDIAN_SUPPORTED +# define PNG_READ_BIG_ENDIAN_SUPPORTED +# endif +#endif +*/ + +/* Buggy compilers (e.g., gcc 2.7.2.2) need this */ +/* +#define PNG_NO_POINTER_INDEXING +*/ + +/* These functions are turned off by default, as they will be phased out. */ +/* +#define PNG_USELESS_TESTS_SUPPORTED +#define PNG_CORRECT_PALETTE_SUPPORTED +*/ + +/* Any chunks you are not interested in, you can undef here. The + * ones that allocate memory may be expecially important (hIST, + * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info + * a bit smaller. + */ + +#if defined(PNG_READ_SUPPORTED) && \ + !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_ANCILLARY_CHUNKS) +# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#if defined(PNG_WRITE_SUPPORTED) && \ + !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS) +# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_READ_TEXT +# define PNG_NO_READ_iTXt +# define PNG_NO_READ_tEXt +# define PNG_NO_READ_zTXt +#endif +#ifndef PNG_NO_READ_bKGD +# define PNG_READ_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +#endif +#ifndef PNG_NO_READ_cHRM +# define PNG_READ_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +#endif +#ifndef PNG_NO_READ_gAMA +# define PNG_READ_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +#endif +#ifndef PNG_NO_READ_hIST +# define PNG_READ_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +#endif +#ifndef PNG_NO_READ_iCCP +# define PNG_READ_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +#endif +#ifndef PNG_NO_READ_iTXt +# ifndef PNG_READ_iTXt_SUPPORTED +# define PNG_READ_iTXt_SUPPORTED +# endif +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_READ_oFFs +# define PNG_READ_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +#endif +#ifndef PNG_NO_READ_pCAL +# define PNG_READ_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_sCAL +# define PNG_READ_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_pHYs +# define PNG_READ_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +#endif +#ifndef PNG_NO_READ_sBIT +# define PNG_READ_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sPLT +# define PNG_READ_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sRGB +# define PNG_READ_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +#endif +#ifndef PNG_NO_READ_tEXt +# define PNG_READ_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_tIME +# define PNG_READ_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +#endif +#ifndef PNG_NO_READ_tRNS +# define PNG_READ_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +#endif +#ifndef PNG_NO_READ_zTXt +# define PNG_READ_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +# ifndef PNG_NO_HANDLE_AS_UNKNOWN +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +#endif +#if !defined(PNG_NO_READ_USER_CHUNKS) && \ + defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) +# define PNG_READ_USER_CHUNKS_SUPPORTED +# define PNG_USER_CHUNKS_SUPPORTED +# ifdef PNG_NO_READ_UNKNOWN_CHUNKS +# undef PNG_NO_READ_UNKNOWN_CHUNKS +# endif +# ifdef PNG_NO_HANDLE_AS_UNKNOWN +# undef PNG_NO_HANDLE_AS_UNKNOWN +# endif +#endif +#ifndef PNG_NO_READ_OPT_PLTE +# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ +#endif /* optional PLTE chunk in RGB and RGBA images */ +#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \ + defined(PNG_READ_zTXt_SUPPORTED) +# define PNG_READ_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +#endif + +#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */ + +#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_WRITE_TEXT +# define PNG_NO_WRITE_iTXt +# define PNG_NO_WRITE_tEXt +# define PNG_NO_WRITE_zTXt +#endif +#ifndef PNG_NO_WRITE_bKGD +# define PNG_WRITE_bKGD_SUPPORTED +# ifndef PNG_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_cHRM +# define PNG_WRITE_cHRM_SUPPORTED +# ifndef PNG_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_gAMA +# define PNG_WRITE_gAMA_SUPPORTED +# ifndef PNG_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_hIST +# define PNG_WRITE_hIST_SUPPORTED +# ifndef PNG_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iCCP +# define PNG_WRITE_iCCP_SUPPORTED +# ifndef PNG_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iTXt +# ifndef PNG_WRITE_iTXt_SUPPORTED +# define PNG_WRITE_iTXt_SUPPORTED +# endif +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_oFFs +# define PNG_WRITE_oFFs_SUPPORTED +# ifndef PNG_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pCAL +# define PNG_WRITE_pCAL_SUPPORTED +# ifndef PNG_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sCAL +# define PNG_WRITE_sCAL_SUPPORTED +# ifndef PNG_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pHYs +# define PNG_WRITE_pHYs_SUPPORTED +# ifndef PNG_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sBIT +# define PNG_WRITE_sBIT_SUPPORTED +# ifndef PNG_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sPLT +# define PNG_WRITE_sPLT_SUPPORTED +# ifndef PNG_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sRGB +# define PNG_WRITE_sRGB_SUPPORTED +# ifndef PNG_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tEXt +# define PNG_WRITE_tEXt_SUPPORTED +# ifndef PNG_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tIME +# define PNG_WRITE_tIME_SUPPORTED +# ifndef PNG_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tRNS +# define PNG_WRITE_tRNS_SUPPORTED +# ifndef PNG_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_zTXt +# define PNG_WRITE_zTXt_SUPPORTED +# ifndef PNG_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +# ifndef PNG_NO_HANDLE_AS_UNKNOWN +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +# endif +#endif +#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ + defined(PNG_WRITE_zTXt_SUPPORTED) +# define PNG_WRITE_TEXT_SUPPORTED +# ifndef PNG_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +# endif +#endif + +#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */ + +/* Turn this off to disable png_read_png() and + * png_write_png() and leave the row_pointers member + * out of the info structure. + */ +#ifndef PNG_NO_INFO_IMAGE +# define PNG_INFO_IMAGE_SUPPORTED +#endif + +/* need the time information for reading tIME chunks */ +#if defined(PNG_tIME_SUPPORTED) +# if !defined(_WIN32_WCE) + /* "time.h" functions are not supported on WindowsCE */ +# include +# endif +#endif + +/* Some typedefs to get us started. These should be safe on most of the + * common platforms. The typedefs should be at least as large as the + * numbers suggest (a png_uint_32 must be at least 32 bits long), but they + * don't have to be exactly that size. Some compilers dislike passing + * unsigned shorts as function parameters, so you may be better off using + * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may + * want to have unsigned int for png_uint_32 instead of unsigned long. + */ + +typedef unsigned long png_uint_32; +typedef long png_int_32; +typedef unsigned short png_uint_16; +typedef short png_int_16; +typedef unsigned char png_byte; + +/* This is usually size_t. It is typedef'ed just in case you need it to + change (I'm not sure if you will or not, so I thought I'd be safe) */ +typedef size_t png_size_t; + +/* The following is needed for medium model support. It cannot be in the + * PNG_INTERNAL section. Needs modification for other compilers besides + * MSC. Model independent support declares all arrays and pointers to be + * large using the far keyword. The zlib version used must also support + * model independent data. As of version zlib 1.0.4, the necessary changes + * have been made in zlib. The USE_FAR_KEYWORD define triggers other + * changes that are needed. (Tim Wegner) + */ + +/* Separate compiler dependencies (problem here is that zlib.h always + defines FAR. (SJT) */ +#ifdef __BORLANDC__ +# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) +# define LDATA 1 +# else +# define LDATA 0 +# endif + /* GRR: why is Cygwin in here? Cygwin is not Borland C... */ +# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__) +# define PNG_MAX_MALLOC_64K +# if (LDATA != 1) +# ifndef FAR +# define FAR __far +# endif +# define USE_FAR_KEYWORD +# endif /* LDATA != 1 */ + /* Possibly useful for moving data out of default segment. + * Uncomment it if you want. Could also define FARDATA as + * const if your compiler supports it. (SJT) +# define FARDATA FAR + */ +# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ +#endif /* __BORLANDC__ */ + + +/* Suggest testing for specific compiler first before testing for + * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, + * making reliance oncertain keywords suspect. (SJT) + */ + +/* MSC Medium model */ +#if defined(FAR) +# if defined(M_I86MM) +# define USE_FAR_KEYWORD +# define FARDATA FAR +# include +# endif +#endif + +/* SJT: default case */ +#ifndef FAR +# define FAR +#endif + +/* At this point FAR is always defined */ +#ifndef FARDATA +# define FARDATA +#endif + +/* Typedef for floating-point numbers that are converted + to fixed-point with a multiple of 100,000, e.g., int_gamma */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void FAR * png_voidp; +typedef png_byte FAR * png_bytep; +typedef png_uint_32 FAR * png_uint_32p; +typedef png_int_32 FAR * png_int_32p; +typedef png_uint_16 FAR * png_uint_16p; +typedef png_int_16 FAR * png_int_16p; +typedef PNG_CONST char FAR * png_const_charp; +typedef char FAR * png_charp; +typedef png_fixed_point FAR * png_fixed_point_p; + +#ifndef PNG_NO_STDIO +#if defined(_WIN32_WCE) +typedef HANDLE png_FILE_p; +#else +typedef FILE * png_FILE_p; +#endif +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * png_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte FAR * FAR * png_bytepp; +typedef png_uint_32 FAR * FAR * png_uint_32pp; +typedef png_int_32 FAR * FAR * png_int_32pp; +typedef png_uint_16 FAR * FAR * png_uint_16pp; +typedef png_int_16 FAR * FAR * png_int_16pp; +typedef PNG_CONST char FAR * FAR * png_const_charpp; +typedef char FAR * FAR * png_charpp; +typedef png_fixed_point FAR * FAR * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * FAR * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char FAR * FAR * FAR * png_charppp; + +/* libpng typedefs for types in zlib. If zlib changes + * or another compression library is used, then change these. + * Eliminates need to change all the source files. + */ +typedef charf * png_zcharp; +typedef charf * FAR * png_zcharpp; +typedef z_stream FAR * png_zstreamp; + +/* + * Define PNG_BUILD_DLL if the module being built is a Windows + * LIBPNG DLL. + * + * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL. + * It is equivalent to Microsoft predefined macro _DLL that is + * automatically defined when you compile using the share + * version of the CRT (C Run-Time library) + * + * The cygwin mods make this behavior a little different: + * Define PNG_BUILD_DLL if you are building a dll for use with cygwin + * Define PNG_STATIC if you are building a static library for use with cygwin, + * -or- if you are building an application that you want to link to the + * static library. + * PNG_USE_DLL is defined by default (no user action needed) unless one of + * the other flags is defined. + */ + +#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL)) +# define PNG_DLL +#endif +/* If CYGWIN, then disallow GLOBAL ARRAYS unless building a static lib. + * When building a static lib, default to no GLOBAL ARRAYS, but allow + * command-line override + */ +#if defined(__CYGWIN__) +# if !defined(PNG_STATIC) +# if defined(PNG_USE_GLOBAL_ARRAYS) +# undef PNG_USE_GLOBAL_ARRAYS +# endif +# if !defined(PNG_USE_LOCAL_ARRAYS) +# define PNG_USE_LOCAL_ARRAYS +# endif +# else +# if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNG_NO_GLOBAL_ARRAYS) +# if defined(PNG_USE_GLOBAL_ARRAYS) +# undef PNG_USE_GLOBAL_ARRAYS +# endif +# endif +# endif +# if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) +# define PNG_USE_LOCAL_ARRAYS +# endif +#endif + +/* Do not use global arrays (helps with building DLL's) + * They are no longer used in libpng itself, since version 1.0.5c, + * but might be required for some pre-1.0.5c applications. + */ +#if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) +# if defined(PNG_NO_GLOBAL_ARRAYS) || (defined(__GNUC__) && defined(PNG_DLL)) +# define PNG_USE_LOCAL_ARRAYS +# else +# define PNG_USE_GLOBAL_ARRAYS +# endif +#endif + +#if defined(__CYGWIN__) +# undef PNGAPI +# define PNGAPI __cdecl +# undef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +/* If you define PNGAPI, e.g., with compiler option "-DPNGAPI=__stdcall", + * you may get warnings regarding the linkage of png_zalloc and png_zfree. + * Don't ignore those warnings; you must also reset the default calling + * convention in your compiler to match your PNGAPI, and you must build + * zlib and your applications the same way you build libpng. + */ + +#ifndef PNGAPI + +#if defined(__MINGW32__) && !defined(PNG_MODULEDEF) +# ifndef PNG_NO_MODULEDEF +# define PNG_NO_MODULEDEF +# endif +#endif + +#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF) +# define PNG_IMPEXP +#endif + +#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \ + (( defined(_Windows) || defined(_WINDOWS) || \ + defined(WIN32) || defined(_WIN32) || defined(__WIN32__) )) + +# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) +# define PNGAPI __cdecl +# else +# define PNGAPI _cdecl +# endif + +# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \ + 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */) +# define PNG_IMPEXP +# endif + +# if !defined(PNG_IMPEXP) + +# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol +# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol + + /* Borland/Microsoft */ +# if defined(_MSC_VER) || defined(__BORLANDC__) +# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500) +# define PNG_EXPORT PNG_EXPORT_TYPE1 +# else +# define PNG_EXPORT PNG_EXPORT_TYPE2 +# if defined(PNG_BUILD_DLL) +# define PNG_IMPEXP __export +# else +# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in + VC++ */ +# endif /* Exists in Borland C++ for + C++ classes (== huge) */ +# endif +# endif + +# if !defined(PNG_IMPEXP) +# if defined(PNG_BUILD_DLL) +# define PNG_IMPEXP __declspec(dllexport) +# else +# define PNG_IMPEXP __declspec(dllimport) +# endif +# endif +# endif /* PNG_IMPEXP */ +#else /* !(DLL || non-cygwin WINDOWS) */ +# if (defined(__IBMC__) || defined(IBMCPP__)) && defined(__OS2__) +# define PNGAPI _System +# define PNG_IMPEXP +# else +# if 0 /* ... other platforms, with other meanings */ +# else +# define PNGAPI +# define PNG_IMPEXP +# endif +# endif +#endif +#endif + +#ifndef PNGAPI +# define PNGAPI +#endif +#ifndef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +#ifndef PNG_EXPORT +# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol +#endif + +#ifdef PNG_USE_GLOBAL_ARRAYS +# ifndef PNG_EXPORT_VAR +# define PNG_EXPORT_VAR(type) extern PNG_IMPEXP type +# endif +#endif + +/* User may want to use these so they are not in PNG_INTERNAL. Any library + * functions that are passed far data must be model independent. + */ + +#ifndef PNG_ABORT +# define PNG_ABORT() abort() +#endif + +#ifdef PNG_SETJMP_SUPPORTED +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED) +#endif + +#if defined(USE_FAR_KEYWORD) /* memory model independent fns */ +/* use this to make far-to-near assignments */ +# define CHECK 1 +# define NOCHECK 0 +# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) +# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) +# define png_strcpy _fstrcpy +# define png_strlen _fstrlen +# define png_memcmp _fmemcmp /* SJT: added */ +# define png_memcpy _fmemcpy +# define png_memset _fmemset +#else /* use the usual functions */ +# define CVT_PTR(ptr) (ptr) +# define CVT_PTR_NOCHECK(ptr) (ptr) +# define png_strcpy strcpy +# define png_strlen strlen +# define png_memcmp memcmp /* SJT: added */ +# define png_memcpy memcpy +# define png_memset memset +#endif +/* End of memory model independent support */ + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536 +#endif + +#ifdef PNG_READ_SUPPORTED +/* Prior to libpng-1.0.9, this block was in pngasmrd.h */ +#if defined(PNG_INTERNAL) + +/* These are the default thresholds before the MMX code kicks in; if either + * rowbytes or bitdepth is below the threshold, plain C code is used. These + * can be overridden at runtime via the png_set_mmx_thresholds() call in + * libpng 1.2.0 and later. The values below were chosen by Intel. + */ + +#ifndef PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT +# define PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT 128 /* >= */ +#endif +#ifndef PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT +# define PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT 9 /* >= */ +#endif + +/* Set this in the makefile for VC++ on Pentium, not here. */ +/* Platform must be Pentium. Makefile must assemble and load pngvcrd.c . + * MMX will be detected at run time and used if present. + */ +#ifdef PNG_USE_PNGVCRD +# define PNG_HAVE_ASSEMBLER_COMBINE_ROW +# define PNG_HAVE_ASSEMBLER_READ_INTERLACE +# define PNG_HAVE_ASSEMBLER_READ_FILTER_ROW +#endif + +/* Set this in the makefile for gcc/as on Pentium, not here. */ +/* Platform must be Pentium. Makefile must assemble and load pnggccrd.c . + * MMX will be detected at run time and used if present. + */ +#ifdef PNG_USE_PNGGCCRD +# define PNG_HAVE_ASSEMBLER_COMBINE_ROW +# define PNG_HAVE_ASSEMBLER_READ_INTERLACE +# define PNG_HAVE_ASSEMBLER_READ_FILTER_ROW +#endif +/* - see pnggccrd.c for info about what is currently enabled */ + +#endif /* PNG_INTERNAL */ +#endif /* PNG_READ_SUPPORTED */ + +#endif /* PNGCONF_H */ + diff --git a/src/BitmapUtils.cpp b/src/BitmapUtils.cpp new file mode 100644 index 000000000..3f54edb84 --- /dev/null +++ b/src/BitmapUtils.cpp @@ -0,0 +1,977 @@ +/* + * Copyright (c) 2006, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "BitmapUtils.h" +#include +#include +#include +#include +#include +#include "Interpolation.h" + +#if APL + #include + #if defined(__POWERPC__) +inline void BMP_EndianFlipLong(long * x) { long t = Endian32_Swap(*x); *x = t; } +inline void BMP_EndianFlipShort(short * x) { short t = Endian16_Swap(*x); *x = t; } +#else +#define BMP_EndianFlipLong(x) (x) +#define BMP_EndianFlipShort(x) (x) +#endif +#else + #define BMP_EndianFlipLong(x) (x) + #define BMP_EndianFlipShort(x) (x) +#endif + +#if BITMAP_USE_JPEG + +#if IBM +#define XMD_H +#define HAVE_BOOLEAN +#endif + +#include "jpeglib.h" +#include "jerror.h" + +#endif /* BITMAP_USE_JPEG */ + +/* BEN SAYS 10/11/06: this is a bit of a mess. The basic problem is that pnglib should really be distributed as a library. But + * currently we have pnglib 1.2.8 in the src dir (as source) and pnglib 1.2.5 as headers in libxplanemp and presumably as binaries + * in the "libs" dir. What we really need is a unified approach. + * + * In the long term, the real solution will be for the SDK to guarantee pnglib 1.2.12 as part of the SDK environment; this will save + * all plugin developers a lot of grief. Under this configuration, bitmaputils will simply do a #include and the makefile + * will list a copy of png.g that would be archived in the XP-SDK distro headers. + * + * Until then the best way to fix this would be to simply get fresh png 1.2.12 source and either make building it part of the + * make-files or build it and check in the binaries to some kind of dump. + * + * For now, explicitly find the older png headers. I am intentionally leaving them in the top of libxplanemp so we don't forget + * that they do not belong here! + * + */ +#include "../png.h" + +int CreateBitmapFromFile(const char * inFilePath, struct ImageInfo * outImageInfo) +{ + struct BMPHeader header; + struct BMPImageDesc imageDesc; + long pad; + int err = 0; + FILE * fi = NULL; + + outImageInfo->data = NULL; + + fi = fopen(inFilePath, "rb"); + if (fi == NULL) + goto bail; + + /* First we read in the headers, endian flip them, sanity check them, and decide how big our + image is. */ + + if (fread(&header, sizeof(header), 1, fi) != 1) + goto bail; + if (fread(&imageDesc, sizeof(imageDesc), 1, fi) != 1) + goto bail; + + BMP_EndianFlipLong(&header.fileSize); + BMP_EndianFlipLong(&header.dataOffset); + + BMP_EndianFlipLong(&imageDesc.imageWidth); + BMP_EndianFlipLong(&imageDesc.imageHeight); + BMP_EndianFlipShort(&imageDesc.bitCount); + + if ((header.signature1 != 'B') || + (header.signature2 != 'M') || + (imageDesc.bitCount != 24) || + (imageDesc.imageWidth <= 0) || + (imageDesc.imageHeight <= 0)) + goto bail; + + if ((header.fileSize - header.dataOffset) < (imageDesc.imageWidth * imageDesc.imageHeight * 3)) + goto bail; + + pad = (imageDesc.imageWidth * 3 + 3) & ~3; + pad -= imageDesc.imageWidth * 3; + + outImageInfo->width = imageDesc.imageWidth; + outImageInfo->height = imageDesc.imageHeight; + outImageInfo->pad = pad; + + /* Now we can allocate an image buffer. */ + + outImageInfo->channels = 3; + outImageInfo->data = (unsigned char *) malloc(imageDesc.imageWidth * imageDesc.imageHeight * outImageInfo->channels + imageDesc.imageHeight * pad); + if (outImageInfo->data == NULL) + goto bail; + + /* We can pretty much just read the bytes in; we know that we're 24 bit so there is no + color table, and 24 bit BMP files cannot be compressed. */ + + if (fread(outImageInfo->data, imageDesc.imageWidth * imageDesc.imageHeight * outImageInfo->channels + imageDesc.imageHeight * pad, 1, fi) != 1) + goto bail; + + fclose(fi); + return 0; + +bail: + err = errno; + if (fi != NULL) + fclose(fi); + if (outImageInfo->data != NULL) + free(outImageInfo->data); + if (err == 0) + err = -1; + return err; +} + +int WriteBitmapToFile(const struct ImageInfo * inImage, const char * inFilePath) +{ + FILE * fi = NULL; + struct BMPHeader header; + struct BMPImageDesc imageDesc; + int err = 0; + + /* First set up the appropriate header structures to match our bitmap. */ + + header.signature1 = 'B'; + header.signature2 = 'M'; + header.fileSize = sizeof(struct BMPHeader) + sizeof(struct BMPImageDesc) + ((inImage->width * 3 + inImage->pad) * inImage->height); + header.reserved = 0; + header.dataOffset = sizeof(struct BMPHeader) + sizeof(struct BMPImageDesc); + BMP_EndianFlipLong(&header.fileSize); + BMP_EndianFlipLong(&header.reserved); + BMP_EndianFlipLong(&header.dataOffset); + + imageDesc.structSize = sizeof(imageDesc); + imageDesc.imageWidth = inImage->width; + imageDesc.imageHeight = inImage->height; + imageDesc.planes = 1; + imageDesc.bitCount = 24; + imageDesc.compressionType = 0; + imageDesc.imageSize = (inImage->width * inImage->height * 3); + imageDesc.xPixelsPerM = 0; + imageDesc.yPixelsPerM = 0; + imageDesc.colorsUsed = 0; + imageDesc.colorsImportant = 0; + + BMP_EndianFlipLong(&imageDesc.structSize); + BMP_EndianFlipLong(&imageDesc.imageWidth); + BMP_EndianFlipLong(&imageDesc.imageHeight); + BMP_EndianFlipShort(&imageDesc.planes); + BMP_EndianFlipShort(&imageDesc.bitCount); + BMP_EndianFlipLong(&imageDesc.compressionType); + BMP_EndianFlipLong(&imageDesc.imageSize); + BMP_EndianFlipLong(&imageDesc.xPixelsPerM); + BMP_EndianFlipLong(&imageDesc.yPixelsPerM); + BMP_EndianFlipLong(&imageDesc.colorsUsed); + BMP_EndianFlipLong(&imageDesc.colorsImportant); + + fi = fopen(inFilePath, "wb"); + if (fi == NULL) + goto bail; + + /* We can just write out two headers and the data and be done. */ + + if (fwrite(&header, sizeof(header), 1, fi) != 1) + goto bail; + if (fwrite(&imageDesc, sizeof(imageDesc), 1, fi) != 1) + goto bail; + if (fwrite(inImage->data, (inImage->width * 3 + inImage->pad) * inImage->height, 1, fi) != 1) + goto bail; + + fclose(fi); + return 0; + +bail: + err = errno; + if (fi != NULL) + fclose(fi); + if (err == 0) + err = -1; + return err; +} + +int CreateNewBitmap(long inWidth, long inHeight, short inChannels, struct ImageInfo * outImageInfo) +{ + outImageInfo->width = inWidth; + outImageInfo->height = inHeight; + /* This nasty voodoo calculates the padding necessary to make each scanline a multiple of four bytes. */ + outImageInfo->pad = ((inWidth * inChannels + 3) & ~3) - (inWidth * inChannels); + outImageInfo->channels = inChannels; + outImageInfo->data = (unsigned char *) malloc(inHeight * ((inWidth * inChannels) + outImageInfo->pad)); + if (outImageInfo->data == NULL) + return ENOMEM; + return 0; +} + +void FillBitmap(const struct ImageInfo * inImageInfo, char c) +{ + memset(inImageInfo->data, c, inImageInfo->width * inImageInfo->height * inImageInfo->channels); +} + +void DestroyBitmap(const struct ImageInfo * inImageInfo) +{ + free(inImageInfo->data); +} + + +void CopyBitmapSection( + const struct ImageInfo * inSrc, + const struct ImageInfo * inDst, + long inSrcLeft, + long inSrcTop, + long inSrcRight, + long inSrcBottom, + long inDstLeft, + long inDstTop, + long inDstRight, + long inDstBottom) +{ + /* This routine copies a subsection of one bitmap onto a subsection of another, using bicubic interpolation + for scaling. */ + + double srcLeft = inSrcLeft, srcRight = inSrcRight, srcTop = inSrcTop, srcBottom = inSrcBottom; + double dstLeft = inDstLeft, dstRight = inDstRight, dstTop = inDstTop, dstBottom = inDstBottom; + + /* Here's why we subtract one from all of these... + (Ignore bicubic interpolation for a moment please...) + Every destination pixel is comprised of two pixels horizontally and two vertically. We use these widths and heights to do the rescaling + of the image. The goal is to have the rightmost pixel in the destination actually correspond to the rightmost pixel of the source. In + otherwords, we want to get (inDstRight - 1) from (inSrcRight - 1). Now since we use [inDstLeft - inDstRight) as our set of pixels, this + is the last pixel we ask for. But we have to subtract one from the width to get the rescaling right, otherwise we map inDstRight to + inSrcRight, which for very large upscales make inDstRight - 1 derive from inSrcRight - (something less than one) which is a pixel partially + off the right side of the bitmap, which is bad. + Bicubic interpolation is not used when we're this close to the edge of the border, so it is not a factor. + */ + + double dstWidth = dstRight - dstLeft - 1.0; + double dstHeight = dstBottom - dstTop - 1.0; + double srcWidth = srcRight - srcLeft - 1.0; + double srcHeight = srcBottom - srcTop - 1.0; + + double dx, dy; + + long srcRowBytes = inSrc->width * inSrc->channels + inSrc->pad; + long srcRowBytes2 = srcRowBytes * 2; + long dstRowBytes = inDst->width * inSrc->channels + inDst->pad; + unsigned char * srcBaseAddr = inSrc->data; + unsigned char * dstBaseAddr = inDst->data; + + int channels; + + for (dy = dstTop; dy < dstBottom; dy += 1.0) + { + for (dx = dstLeft; dx < dstRight; dx += 1.0) + { + /* For each pixel in the destination, find a pixel in the source. Note that it may have a fractional part + if we are scaling. */ + + double sx = ((dx - dstLeft) / dstWidth * srcWidth) + srcLeft; + double sy = ((dy - dstTop) / dstHeight * srcHeight) + srcTop; + + unsigned char * dstPixel = dstBaseAddr + ((long) dx * inDst->channels) + ((long) dy * dstRowBytes); + unsigned char * srcPixel = srcBaseAddr + ((long) sx * inSrc->channels) + ((long) sy * srcRowBytes); + + /* If we would need pixels from off the edge of the image for bicubic interpolation, + just use bilinear. */ + + if ((sx < 1) || + (sy < 1) || + (sx >= (inSrc->width - 2)) || + (sy >= (inSrc->height - 2))) + { + channels = inSrc->channels; + while (channels--) + { + // While this interpolation works right, when it reads the last row, its mix ratio is 100% the top/left + // BUT it reads the bot/right anyway. This causes access violations on Windows. + // (Apparently it's a "real" operating system...) + + // so we specifically check this case. + + double mixH = sx - floor(sx); + double mixV = sy - floor(sy); + + unsigned char tl = *srcPixel; + unsigned char tr = (mixH> 0.0) ? *(srcPixel+inSrc->channels) : 0; + unsigned char bl = (mixV> 0.0) ? *(srcPixel+srcRowBytes) : 0; + unsigned char br = ((mixH> 0.0) && (mixV > 0.0)) ? + *(srcPixel+srcRowBytes + inSrc->channels) : 0; + + /* Take the pixel (rounded down to integer coords), the one to the right, below, and below to the right. + The fractional part of the pixel is our weighting for interpolation. */ + unsigned char pixel = (unsigned char) BilinearInterpolate2d( + tl, tr, bl, br, mixH, mixV); + *dstPixel = pixel; + ++srcPixel; + ++dstPixel; + } + + } else { + channels = inSrc->channels; + while (channels--) + { + /* Same as above, except we now take 16 pixels surrounding the location we want. */ + *dstPixel = (unsigned char) BicubicInterpolate2d( + *(srcPixel-inSrc->channels-srcRowBytes),*(srcPixel-srcRowBytes),*(srcPixel+inSrc->channels-srcRowBytes),*(srcPixel+inSrc->channels*2-srcRowBytes), + *(srcPixel-inSrc->channels),*srcPixel,*(srcPixel+inSrc->channels),*(srcPixel+inSrc->channels*2), + *(srcPixel-inSrc->channels+srcRowBytes),*(srcPixel+srcRowBytes),*(srcPixel+inSrc->channels+srcRowBytes),*(srcPixel+inSrc->channels*2+srcRowBytes), + *(srcPixel-inSrc->channels+srcRowBytes2),*(srcPixel+srcRowBytes2),*(srcPixel+inSrc->channels+srcRowBytes2),*(srcPixel+inSrc->channels*2+srcRowBytes2), + sx - floor(sx), sy - floor(sy)); + ++srcPixel; + ++dstPixel; + } + } + + } + } +} + +inline double Interp2(double frac, double sml, double big) +{ + return sml + frac * (big - sml); +} + +void CopyBitmapSectionWarped( + const struct ImageInfo * inSrc, + const struct ImageInfo * inDst, + long inTopLeftX, + long inTopLeftY, + long inTopRightX, + long inTopRightY, + long inBotRightX, + long inBotRightY, + long inBotLeftX, + long inBotLeftY, + long inDstLeft, + long inDstTop, + long inDstRight, + long inDstBottom) +{ + /* This routine copies a subsection of one bitmap onto a subsection of another, using bicubic interpolation + for scaling. */ + + double dstLeft = inDstLeft, dstRight = inDstRight, dstTop = inDstTop, dstBottom = inDstBottom; + double topLeftX = inTopLeftX, topLeftY = inTopLeftY, topRightX = inTopRightX, topRightY = inTopRightY; + double botLeftX = inBotLeftX, botLeftY = inBotLeftY, botRightX = inBotRightX, botRightY = inBotRightY; + + /* Here's why we subtract one from all of these... + (Ignore bicubic interpolation for a moment please...) + Every destination pixel is comprised of two pixels horizontally and two vertically. We use these widths and heights to do the rescaling + of the image. The goal is to have the rightmost pixel in the destination actually correspond to the rightmost pixel of the source. In + otherwords, we want to get (inDstRight - 1) from (inSrcRight - 1). Now since we use [inDstLeft - inDstRight) as our set of pixels, this + is the last pixel we ask for. But we have to subtract one from the width to get the rescaling right, otherwise we map inDstRight to + inSrcRight, which for very large upscales make inDstRight - 1 derive from inSrcRight - (something less than one) which is a pixel partially + off the right side of the bitmap, which is bad. + Bicubic interpolation is not used when we're this close to the edge of the border, so it is not a factor. + */ + + double dstWidth = dstRight - dstLeft - 1.0; + double dstHeight = dstBottom - dstTop - 1.0; + + double dx, dy; + + long srcRowBytes = inSrc->width * inSrc->channels + inSrc->pad; + long srcRowBytes2 = srcRowBytes * 2; + long dstRowBytes = inDst->width * inSrc->channels + inDst->pad; + unsigned char * srcBaseAddr = inSrc->data; + unsigned char * dstBaseAddr = inDst->data; + + int channels; + + for (dy = dstTop; dy < dstBottom; dy += 1.0) + { + for (dx = dstLeft; dx < dstRight; dx += 1.0) + { + /* For each pixel in the destination, find a pixel in the source. Note that it may have a fractional part + if we are scaling. */ + + double frac_x = ((dx - dstLeft) / dstWidth); + double frac_y = ((dy - dstTop) / dstHeight); + + double sx = Interp2(frac_y, Interp2(frac_x, topLeftX, topRightX), Interp2(frac_x, botLeftX, botRightX)); + double sy = Interp2(frac_x, Interp2(frac_y, topLeftY, botLeftY), Interp2(frac_y, topRightY, botRightY)); + + unsigned char * dstPixel = dstBaseAddr + ((long) dx * inDst->channels) + ((long) dy * dstRowBytes); + unsigned char * srcPixel = srcBaseAddr + ((long) sx * inSrc->channels) + ((long) sy * srcRowBytes); + + /* If we would need pixels from off the edge of the image for bicubic interpolation, + just use bilinear. */ + + if ((sx < 1) || + (sy < 1) || + (sx >= (inSrc->width - 2)) || + (sy >= (inSrc->height - 2))) + { + channels = inSrc->channels; + while (channels--) + { + // While this interpolation works right, when it reads the last row, its mix ratio is 100% the top/left + // BUT it reads the bot/right anyway. This causes access violations on Windows. + // (Apparently it's a "real" operating system...) + + // so we specifically check this case. + + double mixH = sx - floor(sx); + double mixV = sy - floor(sy); + + unsigned char tl = *srcPixel; + unsigned char tr = (mixH> 0.0) ? *(srcPixel+inSrc->channels) : 0; + unsigned char bl = (mixV> 0.0) ? *(srcPixel+srcRowBytes) : 0; + unsigned char br = ((mixH> 0.0) && (mixV > 0.0)) ? + *(srcPixel+srcRowBytes + inSrc->channels) : 0; + + /* Take the pixel (rounded down to integer coords), the one to the right, below, and below to the right. + The fractional part of the pixel is our weighting for interpolation. */ + unsigned char pixel = (unsigned char) BilinearInterpolate2d( + tl, tr, bl, br, mixH, mixV); + *dstPixel = pixel; + ++srcPixel; + ++dstPixel; + } + + } else { + channels = inSrc->channels; + while (channels--) + { + /* Same as above, except we now take 16 pixels surrounding the location we want. */ + *dstPixel = (unsigned char) BicubicInterpolate2d( + *(srcPixel-inSrc->channels-srcRowBytes),*(srcPixel-srcRowBytes),*(srcPixel+inSrc->channels-srcRowBytes),*(srcPixel+inSrc->channels*2-srcRowBytes), + *(srcPixel-inSrc->channels),*srcPixel,*(srcPixel+inSrc->channels),*(srcPixel+inSrc->channels*2), + *(srcPixel-inSrc->channels+srcRowBytes),*(srcPixel+srcRowBytes),*(srcPixel+inSrc->channels+srcRowBytes),*(srcPixel+inSrc->channels*2+srcRowBytes), + *(srcPixel-inSrc->channels+srcRowBytes2),*(srcPixel+srcRowBytes2),*(srcPixel+inSrc->channels+srcRowBytes2),*(srcPixel+inSrc->channels*2+srcRowBytes2), + sx - floor(sx), sy - floor(sy)); + ++srcPixel; + ++dstPixel; + } + } + + } + } +} + +void RotateBitmapCCW( + struct ImageInfo * ioBitmap) +{ + /* We have to allocate a new bitmap to transfer our old data to. The new bitmap might not have the same + * storage size as the old bitmap because of padding! */ + + long newWidth = ioBitmap->height; + long newHeight = ioBitmap->width; + long newPad = ((newWidth * ioBitmap->channels + 3) & ~3) - (newWidth * ioBitmap->channels); + unsigned char * newData = (unsigned char *) malloc(((newWidth * ioBitmap->channels) + newPad) * newHeight); + if (newData == NULL) + return; + + for (long y = 0; y < ioBitmap->height; ++y) + for (long x = 0; x < ioBitmap->width; ++x) + { + long nx = ioBitmap->height - y - 1; + long ny = x; + + unsigned char * srcP = ioBitmap->data + (x * ioBitmap->channels) + (y * (ioBitmap->channels * ioBitmap->width + ioBitmap->pad)); + unsigned char * dstP = newData + (nx * ioBitmap->channels) + (ny * (ioBitmap->channels * newWidth + newPad)); + long chCount = ioBitmap->channels; + while (chCount--) + { + *dstP++ = *srcP++; + } + } + + free(ioBitmap->data); + ioBitmap->data = newData; + ioBitmap->width = newWidth; + ioBitmap->height = newHeight; + ioBitmap->pad = newPad; + +} + +int ConvertBitmapToAlpha( + struct ImageInfo * ioImage) +{ + unsigned char * oldData, * newData, * srcPixel, * dstPixel; + long count; + long x,y; + + if (ioImage->channels == 4) + return 0; + + /* We have to allocate a new bitmap that is larger than the old to store the alpha channel. */ + + newData = (unsigned char *) malloc(ioImage->width * ioImage->height * 4); + if (newData == NULL) + return ENOMEM; + oldData = ioImage->data; + + srcPixel = oldData; + dstPixel = newData; + count = ioImage->width * ioImage->height; + for (y = 0; y < ioImage->height; ++y) + for (x = 0; x < ioImage->width; ++x) + { + /* For each pixel, if it is pure magenta, it becomes pure black transparent. Otherwise it is + * opaque and retains its color. NOTE: one of the problems with the magenta=alpha strategy is + * that we don't know what color was 'under' the transparency, so if we stretch or skew this bitmap + * we can't really do a good job of interpolating. */ + if ((srcPixel[0] == 0xFF) && + (srcPixel[1] == 0x00) && + (srcPixel[2] == 0xFF)) + { + dstPixel[0] = 0; + dstPixel[1] = 0; + dstPixel[2] = 0; + dstPixel[3] = 0; + } else { + dstPixel[0] = srcPixel[0]; + dstPixel[1] = srcPixel[1]; + dstPixel[2] = srcPixel[2]; + dstPixel[3] = 0xFF; + } + + srcPixel += 3; + dstPixel += 4; + + if (x == (ioImage->width - 1)) + srcPixel += ioImage->pad; + } + + ioImage->data = newData; + ioImage->pad = 0; + free(oldData); + ioImage->channels = 4; + return 0; +} + + +int ConvertAlphaToBitmap( + struct ImageInfo * ioImage) +{ + unsigned char * oldData, * newData, * srcPixel, * dstPixel; + long count; + long x,y; + + if (ioImage->channels == 3) + return 0; + + /* Allocate a new bitmap at 3 channels. + * WARNING WARNING WARNING WARNING WARNING: + * THIS CODE IS BUGGY!!!!!!!!!!!!!!!!!!!!! + * + * There is no padding being allocated to our new buffer, but we do calculate + * a pad below. If we are working with a non-multiple-of-four width image, + * we will scribble over memory and cause chaos. + */ + newData = (unsigned char *) malloc(ioImage->width * ioImage->height * 3); + if (newData == NULL) + return ENOMEM; + oldData = ioImage->data; + + ioImage->pad = ((ioImage->width * 3 + 3) & ~3) - (ioImage->width * 3); + + srcPixel = oldData; + dstPixel = newData; + count = ioImage->width * ioImage->height; + + for (y = 0; y < ioImage->height; ++y) + for (x = 0; x < ioImage->width; ++x) + { + /* For each pixel, only full opaque is taken. Here's why: if the pixel is part alpha, then it is a blend of an + * alpha pixel and a non-alpha pixel. But...we don't have good color data for the alpha pixel; from the above + * routine we set the color to black. So the color data for this pixel is mixed with black. When viewed the + * edges of a stretched bitmap will appear to turn dark before they fade out. + * + * But this point is moot anyway; we really only have one bit of alpha, on or off. So we could pick any cutoff + * value and we'll still get a really sharp jagged line at the edge of the transparency. + * + * You might ask yourself, why does X-Plane do it this way? The answer is that as of this writing, most graphics + * cards do not have the alpha-blending fill rate to blend the entire aircraft panel; this would be a huge hit on + * frame rate. So Austin is using the alpha test mechanism for transparency, which is much faster but only one + * bit deep. + * + */ + if (srcPixel[3] != 0xFF) + { + dstPixel[0] = 0xFF; + dstPixel[1] = 0x00; + dstPixel[2] = 0xFF; + } else { + dstPixel[0] = srcPixel[0]; + dstPixel[1] = srcPixel[1]; + dstPixel[2] = srcPixel[2]; + } + + srcPixel += 4; + dstPixel += 3; + + if (x == (ioImage->width - 1)) + dstPixel += ioImage->pad; + } + + ioImage->data = newData; + free(oldData); + ioImage->channels = 3; + return 0; +} + +#pragma mark - + +#if BITMAP_USE_JPEG + +/* + * JPEG in-memory source manager + * + * Given a JFIF file that is entirley in memory, this object uses that buffer to provide data + * to the JPEG lib. + * + */ + +typedef struct { + struct jpeg_source_mgr pub; // Fields inherited from all jpeg source mgs. + + JOCTET * buffer; // Buffer start and size + int len; // +} mem_source_mgr; +typedef struct mem_source_mgr * mem_src_ptr; + +METHODDEF(void) mem_init_source (j_decompress_ptr cinfo) +{ +} + +METHODDEF(boolean) mem_fill_input_buffer (j_decompress_ptr cinfo) +{ + // If we are asked to fill the buffer, we can't; we give JPEG + // all of the memory up front. So throw a fatal err. + ERREXIT(cinfo, JERR_INPUT_EMPTY); + return TRUE; +} + +METHODDEF(void) mem_skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + mem_src_ptr src = (mem_src_ptr) cinfo->src; + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; +} + +METHODDEF(void) mem_term_source (j_decompress_ptr cinfo) +{ +} + +/* + * JPEG exception-based error handler. This throws an exception + * rather than calling exit() on the process. + * + */ +METHODDEF(void) throw_error_exit (j_common_ptr cinfo) +{ + // On a fatal error, we deallocate the struct first, + // then throw. This is a good idea because the cinfo + // struct may go out of scope during the throw; this + // relieves client code from having to worry about + // order of destruction. + jpeg_destroy(cinfo); + throw EXIT_FAILURE; +} + +METHODDEF(void) +eat_output_message (j_common_ptr cinfo) +{ + // If the user needed to see something, this is where + // we'd find out. We currently don't have a good way + // of showing the users messages. + char buffer[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message) (cinfo, buffer); +} + +GLOBAL(struct jpeg_error_mgr *) +jpeg_throw_error (struct jpeg_error_mgr * err) +{ + // This routine sets up our various error handlers. + // We use their decision making logic, and change + // two of our own handlers. + jpeg_std_error(err); + err->error_exit = throw_error_exit; + err->output_message = eat_output_message; + + return err; +} + + + + + + +int CreateBitmapFromJPEG(const char * inFilePath, struct ImageInfo * outImageInfo) +{ + // We bail immediately if the file is no good. This prevents us from + // having to keep track of file openings; if we have a problem, but the file must be + // closed. + outImageInfo->data = NULL; + FILE * fi = fopen(inFilePath, "rb"); + if (!fi) return errno; + + try { + + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + + cinfo.err = jpeg_throw_error(&jerr); + jpeg_create_decompress(&cinfo); + + jpeg_stdio_src(&cinfo, fi); + + jpeg_read_header(&cinfo, TRUE); + + jpeg_start_decompress(&cinfo); + + outImageInfo->width = cinfo.output_width; + outImageInfo->height = cinfo.output_height; + outImageInfo->pad = 0; + outImageInfo->channels = 3; + outImageInfo->data = (unsigned char *) malloc(outImageInfo->width * outImageInfo->height * outImageInfo->channels); + + int linesize = outImageInfo->width * outImageInfo->channels; + int linecount = outImageInfo->height; + unsigned char * p = outImageInfo->data + (linecount - 1) * linesize; + while (linecount--) + { + if (jpeg_read_scanlines (&cinfo, &p, 1) == 0) + break; + + if (cinfo.output_components == 1) + for (int n = cinfo.output_width - 1; n >= 0; --n) + { + p[n*3+2] = p[n*3+1] = p[n*3] = p[n]; + } + p -= linesize; + } + + jpeg_finish_decompress(&cinfo); + + jpeg_destroy_decompress(&cinfo); + fclose(fi); + return 0; + } catch (...) { + // If we ever get an exception, it's because we got a fatal JPEG error. Our + // error handler deallocates the jpeg struct, so all we have to do is close the + // file and bail. + fclose(fi); + return 1; + } +} + + + +int CreateBitmapFromJPEGData(void * inBytes, int inLength, struct ImageInfo * outImageInfo) +{ + try { + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + + cinfo.err = jpeg_throw_error(&jerr); + jpeg_create_decompress(&cinfo); + + mem_source_mgr src; + + cinfo.src = (struct jpeg_source_mgr *) &src; + + src.pub.init_source = mem_init_source; + src.pub.fill_input_buffer = mem_fill_input_buffer; + src.pub.skip_input_data = mem_skip_input_data; + src.pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src.pub.term_source = mem_term_source; + src.buffer = (JOCTET *) inBytes; + src.len = inLength; + src.pub.bytes_in_buffer = inLength; /* forces fill_input_buffer on first read */ + src.pub.next_input_byte = (JOCTET *) inBytes; /* until buffer loaded */ + + jpeg_read_header(&cinfo, TRUE); + + jpeg_start_decompress(&cinfo); + + outImageInfo->width = cinfo.output_width; + outImageInfo->height = cinfo.output_height; + outImageInfo->pad = 0; + outImageInfo->channels = 3; + outImageInfo->data = (unsigned char *) malloc(outImageInfo->width * outImageInfo->height * outImageInfo->channels); + + int linesize = outImageInfo->width * outImageInfo->channels; + int linecount = outImageInfo->height; + unsigned char * p = outImageInfo->data + (linecount - 1) * linesize; + while (linecount--) + { + if (jpeg_read_scanlines (&cinfo, &p, 1) == 0) + break; + + if (cinfo.output_components == 1) + for (int n = cinfo.output_width - 1; n >= 0; --n) + { + p[n*3+2] = p[n*3+1] = p[n*3] = p[n]; + } + p -= linesize; + } + + jpeg_finish_decompress(&cinfo); + + jpeg_destroy_decompress(&cinfo); + return 0; + } catch (...) { + // If we get an exceptoin, cinfo is already cleaned up; just bail. + return 1; + } +} + +#endif /* BITMAP_USE_JPEG */ + +void my_error (png_structp,png_const_charp err){} +void my_warning(png_structp,png_const_charp err){} + +unsigned char * png_start_pos = NULL; +unsigned char * png_end_pos = NULL; +unsigned char * png_current_pos = NULL; + +void png_buffered_read_func(png_structp png_ptr, png_bytep data, png_size_t length) +{ + if((png_current_pos+length)>png_end_pos) + png_error(png_ptr,"PNG Read Error, overran end of buffer!"); + memcpy(data,png_current_pos,length); + png_current_pos+=length; +} + + +int CreateBitmapFromPNG(const char * inFilePath, struct ImageInfo * outImageInfo) +{ + png_uint_32 width, height; + int bit_depth,color_type,interlace_type,compression_type,P_filter_type; + + png_structp pngPtr = NULL; + png_infop infoPtr = NULL; + unsigned char * buffer = NULL; + FILE * file = NULL; + int fileLength = 0; + outImageInfo->data = NULL; + char** rows = NULL; + double lcl_gamma; // This will be the gamma of the file if it has one. +#if APL // Macs and PCs have different gamma responses. + double screen_gamma=1.8; // Darks look darker and brights brighter on the PC. +#endif // Macs are more even. +#if IBM||LIN + double screen_gamma=2.2; +#endif + + pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING,(png_voidp)NULL,my_error,my_warning); + if(!pngPtr) goto bail; + + infoPtr=png_create_info_struct(pngPtr); + if(!infoPtr) goto bail; + + file = fopen(inFilePath, "rb"); + if (!file) goto bail; + fseek(file, 0, SEEK_END); + fileLength = ftell(file); + fseek(file, 0, SEEK_SET); + buffer = new unsigned char[fileLength]; + if (!buffer) goto bail; + if (fread(buffer, 1, fileLength, file) != fileLength) goto bail; + fclose(file); + file = NULL; + + png_start_pos = buffer; + png_current_pos = buffer; + png_end_pos = buffer + fileLength; + + if (png_sig_cmp(png_current_pos,0,8)) goto bail; + + png_set_interlace_handling(pngPtr); + if(setjmp(pngPtr->jmpbuf)) + { + goto bail; + } + + png_init_io (pngPtr,NULL ); + png_set_read_fn (pngPtr,NULL,png_buffered_read_func); + png_set_sig_bytes(pngPtr,8 ); png_current_pos+=8; + png_read_info (pngPtr,infoPtr ); + + png_get_IHDR(pngPtr,infoPtr,&width,&height, + &bit_depth,&color_type,&interlace_type, + &compression_type,&P_filter_type); + + outImageInfo->width = width; + outImageInfo->height = height; + + if( png_get_gAMA (pngPtr,infoPtr ,&lcl_gamma)) // Perhaps the file has its gamma recorded, for example by photoshop. Just tell png to callibrate for our hw platform. + png_set_gamma(pngPtr,screen_gamma, lcl_gamma); + else png_set_gamma(pngPtr,screen_gamma, 1.0/1.8 ); // If the file doesn't have gamma, assume it was drawn on a Mac. + + if(color_type==PNG_COLOR_TYPE_PALETTE && bit_depth<= 8)png_set_expand (pngPtr); + if(color_type==PNG_COLOR_TYPE_GRAY && bit_depth< 8)png_set_expand (pngPtr); + if(png_get_valid(pngPtr,infoPtr,PNG_INFO_tRNS) )png_set_expand (pngPtr); + if( bit_depth==16)png_set_strip_16 (pngPtr); + if( bit_depth< 8)png_set_packing (pngPtr); + if( color_type==PNG_COLOR_TYPE_GRAY )png_set_gray_to_rgb (pngPtr); + if( color_type==PNG_COLOR_TYPE_GRAY_ALPHA )png_set_gray_to_rgb (pngPtr); + switch(color_type) { + case PNG_COLOR_TYPE_GRAY: outImageInfo->channels = 3; break; + case PNG_COLOR_TYPE_GRAY_ALPHA: outImageInfo->channels = 4; break; + case PNG_COLOR_TYPE_RGB: outImageInfo->channels = 3; break; + case PNG_COLOR_TYPE_RGBA: outImageInfo->channels = 4; break; + default: goto bail; + } + png_set_bgr(pngPtr); + png_read_update_info(pngPtr,infoPtr); + + outImageInfo->pad = 0; + outImageInfo->data = (unsigned char *) malloc(outImageInfo->width * outImageInfo->height * outImageInfo->channels); + if (!outImageInfo->data) goto bail; + + rows=(char**)malloc(height*sizeof(char*)); + if (!rows) goto bail; + + for(int i=0;idata +((outImageInfo->height-1-i)*(outImageInfo->width)*(outImageInfo->channels)); + } + + png_read_image(pngPtr,(png_byte**)rows); // Now we just tell pnglib to read in the data. When done our row ptrs will be filled in. + free(rows); + rows = NULL; + + delete [] buffer; + buffer = NULL; + + png_destroy_read_struct(&pngPtr,(png_infopp)&infoPtr,(png_infopp)NULL); + + return 0; +bail: + + if (pngPtr && infoPtr) png_destroy_read_struct(&pngPtr,(png_infopp)&infoPtr,(png_infopp)NULL); + else if (pngPtr) png_destroy_read_struct(&pngPtr,(png_infopp)NULL,(png_infopp)NULL); + if (buffer) delete [] buffer; + if (file) fclose(file); + if (outImageInfo->data) free(outImageInfo->data); + if (rows) free(rows); + + return -1; + +} + diff --git a/src/BitmapUtils.h b/src/BitmapUtils.h new file mode 100644 index 000000000..dece79c2b --- /dev/null +++ b/src/BitmapUtils.h @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2006, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef _BitmapUtils_h_ +#define _BitmapUtils_h_ + +/* + WARNING: Struct alignment must be "68K" (e.g. 2-byte alignment) for these + structures to be happy!!! +*/ + +/* + These headers match the Microsoft bitmap file and image headers more or less + and are read right out of the file. +*/ + +#if APL +#pragma options align=mac68k +#endif +#if IBM +#pragma pack(push, 2) +#endif + +struct BMPHeader { + char signature1; + char signature2; + long fileSize; + long reserved; + long dataOffset; +}; + +struct BMPImageDesc { + long structSize; + long imageWidth; + long imageHeight; + short planes; + short bitCount; + long compressionType; + long imageSize; + long xPixelsPerM; //130B0000? B013 = 45075? + long yPixelsPerM; + long colorsUsed; + long colorsImportant; +}; + +#if APL +#pragma options align=reset +#endif +#if IBM +#pragma pack(pop) +#endif + + +/* + This is our in memory way of storing an image. Data is a pointer + to an array of bytes large enough to hold the image. We always + use 24-bit RGB or 32-bit ARGB. The lower left corner of the BMP + file is in the first byte of data. + + Pad is how many bytes we skip at the end of each scanline. Each + scanline must start on a 4-byte boundary! +*/ + +struct ImageInfo { + unsigned char * data; + long width; + long height; + long pad; + short channels; +}; + +/* Given a file path and an uninitialized imageInfo structure, this routine fills + * in the imageInfo structure by loading the bitmap. */ +int CreateBitmapFromFile(const char * inFilePath, struct ImageInfo * outImageInfo); + +#if BITMAP_USE_JPEG +/* Same as above, but uses IJG JPEG code. */ +int CreateBitmapFromJPEG(const char * inFilePath, struct ImageInfo * outImageInfo); + +/* Same as above, but create the image from an in-memory image of a JFIF file, + * allows you to read the image yourself, or mem map it. */ +int CreateBitmapFromJPEGData(void * inBytes, int inLength, struct ImageInfo * outImageInfo); +#endif + +/* Yada yada yada, libPng. */ +int CreateBitmapFromPNG(const char * inFilePath, struct ImageInfo * outImageInfo); + +/* Given an imageInfo structure, this routine writes it to disk as a .bmp file. + * Note that only 3-channel bitmaps may be written as .bmp files!! */ +int WriteBitmapToFile(const struct ImageInfo * inImage, const char * inFilePath); + +/* This routine creates a new bitmap and fills in an uninitialized imageInfo structure. + * The contents of the bitmap are undetermined and must be 'cleared' by you. */ +int CreateNewBitmap(long inWidth, long inHeight, short inChannels, struct ImageInfo * outImageInfo); + +/* Given a bitmap, this routine fills the whole bitmap in with a gray level of c, where + * c = 0 means black and c = 255 means white. */ +void FillBitmap(const struct ImageInfo * inImageInfo, char c); + +/* This routine deallocates a bitmap that was created with CreateBitmapFromFile or + * CreateNewBitmap. */ +void DestroyBitmap(const struct ImageInfo * inImageInfo); + +/* Given two bitmaps, this routine copies a section from one bitmap to another. + * This routine will use bicubic and bilinear interpolation to copy the bitmap + * as cleanly as possible. However, if the bitmap contains alpha, the copy routine + * will create a jagged edge to keep from smearing the alpha channel. */ +void CopyBitmapSection( + const struct ImageInfo * inSrc, + const struct ImageInfo * inDst, + long inSrcLeft, + long inSrcTop, + long inSrcRight, + long inSrcBottom, + long inDstLeft, + long inDstTop, + long inDstRight, + long inDstBottom); + +void CopyBitmapSectionWarped( + const struct ImageInfo * inSrc, + const struct ImageInfo * inDst, + long inTopLeftX, + long inTopLeftY, + long inTopRightX, + long inTopRightY, + long inBotRightX, + long inBotRightY, + long inBotLeftX, + long inBotLeftY, + long inDstLeft, + long inDstTop, + long inDstRight, + long inDstBottom); + +/* This routine rotates a bitmap counterclockwise 90 degrees, exchanging its width + * and height. */ +void RotateBitmapCCW( + struct ImageInfo * ioBitmap); + +/* This routine converts a 3-channel bitmap to a 4-channel bitmap by converting + * magenta pixels to alpha. */ +int ConvertBitmapToAlpha( + struct ImageInfo * ioImage); + +/* This routine converts a 4-channel bitmap to a 3-channel bitmap by converting + * alpha back to magenta. */ +int ConvertAlphaToBitmap( + struct ImageInfo * ioImage); +#endif diff --git a/src/CSLLoaderThread.cpp b/src/CSLLoaderThread.cpp new file mode 100644 index 000000000..32832f268 --- /dev/null +++ b/src/CSLLoaderThread.cpp @@ -0,0 +1,101 @@ +#include "CSLLoaderThread.h" +#include "ptypes.h" +#include "pasync.h" + +#include "XPLMMultiplayerCSL.h" +#include "XPLMMultiplayerObj.h" + +USING_PTYPES + +const int maxthreads = 1; + + + +class loadjob: public message +{ +public: + CSLPlane_t* toload; + loadjob(const int msg, CSLPlane_t* itoload) + : message(msg) { toload = itoload; } + ~loadjob() { delete toload; } +}; + + +void loadjobthread::execute() +{ + bool quit = false; + while (!quit) + { + // get the next message from the queue + message* msg = jq->getmessage(); + + try + { + switch (msg->id) + { + case MSG_LOADJOB_OBJ: + { + CSLPlane_t* toload = ((loadjob*)msg)->toload; + toload->obj_idx = OBJ_LoadModel(toload->file_path.c_str()); + } + break; + + case MSG_LOADJOB_TEX: + { + CSLPlane_t* toload = ((loadjob*)msg)->toload; + toload->texID = OBJ_LoadTexture(toload->tex_path.c_str(), false); + } + break; + + case MSG_LOADJOB_TEX_LIT: + { + CSLPlane_t* toload = ((loadjob*)msg)->toload; + toload->texLitID = OBJ_LoadTexture(toload->texLit_path.c_str(), false); + } + break; + + case MSG_QUIT: + // MSG_QUIT is not used in our example + quit = true; + break; + } + } + catch(...) + { + // the message object must be freed! + delete msg; + throw; + } + delete msg; + } +} + + + +void CSLLoaderType::startthreads() +{ + // create the thread pool + static tobjlist threads(true); + int i; + for(i = 0; i < maxthreads; i++) + { + static loadjobthread* j = new loadjobthread(i + 1, jq); + j->start(); + threads.add(j); + } +} + +void CSLLoaderType::load(CSLPlane_t* toload) +{ + jq->post(new loadjob(MSG_LOADJOB_OBJ, toload)); +} + +void CSLLoaderType::loadTex(CSLPlane_t* toload) +{ + jq->post(new loadjob(MSG_LOADJOB_TEX, toload)); +} + +void CSLLoaderType::loadTexLIT(CSLPlane_t* toload) +{ + jq->post(new loadjob(MSG_LOADJOB_TEX_LIT, toload)); +} diff --git a/src/CSLLoaderThread.h b/src/CSLLoaderThread.h new file mode 100644 index 000000000..82762ceb6 --- /dev/null +++ b/src/CSLLoaderThread.h @@ -0,0 +1,41 @@ +#include "ptypes.h" +#include "pasync.h" + +#include "XPLMMultiplayerCSL.h" + +const int MSG_LOADJOB_OBJ = 1; +const int MSG_LOADJOB_TEX = 2; +const int MSG_LOADJOB_TEX_LIT = 3; + +const int NOT_LOADED_TEX_LIT=-6; +const int NOT_LOADED_TEX=-5; +const int LOADING_TEX=-4; +const int NOT_LOADED_OBJ=-3; +const int LOADING_OBJ=-2; + +class loadjobthread: public pt::thread +{ +protected: + int id; + pt::jobqueue* jq; + virtual void execute(); +public: + loadjobthread(int iid, pt::jobqueue* ijq) + : thread(true), id(iid), jq(ijq) {} + ~loadjobthread() { } +}; + + + +class CSLLoaderType +{ +protected: + pt::jobqueue *jq; +public: + CSLLoaderType() { jq=new pt::jobqueue(); } + ~CSLLoaderType() {} + void startthreads(); + void load(CSLPlane_t* toload); + void loadTex(CSLPlane_t* toload); + void loadTexLIT(CSLPlane_t* toload); +}; diff --git a/src/Interpolation.h b/src/Interpolation.h new file mode 100644 index 000000000..d6e286ad8 --- /dev/null +++ b/src/Interpolation.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef _Interpolation_h_ +#define _Interpolation_h_ + +/* Interpolation Utilities. These are defined inline in the hope of speed. */ + +double clamp(double v, double min, double max); + +double BilinearInterpolate1d( + double v0, + double v1, + double position); + +double BilinearInterpolate2d( + double v0, double v1, + double v2, double v3, + double hPosition, + double vPosition); + +double BicubicInterpolate1d( + double v0, + double v1, + double v2, + double v3, + double position); + +double BicubicInterpolate2d( + double v0, double v1, double v2, double v3, + double v4, double v5, double v6, double v7, + double v8, double v9, double v10, double v11, + double v12, double v13, double v14, double v15, + double hPosition, + double vPosition); + +#include "Interpolation.i" + +#endif diff --git a/src/Interpolation.i b/src/Interpolation.i new file mode 100644 index 000000000..1e24512ea --- /dev/null +++ b/src/Interpolation.i @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2006, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + +/* Interpolation inlines... */ + +double clamp(double v, double min, double max) +{ + return (v < min) ? min : ((v > max) ? max : v); +} + +/* Bilinear interpolation is just a weighted average of the two sources. + v0 is the value at point 0, v1 is the value at point 1, and position is a + fractional position between the two. */ + +double BilinearInterpolate1d( + double v0, + double v1, + double position) +{ + return v0 * (1.0 - position) + v1 * position; +} + +/* 2-d interpolation is just a recursion on 1-d interpolation. Our points + are organized as + 0 1 + 2 3 + in two dimensions with hPosition and vPosition being fractions specifying + where in the square we want to interpolate. */ + +double BilinearInterpolate2d( + double v0, double v1, + double v2, double v3, + double hPosition, + double vPosition) +{ + return BilinearInterpolate1d( + BilinearInterpolate1d(v0, v1, hPosition), + BilinearInterpolate1d(v2, v3, hPosition), + vPosition); +} + +/* Bicubic Interpolation. We take four values at -1, 0, 1, and 2. + We use all of them to interpolate a fractional value between 0 and 1. + But we take advantage of the extra data to provide more accuracy in + our interpolation. */ + +double BicubicInterpolate1d( + double v0, + double v1, + double v2, + double v3, + double position) +{ + /* + Bicubic interpolation constructs a cubic polynomial through all + four points passed in: (-1.0, v0) (0.0, v1) (1.0, v2) (2.0, v3) + and then evaluates it for position. + + The polynomial can be represented as: + + Ax^3 + Bx^2 + Cx + D + + I precalculated the values for A, B, C, and D based on v0-v3. We + calculate these constants and then plug them into the equation. + */ + + double D = v1; + double B = (v0 + v2) / 2.0 - v1; + double A = (v3 - v2 - 3 * B) / 7.0; + double C = v2 - A - B - D; + + return clamp(A * position * position * position + + B * position * position + + C * position + D, 0, 255.0); + +} + +double BicubicInterpolate2d( + double v0, double v1, double v2, double v3, + double v4, double v5, double v6, double v7, + double v8, double v9, double v10, double v11, + double v12, double v13, double v14, double v15, + double hPosition, + double vPosition) +{ + return BicubicInterpolate1d( + BicubicInterpolate1d(v0, v1, v2, v3, hPosition), + BicubicInterpolate1d(v4, v5, v6, v7, hPosition), + BicubicInterpolate1d(v8, v9, v10, v11, hPosition), + BicubicInterpolate1d(v12, v13, v14, 15, hPosition), + vPosition); +} diff --git a/src/PlatformUtils.h b/src/PlatformUtils.h new file mode 100644 index 000000000..4c032cfa2 --- /dev/null +++ b/src/PlatformUtils.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2004, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef _PlatformUtils_h_ +#define _PlatformUtils_h_ + +/* + * PlatformUtils + * + * This file declares all of the platform specific code for the converter. + * + * PlatformUtils.mac.c contains the mac implementation; this code must be rewritten + * for the PC. + * + */ + +/* The directory separator is a macro and should be cased by some kind of compiler + #define or something. */ + +#if IBM + #define DIR_CHAR '\\' + #define DIR_STR "\\" +#elif (APL && __MACH__) || LIN + #define DIR_CHAR '/' + #define DIR_STR "/" +#elif APL + #define DIR_CHAR ':' + #define DIR_STR ":" +#else + #error PLATFORM NOT DEFINED +#endif + +/* + * These routines convert between little endian and native endian. This means they + * swap byte order on the Mac and do nothing on the PC. These are good for reading + * PC File structures, but EndianUtils.h contains more powerful stuff. + * + */ + +void EndianFlipShort(short * ioShort); +void EndianFlipLong(long * ioLong); + +/* + * This routine returns a fully qualified path to the application. + * + */ +const char * GetApplicationPath(void); + +#if APL +/* + * Convert an HFS path to a POSIX Path. Returns 0 for success, -1 for failure. + * WARNING: this only works for EXISTING FILES!!!!!!!!!!!!!!!!! + * + */ +int HFS2PosixPath(const char *path, char *result, int resultLen); +int Posix2HFSPath(const char *path, char *result, int resultLen); +#endif + +/* + * Takes a path and replaces the dir chars with the 'native' ones. + * Note that this is intended for PARTIAL paths. + * + */ +void MakePartialPathNative(char * ioBegin, char * ioEnd); // Takes a char range + + +/* + * GetFilePathFromUser takes a prompting C-string and fills in the buffer with a path + * to a picked file. It returns 1 if a file was picked, 0 if the user canceled. + * + */ +enum { + getFile_Open, + getFile_Save, + getFile_PickFolder +}; +int GetFilePathFromUser( + int inType, + const char * inPrompt, + const char * inAction, + int inID, + char * outFileName); + +/* + * DoUserAlert puts up an alert dialog box with the message and an OK button. + * + */ +void DoUserAlert(const char * inMsg); + +/* + * ShowProgressMessage puts up a dialog box with a progress message. Calling it + * repeatedly changes the progress message. + * + */ +void ShowProgressMessage(const char * inMsg, float * progress); + +/* + * ConfirmMessage puts up a dialog box with a message and two buttons. The proceed + * button is the default one. Pass in the message and the text of the two buttons. + * Returns 1 if the user clicks the proceed button, 0 if the user cancels. + * + */ +int ConfirmMessage(const char * inMsg, const char * proceedBtn, const char * cancelBtn); + +#endif diff --git a/src/PlatformUtils.lin.cpp b/src/PlatformUtils.lin.cpp new file mode 100644 index 000000000..316a3cc82 --- /dev/null +++ b/src/PlatformUtils.lin.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2004, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "PlatformUtils.h" +#include + + +void EndianFlipShort(short * ioShort) + +{ + // Not necessary on WINTEL machines. +} + +void EndianFlipLong(long * ioLong) + +{ + // Not necessary on WINTEL machines. +} + + +int GetFilePathFromUser( + int inType, + const char * inPrompt, + const char * inAction, + int inID, + char * outFileName) +{ +} + + +void DoUserAlert(const char * inMsg) +{ +} + + +void ShowProgressMessage(const char * inMsg, float * inProgress) +{ + +} + + +int ConfirmMessage(const char * inMsg, const char * proceedBtn, const char * cancelBtn) +{ +} + +void MakePartialPathNative(char * ioBegin, char * ioEnd) +{ + for (char * p = ioBegin; p != ioEnd; ++p) + { + if (*p == '/' || *p == ':' || *p == '\\') + *p = DIR_CHAR; + } +} + +// getting the application path on Linux systems is impossible. +// Thus, we return a link to a directory in the users home +// (this is better anyway - this way, the password won't be stored +// on a common system) +const char * GetApplicationPath(void) +{ + return "./dummy"; +} diff --git a/src/PlatformUtils.mac.cpp b/src/PlatformUtils.mac.cpp new file mode 100644 index 000000000..64c753ef5 --- /dev/null +++ b/src/PlatformUtils.mac.cpp @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2004, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "PlatformUtils.h" + +//#define _STDINT_H_ +#include +//#include +//#include +//#include +//#include + +#include + + + +static OSErr FSSpecToPathName(const FSSpec * inFileSpec, char * outPathname); + +/* Endian routines for the Mac use Apple's Endian macros. */ + +void EndianFlipShort(short * ioShort) +{ +#if defined(__POWERPC__) + *ioShort = Endian16_Swap(*ioShort); +#endif +} + +void EndianFlipLong(long * ioLong) +{ +#if defined(__POWERPC__) + *ioLong = Endian32_Swap(*ioLong); +#endif +} + +/* Get FilePathFromUser puts up a nav services dialog box and converts the results + to a C string path. */ + +pascal void event_proc(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, void *callBackUD) +{ +} + +template +struct CFSmartPtr { + CFSmartPtr(T p) : p_(p) { } + ~CFSmartPtr() { if (p_) CFRelease(p_); } + operator T () { return p_; } + T p_; +}; + +int HFS2PosixPath(const char *path, char *result, int resultLen) +{ + CFSmartPtr inStr(CFStringCreateWithCString(kCFAllocatorDefault, path ,kCFStringEncodingMacRoman)); + if (inStr == NULL) return -1; + + CFSmartPtr url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, inStr, kCFURLHFSPathStyle,0)); + if (url == NULL) return -1; + + CFSmartPtr outStr(CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle)); + if (outStr == NULL) return -1; + + if (!CFStringGetCString(outStr, result, resultLen, kCFStringEncodingMacRoman)) + return -1; + + return 0; +} + +int Posix2HFSPath(const char *path, char *result, int resultLen) +{ + CFSmartPtr inStr(CFStringCreateWithCString(kCFAllocatorDefault, path ,kCFStringEncodingMacRoman)); + if (inStr == NULL) return -1; + + CFSmartPtr url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, inStr, kCFURLPOSIXPathStyle,0)); + if (url == NULL) return -1; + + CFSmartPtr outStr(CFURLCopyFileSystemPath(url, kCFURLHFSPathStyle)); + if (outStr == NULL) return -1; + + if (!CFStringGetCString(outStr, result, resultLen, kCFStringEncodingMacRoman)) + return -1; + + return 0; +} + +void MakePartialPathNative(char * ioBegin, char * ioEnd) +{ + for (char * p = ioBegin; p != ioEnd; ++p) + { + if (*p == '/' || *p == ':' || *p == '\\') + *p = DIR_CHAR; + } +} + + + +const char * GetApplicationPath(void) +{ + static char pathBuf[1024]; + ProcessInfoRec pir; + FSSpec spec; + Str255 pStr; + ProcessSerialNumber psn = { 0, kCurrentProcess }; + pir.processInfoLength = sizeof(pir); + pir.processAppSpec = &spec; + pir.processName = pStr; + GetProcessInformation(&psn, &pir); + OSErr err = FSSpecToPathName(&spec, pathBuf); + if (err != noErr) + return NULL; + return pathBuf; +} + +int GetFilePathFromUser( + int inType, + const char * inPrompt, + const char * inAction, + int inID, + char * outFileName) +{ + OSErr err; + NavReplyRecord reply; + NavDialogOptions options; + FSSpec fileSpec; + + reply.version = kNavReplyRecordVersion; + err = NavGetDefaultDialogOptions(&options); + if (err != noErr) + return 0; + + if (inType == getFile_Save) + { + options.savedFileName[0] = strlen(outFileName); + memcpy(options.savedFileName+1, outFileName, options.savedFileName[0]); + } + + options.message[0] = strlen(inPrompt); + memcpy(options.message+1,inPrompt, options.message[0]); + options.actionButtonLabel[0] = strlen(inAction); + memcpy(options.actionButtonLabel+1,inAction, options.actionButtonLabel[0]); + options.dialogOptionFlags &= ~kNavAllowMultipleFiles; + options.preferenceKey = inID; + NavEventUPP eventUPP = NewNavEventUPP(event_proc); + + switch(inType) { + case getFile_Open: + err = NavGetFile(NULL, &reply, &options, eventUPP, NULL, NULL, NULL, NULL); + if ((err != noErr) && (err != userCanceledErr)) + return 0; + break; + case getFile_Save: + err = NavPutFile(NULL, &reply, &options, eventUPP, 0, 0, NULL); + if ((err != noErr) && (err != userCanceledErr)) + return 0; + break; + case getFile_PickFolder: + err = NavChooseFolder(NULL, &reply, &options, eventUPP, NULL, NULL); + if ((err != noErr) && (err != userCanceledErr)) + return 0; + break; + } + DisposeNavEventUPP(eventUPP); + if (!reply.validRecord) + goto bail; + + /* Convert the result from an AEDesc to a Mac file spec. */ + err = AEGetNthPtr(&reply.selection, 1, typeFSS, NULL, NULL, &fileSpec, sizeof(fileSpec), NULL); + if (err != noErr) + goto bail; + + /* Then convert the FSSpec to a full path. */ + err = FSSpecToPathName(&fileSpec, outFileName); + if (err != noErr) + goto bail; + + NavDisposeReply(&reply); + return 1; + +bail: + NavDisposeReply(&reply); + return 0; + + +} + +void DoUserAlert(const char * inMsg) +{ + Str255 p1,p2; + size_t sl; + + sl = strlen(inMsg); + if (sl > 255) + sl = 255; + + p1[0] = sl; + memcpy(p1+1, inMsg, sl); + + p2[0]=0; // Ben says: GCC doesn't understand "\p". + + StandardAlert(kAlertStopAlert, p1, p2, NULL, NULL); +} + +void ShowProgressMessage(const char * inMsg, float * progress) +{ + static WindowRef wind = NULL; + Rect windBounds = { 0, 0, 250, 500 }; + if (wind == NULL) + { + if (CreateNewWindow(kMovableAlertWindowClass, kWindowStandardHandlerAttribute, &windBounds, &wind) != noErr) return; + if (wind == NULL) return; + RepositionWindow(wind, NULL,kWindowCenterOnMainScreen); + ShowWindow(wind); + } + + SetPortWindowPort(wind); + CFStringRef ref = CFStringCreateWithCString(NULL, inMsg, smSystemScript); + EraseRect(&windBounds); + InsetRect(&windBounds, 20, 15); + DrawThemeTextBox(ref, kThemeSystemFont, kThemeStateActive, true, &windBounds, teJustLeft, NULL); + CFRelease(ref); + + if (progress) + { + float p = *progress; + ThemeTrackDrawInfo info; + info.kind = (p >= 0.0) ? kThemeMediumProgressBar : kThemeMediumIndeterminateBar; + SetRect(&info.bounds, 20, 210, 480, 230); + info.min = 0; + info.max = (p >= 0.0) ? 1000.0 : 0.0; + info.value = (p >= 0.0) ? (p * 1000.0) : 0; + info.reserved = 0; + info.attributes = kThemeTrackHorizontal; + info.enableState = kThemeTrackActive; + info.filler1 = 0; + static UInt8 nPhase = 0; + info.trackInfo.progress.phase = nPhase; + nPhase++; + DrawThemeTrack(&info, NULL, NULL, 0); + } + QDFlushPortBuffer(GetWindowPort(wind), NULL); +} + +int ConfirmMessage(const char * inMsg, const char * proceedBtn, const char * cancelBtn) +{ + Str255 pStr, proStr, clcStr, p2; + AlertStdAlertParamRec params; + short itemHit; + + pStr[0] = strlen(inMsg); + memcpy(pStr+1,inMsg,pStr[0]); + proStr[0] = strlen(proceedBtn); + memcpy(proStr+1, proceedBtn, proStr[0]); + clcStr[0] = strlen(cancelBtn); + memcpy(clcStr+1, cancelBtn, clcStr[0]); + + params.movable = false; + params.helpButton = false; + params.filterProc = NULL; + params.defaultText = proStr; + params.cancelText = clcStr; + params.otherText = NULL; + params.defaultButton = 1; + params.cancelButton = 2; + params.position = kWindowDefaultPosition; + + p2[0]=0; + + StandardAlert(kAlertCautionAlert, pStr, p2, ¶ms, &itemHit); + + return (itemHit == 1); +} + +/* + * FSSpecToPathName + * + * This routine builds a full path from a file spec by recursing up the directory + * tree to the route, prepending each directory name. + * + */ + +OSErr FSSpecToPathName(const FSSpec * inFileSpec, char * outPathname) +{ + short vRefNum = inFileSpec->vRefNum; + long startDirID = inFileSpec->parID; + + CInfoPBRec paramRec; + Str255 dirName; /* This will contain the name of the directory we get info about. */ + OSErr err = noErr; + + paramRec.dirInfo.ioCompletion = nil; + paramRec.dirInfo.ioNamePtr = (StringPtr)(&dirName); + paramRec.dirInfo.ioDrParID = startDirID; + + /* Start by putting a directory separator and the file name on the path. */ + outPathname[0] = ':'; + memcpy(outPathname+1, inFileSpec->name+1, inFileSpec->name[0]); + outPathname[inFileSpec->name[0]+1] = 0; + + do { + paramRec.dirInfo.ioVRefNum = vRefNum; + paramRec.dirInfo.ioFDirIndex = -1; + paramRec.dirInfo.ioDrDirID = paramRec.dirInfo.ioDrParID; + + if (!(err = PBGetCatInfoSync(¶mRec))) + { + /* For each directory we get info about, prepend a : and the directory name. + But for the root directory, do NOT prepend the colon. */ + short newPart = dirName[0] + ((paramRec.dirInfo.ioDrDirID != fsRtDirID) ? 1 : 0); + memmove(outPathname+newPart, outPathname, strlen(outPathname)+1); + if (paramRec.dirInfo.ioDrDirID != fsRtDirID) + { + outPathname[0] = ':'; + memcpy(outPathname+1, dirName+1, dirName[0]); + } else + memcpy(outPathname, dirName+1, dirName[0]); + } + } while ((err == noErr) && (paramRec.dirInfo.ioDrDirID != fsRtDirID)); + return err; +} + diff --git a/src/PlatformUtils.win.cpp b/src/PlatformUtils.win.cpp new file mode 100644 index 000000000..6bafe1a05 --- /dev/null +++ b/src/PlatformUtils.win.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2004, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include +#include +#include "PlatformUtils.h" +#include +#include + + +void EndianFlipShort(short * ioShort) + +{ + // Not necessary on WINTEL machines. +} + +void EndianFlipLong(long * ioLong) + +{ + // Not necessary on WINTEL machines. +} + +const char * GetApplicationPath(void) + +{ + static char pathBuf[1024]; + if (GetModuleFileName(NULL, pathBuf, sizeof(pathBuf))) + return pathBuf; + else + return NULL; +} + +int GetFilePathFromUser( + int inType, + const char * inPrompt, + const char * inAction, + int inID, + char * outFileName) +{ + BROWSEINFO bif = { 0 }; + OPENFILENAME ofn = { 0 }; + + BOOL result; + + switch(inType) { + case getFile_Open: + case getFile_Save: + ofn.lStructSize = sizeof(ofn); + ofn.lpstrFilter = "All Files\000*.*\000"; + ofn.nFilterIndex = 1; // Start with .acf files + ofn.lpstrFile = outFileName; + if (inType != getFile_Save) + outFileName[0] = 0; // No initialization for open. + ofn.nMaxFile = 512; // Guess string length? + ofn.lpstrFileTitle = NULL; // Don't want file name w/out path + ofn.lpstrTitle = inPrompt; + result = (inType == getFile_Open) ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn); + return (result) ? 1 : 0; + + case getFile_PickFolder: + bif.hwndOwner = NULL; + bif.pidlRoot = NULL; + bif.pszDisplayName = NULL; + bif.lpszTitle = inPrompt; + bif.ulFlags = 0; + bif.lpfn = NULL; + bif.lParam = NULL; + LPITEMIDLIST items = SHBrowseForFolder(&bif); + if (items == NULL) return 0; + result = 0; + if (SHGetPathFromIDList (items, outFileName)) + { + result = 1; + strcat(outFileName, "\\"); + } + IMalloc * imalloc = 0; + if ( SUCCEEDED( SHGetMalloc ( &imalloc )) ) + { + imalloc->Free ( items ); + imalloc->Release ( ); + } + return result ? 1 : 0; + } + + return 0; +} + + +void DoUserAlert(const char * inMsg) +{ + MessageBox(NULL, inMsg, "Alert", MB_OK + MB_ICONWARNING); +} + + +static TCHAR sWindowClass[] = "__XPlaneInstallerWindowClass"; + + +static char progBuf[2048] = { 0 }; + + +LRESULT CALLBACK PaintProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + switch(msg) { + case WM_PAINT: + { + RECT r; + GetClientRect(wnd, &r); + PAINTSTRUCT paint; + HDC dc = BeginPaint(wnd, &paint); + r.left += 20; + r.right -= 20; + r.top += 15; + r.bottom -= 40; + DrawText(dc, progBuf, strlen(progBuf), &r, DT_LEFT | DT_WORDBREAK); + EndPaint(wnd, &paint); + return 0; + } + break; + default: + return DefWindowProc(wnd, msg, wparam, lparam); + } +} + + + +void ShowProgressMessage(const char * inMsg, float * inProgress) +{ + strcpy(progBuf, inMsg); + + + static HWND wind = NULL; + static HWND prog = NULL; + if (wind == NULL) + { + + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = PaintProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = GetModuleHandle(NULL); + wcex.hIcon = NULL; // LoadIcon(hInstance, (LPCTSTR)IDI_TESTDND); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = sWindowClass; + wcex.hIconSm = NULL; // LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + + + RegisterClassEx(&wcex); + + + wind = CreateWindowEx( + WS_EX_APPWINDOW | WS_EX_DLGMODALFRAME, + sWindowClass, + "X-Plane Installer", + WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN , + 50, 100, 500, 250, + NULL, + NULL, + GetModuleHandle(NULL), + NULL); + + + InitCommonControls(); + RECT rcClient; + ShowWindow(wind, SW_SHOWNORMAL); + GetClientRect(wind, &rcClient); + int cyVScroll = GetSystemMetrics(SM_CYVSCROLL); + prog = CreateWindowEx(0, PROGRESS_CLASS, + (LPSTR) NULL, WS_CHILD | WS_VISIBLE, + rcClient.left + 20, rcClient.bottom - 20 - + cyVScroll, rcClient.right - 40, cyVScroll, + wind, NULL, GetModuleHandle(NULL), NULL); + SendMessage(prog, PBM_SETRANGE, 0, + MAKELPARAM(0, 1000)); + SendMessage(prog, PBM_SETPOS, (WPARAM) 0, 0); + } + + + RECT br; + br.left = 0; + br.right = 500; + br.bottom = 210; + br.top = 0; + InvalidateRect(wind, &br, TRUE); + + + if (inProgress != NULL) + { + float v = *inProgress; + ShowWindow(prog,SW_SHOWNORMAL); + if (v >= 0.0) + { + int n = v * 1000.0; +// SendMessage(prog, PBM_SETMARQUEE, (WPARAM) 0, 0); + SendMessage(prog, PBM_SETPOS, (WPARAM) n, 0); + } else { +// SendMessage(prog, PBM_SETMARQUEE, (WPARAM) 1, 0); + SendMessage(prog, PBM_SETPOS, (WPARAM) 0, 0); + } + } else + ShowWindow(prog,SW_HIDE); + + + MSG msg; + if (PeekMessage(&msg, wind, 0, 0, PM_REMOVE)) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } +} + + +int ConfirmMessage(const char * inMsg, const char * proceedBtn, const char * cancelBtn) +{ + int result = MessageBox( + NULL, // No Parent HWND + inMsg, + "X-Plane 8", // Dialog caption +// MB_OKCANCEL + + MB_YESNO + +// MB_ICONWARNING + + MB_USERICON + + MB_DEFBUTTON1); + + + return (result == IDOK || result == IDYES) ? 1 : 0; +} + +void MakePartialPathNative(char * ioBegin, char * ioEnd) +{ + for (char * p = ioBegin; p != ioEnd; ++p) + { + if (*p == '/' || *p == ':' || *p == '\\') + *p = DIR_CHAR; + } +} + diff --git a/src/TexUtils.cpp b/src/TexUtils.cpp new file mode 100644 index 000000000..3e6460e4f --- /dev/null +++ b/src/TexUtils.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2006, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "XPLMGraphics.h" +#include "TexUtils.h" +#include "BitmapUtils.h" +#include "XPLMUtilities.h" +#include +#include +#include +#include +#include +#if IBM +#include +#include +#include +#elif APL +#include +#include +#else +#include +#include +#endif + +using std::swap; + +static void HalfBitmap(ImageInfo& ioImage) +{ + int row_b = (ioImage.width * ioImage.channels) + ioImage.pad; + + unsigned char * srcp1 = ioImage.data; + unsigned char * srcp2 = ioImage.data + row_b; + unsigned char * dstp = ioImage.data; + + ioImage.height /= 2; + ioImage.width /= 2; + int yr = ioImage.height; + int t1, t2, t3, t4; + + if (ioImage.channels == 3) + { + while (yr--) + { + int xr = ioImage.width; + while (xr--) + { + t1 = *srcp1++; + t2 = *srcp1++; + t3 = *srcp1++; + + t1 += *srcp1++; + t2 += *srcp1++; + t3 += *srcp1++; + + t1 += *srcp2++; + t2 += *srcp2++; + t3 += *srcp2++; + + t1 += *srcp2++; + t2 += *srcp2++; + t3 += *srcp2++; + + t1 >>= 2; + t2 >>= 2; + t3 >>= 2; + + *dstp++ = t1; + *dstp++ = t2; + *dstp++ = t3; + } + + srcp1 += row_b; + srcp1 += ioImage.pad; + srcp2 += row_b; + srcp2 += ioImage.pad; + } + } else { + + while (yr--) + { + int xr = ioImage.width; + while (xr--) + { + t1 = *srcp1++; + t2 = *srcp1++; + t3 = *srcp1++; + t4 = *srcp1++; + + t1 += *srcp1++; + t2 += *srcp1++; + t3 += *srcp1++; + t4 += *srcp1++; + + t1 += *srcp2++; + t2 += *srcp2++; + t3 += *srcp2++; + t4 += *srcp2++; + + t1 += *srcp2++; + t2 += *srcp2++; + t3 += *srcp2++; + t4 += *srcp2++; + + t1 >>= 2; + t2 >>= 2; + t3 >>= 2; + t4 >>= 2; + + *dstp++ = t1; + *dstp++ = t2; + *dstp++ = t3; + *dstp++ = t4; + } + + srcp1 += row_b; + srcp1 += ioImage.pad; + srcp2 += row_b; + srcp2 += ioImage.pad; + } + } + ioImage.pad = 0; + +} + +bool LoadTextureFromFile(const char * inFileName, int inTexNum, bool magentaAlpha, bool inWrap, bool mipmap, int * outWidth, int * outHeight, int inDeres) +{ + bool ok = false; + struct ImageInfo im; + long count = 0; +#if 1 + unsigned char * p; +#endif + int result = CreateBitmapFromPNG(inFileName, &im); + if (result) result = CreateBitmapFromFile(inFileName, &im); + if (result == 0) + { + while (inDeres > 0) + { + HalfBitmap(im); + --inDeres; + } + + if (!magentaAlpha || ConvertBitmapToAlpha(&im) == 0) + { + if (im.pad == 0) + { + XPLMBindTexture2d(inTexNum, 0); + if (magentaAlpha) + { +#if 1 + p = im.data; + count = im.width * im.height; + while (count--) + { + std::swap(p[0], p[2]); +// swap(p[1], p[2]); + p += 4; + } +#endif + if (mipmap) + gluBuild2DMipmaps(GL_TEXTURE_2D, 4, im.width, im.height, GL_RGBA, GL_UNSIGNED_BYTE, im.data); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, im.width ,im.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, im.data); + if (outWidth) *outWidth = im.width; + if (outHeight) *outHeight = im.height; + } else { +#if 1 + p = im.data; + count = im.width * im.height; + while (count--) + { + std::swap(p[0], p[2]); + p += 3; + } +#endif + if (mipmap) + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, im.width, im.height, GL_RGB, GL_UNSIGNED_BYTE, im.data); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, im.width ,im.height, 0, GL_RGB, GL_UNSIGNED_BYTE, im.data); + if (outWidth) *outWidth = im.width; + if (outHeight) *outHeight = im.height; + } + ok = true; + } + } + + DestroyBitmap(&im); + } + + if (ok) + { + // BAS note: for some reason on my WinXP system with GF-FX, if + // I do not set these explicitly to linear, I get no drawing at all. + // Who knows what default state the card is in. :-( + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmap ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR); + + static const char * ver_str = (const char *) glGetString(GL_VERSION); + static const char * ext_str = (const char *) glGetString(GL_EXTENSIONS); + + static bool tex_clamp_avail = + strstr(ext_str,"GL_SGI_texture_edge_clamp" ) || + strstr(ext_str,"GL_SGIS_texture_edge_clamp" ) || + strstr(ext_str,"GL_ARB_texture_edge_clamp" ) || + strstr(ext_str,"GL_EXT_texture_edge_clamp" ) || + strncmp(ver_str,"1.2", 3) || + strncmp(ver_str,"1.3", 3) || + strncmp(ver_str,"1.4", 3) || + strncmp(ver_str,"1.5", 3); + + + if(inWrap ){glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT ); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT );} + else if(tex_clamp_avail){glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);} + else {glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP ); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP );} + + } + int err = glGetError(); + if (err) + { + char buf[256]; + sprintf(buf, "Texture load got OGL err: %d\n", err); + XPLMDebugString(buf); + } + return ok; +} diff --git a/src/TexUtils.h b/src/TexUtils.h new file mode 100644 index 000000000..068b44623 --- /dev/null +++ b/src/TexUtils.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2006, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef TEXUTILS_H +#define TEXUTILS_H + +bool LoadTextureFromFile(const char * inFileName, int inTexNum, bool magentaAlpha, bool inWrap, bool inMipmap, int * outWidth, int * outHeight, int inDeres); + + + +#endif diff --git a/src/XOGLUtils.cpp b/src/XOGLUtils.cpp new file mode 100644 index 000000000..51e8a4c0b --- /dev/null +++ b/src/XOGLUtils.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2005, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + #include "XOGLUtils.h" + +// This had to be renamed because on Linux, namespaces appear to be shared between ourselves and XPlane +// so i would end up overwritting XPlanes function pointer! +#if APL +//PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; +#endif +#if IBM +PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; +PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL; +PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = NULL; +PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL; +PFNGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB = NULL; +#endif + +/************************************************** +Nasty Mac Specific Stuff to Load OGL DLL Extensions +***************************************************/ + +#if APL + +#include +#include + +CFBundleRef gBundleRefOpenGL = NULL; + +OSStatus aglInitEntryPoints (void) +{ + OSStatus err = noErr; + const Str255 frameworkName = "\pOpenGL.framework"; + FSRefParam fileRefParam; + FSRef fileRef; + CFURLRef bundleURLOpenGL; + + memset(&fileRefParam, 0, sizeof(fileRefParam)); + memset(&fileRef, 0, sizeof(fileRef)); + + fileRefParam.ioNamePtr = frameworkName; + fileRefParam.newRef = &fileRef; + + // Frameworks directory/folder + err = FindFolder (kSystemDomain, kFrameworksFolderType, false, + &fileRefParam.ioVRefNum, &fileRefParam.ioDirID); + if (noErr != err) { + return err; + } + err = PBMakeFSRefSync (&fileRefParam); // make FSRef for folder + if (noErr != err) { + return err; + } + // create URL to folder + bundleURLOpenGL = CFURLCreateFromFSRef (kCFAllocatorDefault, + &fileRef); + if (!bundleURLOpenGL) { + return paramErr; + } + // create ref to GL's bundle + gBundleRefOpenGL = CFBundleCreate (kCFAllocatorDefault, + bundleURLOpenGL); + if (!gBundleRefOpenGL) { + return paramErr; + } + CFRelease (bundleURLOpenGL); // release created bundle + // if the code was successfully loaded, look for our function. + if (!CFBundleLoadExecutable (gBundleRefOpenGL)) { + return paramErr; + } + return err; +} + +void * aglGetProcAddress (char * pszProc) +{ + static bool first_time = true; + if (first_time) + { + first_time = false; + if (aglInitEntryPoints() != noErr) + return NULL; + } + return CFBundleGetFunctionPointerForName (gBundleRefOpenGL, + CFStringCreateWithCStringNoCopy (NULL, + pszProc, CFStringGetSystemEncoding (), NULL)); +} + +#define wglGetProcAddress(x) aglGetProcAddress(x) + +#endif + +#if LIN + +#define wglGetProcAddress(x) glXGetProcAddressARB((GLubyte*) (x)) + +#endif + +/************************************************** + Utilities Initialization +***************************************************/ + +bool OGL_UtilsInit() +{ + static bool firstTime = true; + if(firstTime) + { + // Initialize all OGL Function Pointers +#if APL + //glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB" ); +#endif +#if IBM + glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB" ); + glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress("glActiveTextureARB" ); + glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress("glClientActiveTextureARB"); + glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC ) wglGetProcAddress("glMultiTexCoord2fARB" ); + glMultiTexCoord2fvARB = (PFNGLMULTITEXCOORD2FVARBPROC ) wglGetProcAddress("glMultiTexCoord2fvARB" ); +#endif + firstTime = false; + } + + // Make sure everything got initialized + if(glBindBufferARB && + glActiveTextureARB && + glClientActiveTextureARB && + glMultiTexCoord2fARB && + glMultiTexCoord2fvARB) + { + return true; + } + else + return false; + +} diff --git a/src/XOGLUtils.h b/src/XOGLUtils.h new file mode 100644 index 000000000..c9f449b62 --- /dev/null +++ b/src/XOGLUtils.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _XOGLUtils_h_ +#define _XOGLUtils_h_ + +#if IBM + #include + #include + #include + #include +#elif LIN + #define GLX_GLXEXT_PROTOTYPES + #define GL_GLEXT_PROTOTYPES + #include + #include + #include + #include +#elif APL + #include + #include + #include +#endif + +#if LIN + #define GLX_GLXEXT_PROTOTYPES +#endif + +// Open GL Extension Defintion +#if APL + #define APIENTRY +#endif +#if APL || LIN + #define GL_ARRAY_BUFFER_ARB 0x8892 + #define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 +#endif + +typedef void (APIENTRY * PFNGLBINDBUFFERARBPROC ) (GLenum, GLuint); +typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum); +typedef void (APIENTRY * PFNGLCLIENTACTIVETEXTUREARBPROC ) (GLenum); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC ) (GLenum, GLfloat, GLfloat); +typedef void (APIENTRY * PFNGLMULTITEXCOORD2FVARBPROC) (GLenum, const GLfloat *); + +#if IBM +extern PFNGLBINDBUFFERARBPROC glBindBufferARB; +extern PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB; +extern PFNGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB; +extern PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; +extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB; +#endif + +bool OGL_UtilsInit(); + +#endif diff --git a/src/XObjDefs.cpp b/src/XObjDefs.cpp new file mode 100644 index 000000000..ecf065b29 --- /dev/null +++ b/src/XObjDefs.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2004, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "XObjDefs.h" + +cmd_info gCmds[] = { + +{ obj_End, type_None, "end", 0 }, +{ obj_Light, type_PtLine, "light", 1 }, +{ obj_Line, type_PtLine, "line", 2 }, +{ obj_Tri, type_Poly, "tri", 3 }, +{ obj_Quad, type_Poly, "quad", 4 }, +{ obj_Quad_Cockpit, type_Poly, "quad_cockpit", 4 }, +{ obj_Quad_Hard, type_Poly, "quad_hard", 4 }, +{ obj_Smoke_Black, type_Attr, "smoke_black", 4 }, +{ obj_Smoke_White, type_Attr, "smoke_white", 4 }, +{ obj_Movie, type_Poly, "quad_movie", 4 }, +{ obj_Polygon, type_Poly, "polygon", 0 }, +{ obj_Quad_Strip, type_Poly, "quad_strip", 0 }, +{ obj_Tri_Strip, type_Poly, "tri_strip", 0 }, +{ obj_Tri_Fan, type_Poly, "tri_fan", 0 }, +{ attr_Shade_Flat, type_Attr, "ATTR_shade_flat", 0 }, +{ attr_Shade_Smooth, type_Attr, "ATTR_shade_smooth",0 }, +{ attr_Shade_Flat, type_Attr, "shade_flat", 0 }, +{ attr_Shade_Smooth, type_Attr, "shade_smooth", 0 }, +{ attr_Ambient_RGB, type_Attr, "ATTR_ambient_rgb", 3 }, +{ attr_Diffuse_RGB, type_Attr, "ATTR_difuse_rgb", 3 }, +{ attr_Emission_RGB, type_Attr, "ATTR_emission_rgb",3 }, +{ attr_Specular_RGB, type_Attr, "ATTR_specular_rgb",3 }, +{ attr_Shiny_Rat, type_Attr, "ATTR_shiny_rat", 1 }, +{ attr_No_Depth, type_Attr, "ATTR_no_depth", 0 }, +{ attr_Depth, type_Attr, "ATTR_depth", 0 }, +{ attr_LOD, type_Attr, "ATTR_LOD", 2 }, +{ attr_Reset, type_Attr, "ATTR_reset", 0 }, +{ attr_Cull, type_Attr, "ATTR_cull", 0 }, +{ attr_NoCull, type_Attr, "ATTR_no_cull", 0 }, +{ attr_Offset, type_Attr, "ATTR_poly_os", 1 }, +{ attr_Max, type_None, NULL, 0 } +}; + + +int FindObjCmd(const char * inToken) +{ + int n = 0; + while (gCmds[n].name) + { + if (!strcmp(inToken, gCmds[n].name)) + return n; + ++n; + } + + return attr_Max; +} + +int FindIndexForCmd(int inCmd) +{ + int n = 0; + while (gCmds[n].name) + { + if (gCmds[n].cmd_id == inCmd) + return n; + ++n; + } + return 0; +} \ No newline at end of file diff --git a/src/XObjDefs.h b/src/XObjDefs.h new file mode 100644 index 000000000..a9d266436 --- /dev/null +++ b/src/XObjDefs.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2004, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef XOBJDEFS_H +#define XOBJDEFS_H + +#include +#include +using namespace std; + +enum { + + type_None = 0, + type_PtLine, + type_Poly, + type_Attr + +}; + +enum { + obj_End = 0, + obj_Light, + obj_Line, + obj_Tri, + obj_Quad, + obj_Quad_Hard, + obj_Quad_Cockpit, + obj_Smoke_Black, + obj_Smoke_White, + obj_Movie, + obj_Polygon, + obj_Quad_Strip, + obj_Tri_Strip, + obj_Tri_Fan, + attr_Shade_Flat, + attr_Shade_Smooth, + attr_Ambient_RGB, + attr_Diffuse_RGB, + attr_Emission_RGB, + attr_Specular_RGB, + attr_Shiny_Rat, + attr_No_Depth, + attr_Depth, + attr_LOD, + attr_Reset, + attr_Cull, + attr_NoCull, + attr_Offset, + attr_Max +}; + +struct cmd_info { + int cmd_id; + int cmd_type; + const char * name; + int elem_count; +}; + +extern cmd_info gCmds[]; + +struct vec_tex { + float v[3]; + float st[2]; +}; + +struct vec_rgb { + float v[3]; + float rgb[3]; +}; + +struct XObjCmd { + + int cmdType; // Are we a line, poly or attribute? + int cmdID; // What command are we? + + vector attributes; + vector st; + vector rgb; + +}; + +struct XObj { + + string texture; + vector cmds; + +}; + +int FindObjCmd(const char * inToken); + +int FindIndexForCmd(int inCmd); + +#endif \ No newline at end of file diff --git a/src/XObjReadWrite.cpp b/src/XObjReadWrite.cpp new file mode 100644 index 000000000..3256ba9c0 --- /dev/null +++ b/src/XObjReadWrite.cpp @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2004, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "XObjReadWrite.h" +#include "XObjDefs.h" +#include "XUtils.h" +#include + +#if APL + #define CRLF "\r" +#elif WIN + #define CRLF "\r\n" +#else + #define CRLF "\n" +#endif + +/* + TODO: err checking diagnostics + TODO: fix scientific notation support. +*/ + +bool XObjRead(const char * inFile, XObj& outObj) +{ + vector tokens; + string ascii, vers, tag, line; + int cmd_id, count, obj2_op; + int version = 1; + vec_tex vst; + vec_rgb vrgb; + + float scanned_st_rgb[4][3]={0,0,0 , 0,0,0,// [corner][color or st] + 0,0,0 , 0,0,0}; + + outObj.cmds.clear(); + + /********************************************************************* + * READ HEADER + *********************************************************************/ + + StTextFileScanner f(inFile, true); + if (f.done()) return false; + + // First we should have some kind of token telling us whether we're Mac or PC + // line endings. But we don't care that much. + line = f.get(); + BreakString(line, tokens); + if (tokens.empty()) return false; + ascii = tokens[0]; + f.next(); + if (f.done()) return false; + + // Read the version string. We expect either '2' or '700'. + line = f.get(); + + BreakString(line, tokens); + if (tokens.empty()) return false; + vers = tokens[0]; + f.next(); + if (f.done()) return false; + + if (vers == "700") version = 7; + else if (vers == "2" ) version = 2; + else version = 1; + + // If we're OBJ7, another token 'OBJ' follows...this is because + // all XP7 files start with the previous two lines. + if (version == 7) + { + line = f.get(); + BreakString(line, tokens); + if (tokens.empty()) return false; + tag = tokens[0]; + f.next(); + if (f.done()) return false; + } + + // The last line of the header is the texture file name. + if (version != 1) + { + line = f.get(); + BreakString(line, tokens); + if (tokens.empty()) return false; + outObj.texture = tokens[0]; + f.next(); + if (f.done()) return false; + } + + /************************************************************ + * READ GEOMETRIC COMMANDS + ************************************************************/ + bool first_loop = true; + while (!f.done()) + { + XObjCmd cmd; + + // Special case, don't pull from the file for v-1...that + // version string is really an obj command. + if (version != 1 || !first_loop) + { + line = f.get(); + f.next(); + } + first_loop = false; + + BreakString(line, tokens); + if (tokens.empty()) continue; + + /************************************************************ + * OBJ2 SCANNING + ************************************************************/ + if (version != 7) + { + obj2_op = atoi(tokens[0].c_str()); + switch(obj2_op) { + case 1: + case 2: + // Points and lines. The header line contains the color x10. + // The type (pt or line) tell how much geometry follows. + cmd.cmdID = (obj2_op == 1) ? obj_Light : obj_Line; + cmd.cmdType = type_PtLine; + count = obj2_op; + if (tokens.size() < 4) return false; + scanned_st_rgb[0][0]=scanned_st_rgb[1][0]=atof(tokens[1].c_str())*0.1; // r + scanned_st_rgb[0][1]=scanned_st_rgb[1][1]=atof(tokens[2].c_str())*0.1; // g + scanned_st_rgb[0][2]=scanned_st_rgb[1][2]=atof(tokens[3].c_str())*0.1; // b + + // Sets of x,y,z follows. + for (int t = 0; t < count; ++t) + { + line = f.get(); + f.next(); + BreakString(line, tokens); + if (tokens.size() < 3) return false; + vrgb.v[0] = atof(tokens[0].c_str()); + vrgb.v[1] = atof(tokens[1].c_str()); + vrgb.v[2] = atof(tokens[2].c_str()); + vrgb.rgb[0] = scanned_st_rgb[t][0]; + vrgb.rgb[1] = scanned_st_rgb[t][1]; + vrgb.rgb[2] = scanned_st_rgb[t][2]; + cmd.rgb.push_back(vrgb); + } + outObj.cmds.push_back(cmd); + break; + + case 3: + case 4: + case 5: + // Finite-size polygons. The header line contains s1, s2, t1, t2. + cmd.cmdID = (obj2_op == 5) ? obj_Quad_Hard : obj_Quad; + if (obj2_op == 3) cmd.cmdID = obj_Tri; + cmd.cmdType = type_Poly; + count = obj2_op; + if (count == 5) count = 4; + if (tokens.size() < 5 && version == 2) return false; + // Make sure to 'spread' the 4 S/T coords to 8 points. This is + // because + if (version == 2) + { + scanned_st_rgb[2][0]=scanned_st_rgb[3][0]=atof(tokens[1].c_str()); // s1 + scanned_st_rgb[0][0]=scanned_st_rgb[1][0]=atof(tokens[2].c_str()); // s2 + scanned_st_rgb[1][1]=scanned_st_rgb[2][1]=atof(tokens[3].c_str()); // t1 + scanned_st_rgb[0][1]=scanned_st_rgb[3][1]=atof(tokens[4].c_str()); // t2 + } else { + scanned_st_rgb[2][0]=scanned_st_rgb[3][0]=0.0; + scanned_st_rgb[0][0]=scanned_st_rgb[1][0]=0.0; + scanned_st_rgb[1][1]=scanned_st_rgb[2][1]=0.0; + scanned_st_rgb[0][1]=scanned_st_rgb[3][1]=0.0; + } + // Read sets of 3 points. + for (int t = 0; t < count; ++t) + { + line = f.get(); + f.next(); + BreakString(line, tokens); + if (tokens.size() < 3) return false; + + vst.v[0] = atof(tokens[0].c_str()); + vst.v[1] = atof(tokens[1].c_str()); + vst.v[2] = atof(tokens[2].c_str()); + vst.st[0] = scanned_st_rgb[t][0]; + vst.st[1] = scanned_st_rgb[t][1]; + cmd.st.push_back(vst); + } + outObj.cmds.push_back(cmd); + break; + + case 99: + // 99 is the end token for obj2 files. + return true; + default: + // Negative numbers equal positive + // quad strips. The count is the number + // of vertex pairs, since they are always even. + if (obj2_op >= 0) + return false; + count = -obj2_op; + cmd.cmdID = obj_Quad_Strip; + cmd.cmdType = type_Poly; + + // Read a pair of x,y,z,s,t coords. + while (count--) + { + line = f.get(); + f.next(); + BreakString(line, tokens); + if (tokens.size() < 10) return false; + vst.v[0] = atof(tokens[0].c_str()); + vst.v[1] = atof(tokens[1].c_str()); + vst.v[2] = atof(tokens[2].c_str()); + vst.st[0] = atof(tokens[6].c_str()); + vst.st[1] = atof(tokens[8].c_str()); + cmd.st.push_back(vst); + vst.v[0] = atof(tokens[3].c_str()); + vst.v[1] = atof(tokens[4].c_str()); + vst.v[2] = atof(tokens[5].c_str()); + vst.st[0] = atof(tokens[7].c_str()); + vst.st[1] = atof(tokens[9].c_str()); + cmd.st.push_back(vst); + } + outObj.cmds.push_back(cmd); + break; + } + + } else { + + /************************************************************ + * OBJ7 SCANNING + ************************************************************/ + + cmd_id = FindObjCmd(tokens[0].c_str()); + + cmd.cmdType = gCmds[cmd_id].cmd_type; + cmd.cmdID = gCmds[cmd_id].cmd_id; + count = gCmds[cmd_id].elem_count; + + switch(gCmds[cmd_id].cmd_type) { + case type_None: + if (cmd_id == obj_End) + return true; + else + return false; + case type_PtLine: + + if ((count == 0) && (tokens.size() > 1)) + count = atoi(tokens[1].c_str()); + while (count-- && !f.done()) + { + line = f.get(); + f.next(); + BreakString(line, tokens); + if (tokens.size() > 5) + { + vrgb.v[0] = atof(tokens[0].c_str()); + vrgb.v[1] = atof(tokens[1].c_str()); + vrgb.v[2] = atof(tokens[2].c_str()); + vrgb.rgb[0] = atof(tokens[3].c_str()); + vrgb.rgb[1] = atof(tokens[4].c_str()); + vrgb.rgb[2] = atof(tokens[5].c_str()); + + cmd.rgb.push_back(vrgb); + } else + return false; + } + outObj.cmds.push_back(cmd); + break; + + case type_Poly: + + if ((count == 0) && (tokens.size() > 1)) + count = atoi(tokens[1].c_str()); + while (count-- && !f.done()) + { + line = f.get(); + f.next(); + BreakString(line, tokens); + if (tokens.size() > 4) + { + vst.v[0] = atof(tokens[0].c_str()); + vst.v[1] = atof(tokens[1].c_str()); + vst.v[2] = atof(tokens[2].c_str()); + vst.st[0] = atof(tokens[3].c_str()); + vst.st[1] = atof(tokens[4].c_str()); + + cmd.st.push_back(vst); + + if (tokens.size() > 9) + { + --count; + vst.v[0] = atof(tokens[5].c_str()); + vst.v[1] = atof(tokens[6].c_str()); + vst.v[2] = atof(tokens[7].c_str()); + vst.st[0] = atof(tokens[8].c_str()); + vst.st[1] = atof(tokens[9].c_str()); + + cmd.st.push_back(vst); + } + + } else + return false; + } + outObj.cmds.push_back(cmd); + break; + case type_Attr: + + if (tokens.size() > count) + { + for (int n = 0; n < count; ++n) + cmd.attributes.push_back(atof(tokens[n+1].c_str())); + } else + return false; + + outObj.cmds.push_back(cmd); + break; + } + + } // Obj 7 case + + } // While loop + return true; +} + +#if !defined(APL) +#define APL 0 +#endif + +bool XObjWrite(const char * inFile, const XObj& inObj) +{ + FILE * fi = fopen(inFile, "w"); + if (!fi) return false; + + fprintf(fi,"%c" CRLF, APL ? 'A' : 'I'); + fprintf(fi,"700" CRLF); + fprintf(fi,"OBJ" CRLF CRLF); + fprintf(fi,"%s\t\t//" CRLF CRLF, inObj.texture.c_str()); + + for (vector::const_iterator iter = inObj.cmds.begin(); iter != inObj.cmds.end(); ++iter) + { + int index = FindIndexForCmd(iter->cmdID); + switch(iter->cmdType) { + case type_PtLine: + + if (gCmds[index].elem_count == 0) + fprintf(fi,"%s %d\t\t//" CRLF, gCmds[index].name, iter->rgb.size()); + else + fprintf(fi,"%s\t\t//" CRLF, gCmds[index].name); + + for (vector::const_iterator riter = iter->rgb.begin(); + riter != iter->rgb.end(); ++riter) + { + fprintf(fi,"%f %f %f %f %f %f" CRLF, + riter->v[0], riter->v[1], riter->v[2], + riter->rgb[0], riter->rgb[1], riter->rgb[2]); + } + fprintf(fi,CRLF); + break; + + + case type_Poly: + + if (gCmds[index].elem_count == 0) + fprintf(fi,"%s %d\t\t//" CRLF, gCmds[index].name, iter->st.size()); + else + fprintf(fi,"%s\t\t//" CRLF, gCmds[index].name); + + for (vector::const_iterator siter = iter->st.begin(); + siter != iter->st.end(); ++siter) + { + fprintf(fi,"%f %f %f %f %f" CRLF, + siter->v[0], siter->v[1], siter->v[2], + siter->st[0], siter->st[1]); + } + fprintf(fi,CRLF); + break; + + + case type_Attr: + fprintf(fi,"%s",gCmds[index].name); + for (vector::const_iterator aiter = iter->attributes.begin(); + aiter != iter->attributes.end(); ++aiter) + { + fprintf(fi," %f", *aiter); + } + fprintf(fi, "\t\t//" CRLF CRLF); + break; + } + } + + fprintf(fi,"end\t\t//" CRLF); + + fclose(fi); + return true; +} diff --git a/src/XObjReadWrite.h b/src/XObjReadWrite.h new file mode 100644 index 000000000..ba32782a5 --- /dev/null +++ b/src/XObjReadWrite.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2004, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef XOBJREADWRITE_H +#define XOBJREADWRITE_H + +struct XObj; + +bool XObjRead(const char * inFile, XObj& outObj); +bool XObjWrite(const char * inFile, const XObj& inObj); + +#endif \ No newline at end of file diff --git a/src/XPMPMultiplayer.cpp b/src/XPMPMultiplayer.cpp new file mode 100644 index 000000000..ba0b0b378 --- /dev/null +++ b/src/XPMPMultiplayer.cpp @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2004, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XPMPMultiplayer.h" +#include "XPMPMultiplayerVars.h" +#include "XPMPPlaneRenderer.h" +#include "XPMPMultiplayerCSL.h" + +#include +#include +#include +#include + +#include "XPLMProcessing.h" +#include "XPLMPlanes.h" +#include "XPLMDisplay.h" +#include "XPLMPlugin.h" +#include "XPLMUtilities.h" + +#include "XOGLUtils.h" +#include "PlatformUtils.h" + +#include +#include +#include + +// This prints debug info on our process of loading Austin's planes. +#define DEBUG_MANUAL_LOADING 0 + + +/****************************************************************************** + + T H E T C A S H A C K + + The 1.0 SDK provides no way to add TCAS blips to a panel - we simply don't know + where on the panel to draw. The only way to get said blips is to manipulate + Austin's "9 planes" plane objects, which he refers to when drawing the moving + map. + + But how do we integrate this with our system, which relies on us doing + the drawing (either by calling Austin's low level drawing routine or just + doing it ourselves with OpenGL)? + + The answer is the TCAS hack. Basically we set Austin's number of multiplayer + planes to zero while 3-d drawing is happening so he doesn't draw. Then during + 2-d drawing we pop this number back up to the number of planes that are + visible on TCAS and set the datarefs to move them, so that they appear on TCAS. + + One note: since all TCAS blips are the same, we do no model matching for + TCAS - we just place the first 9 planes at the right place. + + Our rendering loop records for us in gEnableCount how many TCAS planes should + be visible. + + ******************************************************************************/ + + + + + +static XPMPPlanePtr XPMPPlaneIsValid( + XPMPPlaneID inID, + XPMPPlaneVector::iterator * outIter); + +// This drawing hook is called once per frame to do the real drawing. +static int XPMPRenderMultiplayerPlanes( + XPLMDrawingPhase inPhase, + int inIsBefore, + void * inRefcon); + +// This drawing hook is called twice per frame to control how many planes +// should be visible. +static int XPMPControlPlaneCount( + XPLMDrawingPhase inPhase, + int inIsBefore, + void * inRefcon); + + + + +/******************************************************************************** + * SETUP + ********************************************************************************/ + + +const char * XPMPMultiplayerInit( + const char * inCSLFolder, const char * inRelatedPath, + const char * inTexturePath, const char * inDoc8643, + const char * inDefaultPlane, + int (* inIntPrefsFunc)(const char *, const char *, int), + float (* inFloatPrefsFunc)(const char *, const char *, float)) +{ + gDefaultPlane = inDefaultPlane; + gIntPrefsFunc = inIntPrefsFunc; + gFloatPrefsFunc = inFloatPrefsFunc; + char myPath[1024]; + char airPath[1024]; + char line[256]; + char sysPath[1024]; + FILE * fi; + + bool problem = false; + +// TODO - FORM GOOD DIAGNOSTIC MESSAGES HERE! + + // Initialize our OpenGL Utilities + OGL_UtilsInit(); + + if (!CSL_LoadCSL(inCSLFolder, inRelatedPath, inDoc8643)) + problem = true; + + XPMPInitDefaultPlaneRenderer(); + + if (!CSL_Init(inTexturePath)) + problem = true; + + // Register the plane control calls. + XPLMRegisterDrawCallback(XPMPControlPlaneCount, + xplm_Phase_Gauges, 0, /* after*/ 0 /* hide planes*/); + + XPLMRegisterDrawCallback(XPMPControlPlaneCount, + xplm_Phase_Gauges, 1, /* before */ (void *) -1 /* show planes*/); + + // Register the actual drawing func. + XPLMRegisterDrawCallback(XPMPRenderMultiplayerPlanes, + xplm_Phase_Airplanes, 0, /* after*/ 0 /* refcon */); + + if (problem) return "There were problems initializing XSquawkBox. Please examine X-Plane's error.out file for detailed information."; + else return ""; +} + + +// We use this array to track Austin's planes, since we have to mess with them. +static vector gPlanePaths; + +const char * XPMPMultiplayerEnable(void) +{ + // First build up a list of all of Austin's planes, and assign + // their effective index numbers. + gPlanePaths.clear(); + std::vector ptrs; + gPlanePaths.push_back(""); + + for (int p = 0; p < gPackages.size(); ++p) + { + for (int pp = 0; pp < gPackages[p].planes.size(); ++pp) + { + if (gPackages[p].planes[pp].plane_type == plane_Austin) + { + gPackages[p].planes[pp].austin_idx = gPlanePaths.size(); + char buf[1024]; + strcpy(buf,gPackages[p].planes[pp].file_path.c_str()); + #if APL + Posix2HFSPath(buf,buf,1024); + #endif + gPlanePaths.push_back(buf); + } + } + } + + // Copy the list into something that's not permanent, but is needed by the XPLM. + for (int n = 0; n < gPlanePaths.size(); ++n) + { +#if DEBUG_MANUAL_LOADING + char strbuf[1024]; + sprintf(strbuf, "Plane %d = '%s'\n", n, gPlanePaths[n].c_str()); + XPLMDebugString(strbuf); +#endif + ptrs.push_back((char *) gPlanePaths[n].c_str()); + } + ptrs.push_back(NULL); + + + // Attempt to grab multiplayer planes, then analyze. + int result = XPLMAcquirePlanes(&(*ptrs.begin()), NULL, NULL); + if (result) + XPLMSetActiveAircraftCount(1); + else + XPLMDebugString("WARNING: XSquawkBox did not acquire multiplayer planes!!\n"); + + int total, active; + XPLMPluginID who; + + XPLMCountAircraft(&total, &active, &who); + if (result == 0) + { + return "XSquawkBox was not able to start up multiplayer visuals because another plugin is controlling aircraft."; + } else + return ""; +} + + +// This routine checks plane loading and grabs anyone we're missing. +void XPMPLoadPlanesIfNecessary(void) +{ + int active, models; + XPLMPluginID owner; + XPLMCountAircraft(&models, &active, &owner); + if (owner != XPLMGetMyID()) + return; + + if (models > gPlanePaths.size()) + models = gPlanePaths.size(); + for (int n = 1; n < models; ++n) + { + if (!gPlanePaths[n].empty()) + { + const char * ourPath = gPlanePaths[n].c_str(); + char realPath[512]; + char fileName[256]; + XPLMGetNthAircraftModel(n, fileName, realPath); + if (strcmp(ourPath, realPath)) + { +#if DEBUG_MANUAL_LOADING + XPLMDebugString("Manually Loading plane: "); + XPLMDebugString(ourPath); + XPLMDebugString("\n"); +#endif + XPLMSetAircraftModel(n, ourPath); + } + } + } + +} + +/******************************************************************************** + * PLANE OBJECT SUPPORT + ********************************************************************************/ + +XPMPPlaneID XPMPCreatePlane( + const char * inICAOCode, + const char * inAirline, + const char * inLivery, + XPMPPlaneData_f inDataFunc, + void * inRefcon) +{ + XPMPPlanePtr plane = new XPMPPlane_t; + plane->icao = inICAOCode; + plane->livery = inLivery; + plane->airline = inAirline; + plane->dataFunc = inDataFunc; + plane->ref = inRefcon; + plane->model = CSL_MatchPlane(inICAOCode, inAirline, inLivery, &plane->good_livery, true); + + plane->pos.size = sizeof(plane->pos); + plane->surface.size = sizeof(plane->surface); + plane->radar.size = sizeof(plane->radar); + plane->posAge = plane->radarAge = plane->surfaceAge = -1; + + gPlanes.push_back(plane); + + for (XPMPPlaneNotifierVector::iterator iter = gObservers.begin(); iter != + gObservers.end(); ++iter) + { + iter->first.first(plane, xpmp_PlaneNotification_Created, iter->first.second); + } + return plane; +} + +void XPMPDestroyPlane(XPMPPlaneID inID) +{ + XPMPPlaneVector::iterator iter; + XPMPPlanePtr plane = XPMPPlaneIsValid(inID, &iter); + if (plane == NULL) + return; + + for (XPMPPlaneNotifierVector::iterator iter2 = gObservers.begin(); iter2 != + gObservers.end(); ++iter2) + { + iter2->first.first(plane, xpmp_PlaneNotification_Destroyed, iter2->first.second); + } + gPlanes.erase(iter); + + delete plane; +} + +void XPMPChangePlaneModel( + XPMPPlaneID inPlaneID, + const char * inICAOCode, + const char * inAirline, + const char * inLivery) +{ + XPMPPlanePtr plane = XPMPPlaneIsValid(inPlaneID, NULL); + if (plane) + { + plane->icao = inICAOCode; + plane->airline = inAirline; + plane->livery = inLivery; + plane->model = CSL_MatchPlane(inICAOCode, inAirline, inLivery, &plane->good_livery, true); + + } + + for (XPMPPlaneNotifierVector::iterator iter2 = gObservers.begin(); iter2 != + gObservers.end(); ++iter2) + { + iter2->first.first(plane, xpmp_PlaneNotification_ModelChanged, iter2->first.second); + } + +} + +void XPMPSetDefaultPlaneICAO( + const char * inICAO) +{ + gDefaultPlane = inICAO; +} + +long XPMPCountPlanes(void) +{ + return gPlanes.size(); +} + +XPMPPlaneID XPMPGetNthPlane( + long index) +{ + if ((index < 0) || (index >= gPlanes.size())) + return NULL; + + return gPlanes[index]; +} + + +void XPMPGetPlaneICAOAndLivery( + XPMPPlaneID inPlane, + char * outICAOCode, // Can be NULL + char * outLivery) +{ + XPMPPlanePtr plane = XPMPPlaneIsValid(inPlane, NULL); + if (plane == NULL) + return; + + if (outICAOCode) + strcpy(outICAOCode,plane->icao.c_str()); + if (outLivery) + strcpy(outLivery,plane->livery.c_str()); +} + +void XPMPRegisterPlaneNotifierFunc( + XPMPPlaneNotifier_f inFunc, + void * inRefcon) +{ + gObservers.push_back(XPMPPlaneNotifierTripple(XPMPPlaneNotifierPair(inFunc, inRefcon), XPLMGetMyID())); +} + +void XPMPUnregisterPlaneNotifierFunc( + XPMPPlaneNotifier_f inFunc, + void * inRefcon) +{ + XPMPPlaneNotifierVector::iterator iter = std::find( + gObservers.begin(), gObservers.end(), XPMPPlaneNotifierTripple(XPMPPlaneNotifierPair(inFunc, inRefcon), XPLMGetMyID())); + if (iter != gObservers.end()) + gObservers.erase(iter); +} + +int XPMPGetPlaneData( + XPMPPlaneID inPlane, + XPMPPlaneDataType inDataType, + void * outData) +{ + XPMPPlanePtr plane = XPMPPlaneIsValid(inPlane, NULL); + if (plane == NULL) + return -1; + + int now = XPLMGetCycleNumber(); + + switch(inDataType) { + case xpmpDataType_Position: + { + if (plane->posAge != now) + { + XPMPPlaneCallbackResult result = + plane->dataFunc(plane, inDataType, &plane->pos, plane->ref); + if (result == xpmpData_NewData) + plane->posAge = now; + } + + XPMPPlanePosition_t * posD = (XPMPPlanePosition_t *) outData; + memcpy(posD, &plane->pos, XPMP_TMIN(posD->size, plane->pos.size)); + + return plane->posAge; + } + case xpmpDataType_Surfaces: + { + if (plane->surfaceAge != now) + { + XPMPPlaneCallbackResult result = + plane->dataFunc(plane, inDataType, &plane->surface, plane->ref); + if (result == xpmpData_NewData) + plane->surfaceAge = now; + } + + XPMPPlaneSurfaces_t * surfD = (XPMPPlaneSurfaces_t *) outData; + memcpy(surfD, &plane->surface, XPMP_TMIN(surfD->size, plane->surface.size)); + return plane->surfaceAge; + } + case xpmpDataType_Radar: + { + if (plane->radarAge != now) + { + XPMPPlaneCallbackResult result = + plane->dataFunc(plane, inDataType, &plane->radar, plane->ref); + if (result == xpmpData_NewData) + plane->radarAge = now; + } + + XPMPPlaneRadar_t * radD = (XPMPPlaneRadar_t *) outData; + memcpy(radD, &plane->radar, XPMP_TMIN(radD->size, plane->radar.size)); + return plane->radarAge; + } + } + return -1; +} + +XPMPPlanePtr XPMPPlaneIsValid(XPMPPlaneID inID, XPMPPlaneVector::iterator * outIter) +{ + XPMPPlanePtr ptr = (XPMPPlanePtr) inID; + XPMPPlaneVector::iterator iter = std::find(gPlanes.begin(), gPlanes.end(), ptr); + if (iter == gPlanes.end()) + return NULL; + if (outIter) + *outIter = iter; + return ptr; +} + +void XPMPSetPlaneRenderer( + XPMPRenderPlanes_f inRenderer, + void * inRef) +{ + gRenderer = inRenderer; + gRendererRef = inRef; +} + +/******************************************************************************** + * RENDERING + ********************************************************************************/ + +// This callback ping-pongs the multiplayer count up and back depending +// on whether we're drawing the TCAS gauges or not. +int XPMPControlPlaneCount( + XPLMDrawingPhase inPhase, + int inIsBefore, + void * inRefcon) +{ + if (inRefcon == NULL) + { + XPLMSetActiveAircraftCount(1); + } else { + XPLMSetActiveAircraftCount(gEnableCount); + } + return 1; +} + + +// This routine draws the actual planes. +int XPMPRenderMultiplayerPlanes( + XPLMDrawingPhase inPhase, + int inIsBefore, + void * inRefcon) +{ + if (gRenderer) + gRenderer(gRendererRef); + else + XPMPDefaultPlaneRenderer(); +#if XTWR // We don't want to see our own plane! + return 0; +#else + return 1; +#endif +} + +bool XPMPIsICAOValid( + const char * inICAO) + { + return CSL_MatchPlane(inICAO, "", "", NULL, false) != NULL; + } + +void XPMPDumpOneCycle(void) +{ + CSL_Dump(); + gDumpOneRenderCycle = true; +} diff --git a/src/XPMPMultiplayerCSL.cpp b/src/XPMPMultiplayerCSL.cpp new file mode 100644 index 000000000..76b8d548e --- /dev/null +++ b/src/XPMPMultiplayerCSL.cpp @@ -0,0 +1,957 @@ +/* + * Copyright (c) 2005, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XPMPMultiplayerCSL.h" +#include "XPLMUtilities.h" +#include "XPMPMultiplayerObj.h" +#include "XOGLUtils.h" +#include +#include +#include "PlatformUtils.h" + +using std::max; + +#if APL +#include +#endif + +// Set this to 1 to get TONS of diagnostics on what the lib is doing. +#define DEBUG_CSL_LOADING 0 + +// Set this to 1 to cause AIRLINE and LIVERY to create ICAO codes automatically +#define USE_DEFAULTING 0 + +enum { + pass_Depend, + pass_Load, + pass_Count +}; + +/************************************************************************ + * UTILITY ROUTINES + ************************************************************************/ + +static void MakePartialPathNativeObj(string& io_str) +{ + vector chars(io_str.begin(),io_str.end()); + MakePartialPathNative(&*chars.begin(),&*chars.begin()+chars.size()); + io_str=string(chars.begin(),chars.end()); +} + +struct XPLMDump { + XPLMDump() { } + + XPLMDump(const string& inFileName, int lineNum, const char * line) { + XPLMDebugString("XSB WARNING: Parse Error in file "); + XPLMDebugString(inFileName.c_str()); + XPLMDebugString(" line "); + char buf[32]; + sprintf(buf,"%d", lineNum); + XPLMDebugString(buf); + XPLMDebugString(".\n "); + XPLMDebugString(line); + XPLMDebugString(".\n"); + } + + XPLMDump& operator<<(const char * rhs) { + XPLMDebugString(rhs); + return *this; + } + XPLMDump& operator<<(const std::string& rhs) { + XPLMDebugString(rhs.c_str()); + return *this; + } + XPLMDump& operator<<(int n) { + char buf[255]; + sprintf(buf, "%d", n); + XPLMDebugString(buf); + return *this; + } +}; + + +static char * fgets_multiplatform(char * s, int n, FILE * file); +static void BreakStringPvt(const char * inString, std::vector& outStrings, int maxBreak, const std::string& inSeparators); +static bool DoPackageSub(std::string& ioPath); + +bool DoPackageSub(std::string& ioPath) +{ + for (std::map::iterator i = gPackageNames.begin(); i != gPackageNames.end(); ++i) + { + if (strncmp(i->first.c_str(), ioPath.c_str(), i->first.size()) == 0) + { + ioPath.erase(0, i->first.size()); + ioPath.insert(0, i->second); + return true; + } + } + return false; +} + + +// This routine gets one line, but handles any platforms crlf setup. +char * fgets_multiplatform(char * s, int n, FILE * file) +{ + char * p = s; + int c; + int c1; + + // Save one slot for the null. If we do not have enough memory + // to do this, bail. + if (--n < 0) + return(NULL); + + // Only bother to read if we have enough space in the char buf. + if (n) + do + { + c = getc(file); + + // EOF: this could mean I/O error or end of file. + if (c == EOF) + if (feof(file) && p != s) // We read something and now the file's done, ok. + break; + else + { + // Haven't read yet? I/O error? Return NULL! + return(NULL); + } + + *p++ = c; + } + // Stop when we see either newline char or the buffer is full. + // Note that the \r\n IS written to the line. + while (c != '\n' && c != '\r' && --n); + + // Ben's special code: eat a \n if it follows a \r, etc. Mac stdio + // swizzles these guys a bit, so we will consolidate BOTH \r\n and \n\r into + // just the first. + if (c == '\r') + { + c1 = getc(file); + if (c1 != '\n') ungetc(c1, file); + } + if (c == '\n') + { + c1 = getc(file); + if (c1 != '\r') ungetc(c1, file); + } + + // Unless we're bailing with NULL, we MUST null terminate. + *p = 0; + + return(s); +} + +// This routine breaks a line into one or more tokens based on delimitors. +void BreakStringPvt(const char * inString, std::vector& outStrings, + int maxBreak, const std::string& inSeparators) +{ + outStrings.clear(); + + const char * endPos = inString + strlen(inString); + const char * iter = inString; + while (iter < endPos) + { + while ((iter < endPos) && (inSeparators.find(*iter) != std::string::npos)) + ++iter; + if (iter < endPos) + { + if (maxBreak && (maxBreak == (outStrings.size()+1))) + { + outStrings.push_back(std::string(iter, endPos)); + return; + } + const char * wordEnd = iter; + while ((wordEnd < endPos) && (inSeparators.find(*wordEnd) == std::string::npos)) + ++wordEnd; + + outStrings.push_back(std::string(iter, wordEnd)); + + iter = wordEnd; + } + } +} + + +/************************************************************************ + * CSL LOADING + ************************************************************************/ + +static bool LoadOnePackage(const string& inPath, int pass); + +bool CSL_Init( + const char* inTexturePath) +{ + bool ok = OBJ_Init(inTexturePath); + if (!ok) + XPLMDump() << "XSB WARNING: we failed to find XSB's custom lighting texture at " << inTexturePath << ".\n"; + return ok; +} + +// This routine loads one CSL package. +bool LoadOnePackage(const string& inPath, int pass) +{ + string group, icao, livery, airline; + bool parse_err = false; + char line[1024*4]; + int sim, xplm; + XPLMHostApplicationID host; + + // First locate and attempt to load the xsb_aircraft.txt file from th is package. + string path(inPath); + path += (DIR_STR "xsb_aircraft.txt"); + FILE * fi = fopen(path.c_str(), "r"); + + XPLMGetVersions(&sim, &xplm, &host); + int lineNum = 0; + + if (fi != NULL) + { + if (pass == pass_Load) + XPLMDump() << "XSB: Loading package: " << path << "\n"; + + if (pass == pass_Load) + gPackages.push_back(CSLPackage_t()); + CSLPackage_t * pckg = (pass == pass_Load) ? &gPackages.back() : NULL; + if (pass == pass_Load) + pckg->name = path; + + std::vector tokens; + + // BEN SEZ: we need to understand why thsi hack would be needed! + // I dont know why - but this seems to fix a Linux STL issue, somehow -Martin +// tokens.push_back(""); +// tokens.push_back(""); +// tokens.push_back(""); +// tokens.push_back(""); +// tokens.push_back(""); + + // Go through the file and handle each token. + while(!feof(fi)) + { + if (!fgets_multiplatform(line, sizeof(line), fi)) + break; + ++lineNum; + + if (line[0] == '#') continue; + + char * p = line; + while (*p) + { + if (*p == '\n' || *p == '\r') *p = 0; + ++p; + } + + BreakStringPvt(line, tokens, 4, " \t\r\n"); + + // EXPORT_NAME + if (!tokens.empty() && tokens[0] == "EXPORT_NAME" && pass == pass_Depend) + { + if (tokens.size() == 2) + { + if (gPackageNames.count(tokens[1]) == 0) + { + gPackageNames[tokens[1]] = inPath; + } else { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: Package name " << tokens[1].c_str() << " already in use by "<< gPackageNames[tokens[1]].c_str() << " reqested by use by " << inPath.c_str() << "'\n"; + } + } else { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: EXPORT_NAME command requires 1 argument.\n"; + } + } + + + // DEPENDENCY + if (!tokens.empty() && tokens[0] == "DEPENDENCY" && pass == pass_Load) + { + if (tokens.size() == 2) + { + if (gPackageNames.count(tokens[1]) == 0) + { + XPLMDump(path, lineNum, line) << "XSB WARNING: required package " << tokens[1] << " not found. Aborting processing of this package.\n"; + fclose(fi); + return true; + } + } else { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: DEPENDENCY command needs 1 argument.\n"; + } + } + + + // AIRCAFT + if (!tokens.empty() && tokens[0] == "AIRCRAFT" && pass == pass_Load) + { + if (tokens.size() == 4) + { + if (sim >= atoi(tokens[1].c_str()) && + sim <= atoi(tokens[2].c_str())) + { + std::string fullPath = tokens[3]; + MakePartialPathNativeObj(fullPath); + if (!DoPackageSub(fullPath)) + { + XPLMDump(path, lineNum, line) << "XSB WARNING: package not found.\n"; + parse_err = true; + } + pckg->planes.push_back(CSLPlane_t()); + pckg->planes.back().plane_type = plane_Austin; + pckg->planes.back().file_path = fullPath; + pckg->planes.back().moving_gear = true; + pckg->planes.back().austin_idx = -1; +#if DEBUG_CSL_LOADING + XPLMDebugString(" Got Airplane: "); + XPLMDebugString(fullPath.c_str()); + XPLMDebugString("\n"); +#endif + + } + } else { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: AIRCRAFT command takes 3 arguments.\n"; + } + } + + // OBJECT + if (!tokens.empty() && tokens[0] == "OBJECT" && pass == pass_Load) + { + BreakStringPvt(line, tokens, 2, " \t\r\n"); + if (tokens.size() == 2) + { + std::string fullPath = tokens[1]; + MakePartialPathNativeObj(fullPath); + if (!DoPackageSub(fullPath)) + { + XPLMDump(path, lineNum, line) << "XSB WARNING: package not found.\n"; + parse_err = true; + } + pckg->planes.push_back(CSLPlane_t()); + pckg->planes.back().plane_type = plane_Obj; + pckg->planes.back().file_path = fullPath; + pckg->planes.back().moving_gear = true; + pckg->planes.back().texID = 0; + pckg->planes.back().texLitID = 0; + pckg->planes.back().obj_idx = OBJ_LoadModel(fullPath.c_str()); + if (pckg->planes.back().obj_idx == -1) + { + XPLMDump(path, lineNum, line) << "XSB WARNING: the model " << fullPath << " failed to load.\n"; + parse_err = true; + } +#if DEBUG_CSL_LOADING + XPLMDebugString(" Got Object: "); + XPLMDebugString(fullPath.c_str()); + XPLMDebugString("\n"); +#endif + } else { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: OBJECT command takes 1 argument.\n"; + } + } + + + // TEXTURE + if (!tokens.empty() && tokens[0] == "TEXTURE" && pass == pass_Load) + { + if(tokens.size() != 2) + { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: TEXTURE command takes 1 argument.\n"; + } else { + // Load regular texture + string texPath = tokens[1]; + MakePartialPathNativeObj(texPath); + + if (!DoPackageSub(texPath)) + { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: package not found.\n"; + } + pckg->planes.back().texID = OBJ_LoadTexture(texPath.c_str(), false); + if (pckg->planes.back().texID == -1) + { + parse_err = true; + XPLMDump(path, lineNum, line) << "Texture " << texPath << " failed to load.\n"; + } + // Load the lit texture + string texLitPath = texPath; + string::size_type pos2 = texLitPath.find_last_of("."); + if(pos2 != string::npos) + { + texLitPath.insert(pos2, "LIT"); + pckg->planes.back().texLitID = OBJ_LoadTexture(texLitPath.c_str(), false); + } + } + } + + // HASGEAR YES|NO + // This line specifies whether the previous plane has retractable gear. + // Useful for preventing XSB from rolling up a C152's gear on takeoff! + if (!tokens.empty() && tokens[0] == "HASGEAR" && pass == pass_Load) + { + if (tokens.size() != 2 || (tokens[1] != "YES" && tokens[1] != "NO")) + { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: HASGEAR takes one argument that must be YES or NO.\n"; + } else { + if (tokens[1] == "YES") + pckg->planes.back().moving_gear = true; + else if (tokens[1] == "NO") + pckg->planes.back().moving_gear = false; + else { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: HASGEAR must have a YES or NO argument, but we got " << tokens[1] << ".\n"; + } + } + } + + // ICAO + // This line maps one ICAO code to the previous airline, without + // specifying an airline or livery. + if (!tokens.empty() && tokens[0] == "ICAO" && pass == pass_Load) + { + BreakStringPvt(line, tokens, 0, " \t"); + if (tokens.size() == 2) + { + icao = tokens[1]; + group = gGroupings[icao]; + if (pckg->matches[match_icao].count(icao) == 0) + pckg->matches[match_icao] [icao] = pckg->planes.size() - 1; + if (!group.empty()) + if (pckg->matches[match_group].count(group) == 0) + pckg->matches[match_group] [group] = pckg->planes.size() - 1; + } else { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: ICAO command takes 1 argument.\n"; + } + } + + // AIRLINE + // This line maps one ICAO code to the previous airline, with + // an airline but without a livery. This will also create + // an ICAO-only association for non-airline-specific matching. + if (!tokens.empty() && tokens[0] == "AIRLINE" && pass == pass_Load) + { + BreakStringPvt(line, tokens, 0, " \t"); + if (tokens.size() == 3) + { + icao = tokens[1]; + airline = tokens[2]; + group = gGroupings[icao]; + if (pckg->matches[match_icao_airline].count(icao + " " + airline) == 0) + pckg->matches[match_icao_airline] [icao + " " + airline] = pckg->planes.size() - 1; +#if USE_DEFAULTING + if (pckg->matches[match_icao ].count(icao ) == 0) + pckg->matches[match_icao ] [icao ] = pckg->planes.size() - 1; +#endif + if (!group.empty()) + { +#if USE_DEFAULTING + if (pckg->matches[match_group ].count(group ) == 0) + pckg->matches[match_group ] [group ] = pckg->planes.size() - 1; +#endif + if (pckg->matches[match_group_airline].count(group + " " + airline) == 0) + pckg->matches[match_group_airline] [group + " " + airline] = pckg->planes.size() - 1; + } + } else { + parse_err = true; + XPLMDump(path, lineNum, line) << "XB WARNING: AIRLINE command takes two arguments.\n"; + } + } + + // LIVERY + // This line maps one ICAO code to the previous airline, with + // an airline and livery. This will also create + // an ICAO-only and ICAO/airline association for non-airline-specific + // matching. + if (!tokens.empty() && tokens[0] == "LIVERY" && pass == pass_Load) + { + BreakStringPvt(line, tokens, 0, " \t"); + if (tokens.size() == 4) + { + icao = tokens[1]; + airline = tokens[2]; + livery = tokens[3]; + group = gGroupings[icao]; +#if USE_DEFAULTING + if (pckg->matches[match_icao ].count(icao ) == 0) + pckg->matches[match_icao ] [icao ] = pckg->planes.size() - 1; + if (pckg->matches[match_icao ].count(icao ) == 0) + pckg->matches[match_icao_airline ] [icao + " " + airline ] = pckg->planes.size() - 1; +#endif + if (pckg->matches[match_icao_airline_livery ].count(icao + " " + airline + " " + livery) == 0) + pckg->matches[match_icao_airline_livery ] [icao + " " + airline + " " + livery] = pckg->planes.size() - 1; + if (!group.empty()) + { +#if USE_DEFAULTING + if (pckg->matches[match_group ].count(group ) == 0) + pckg->matches[match_group ] [group ] = pckg->planes.size() - 1; + if (pckg->matches[match_group_airline ].count(group + " " + airline ) == 0) + pckg->matches[match_group_airline ] [group + " " + airline ] = pckg->planes.size() - 1; +#endif + if (pckg->matches[match_group_airline_livery ].count(group + " " + airline + " " + livery) == 0) + pckg->matches[match_group_airline_livery ] [group + " " + airline + " " + livery] = pckg->planes.size() - 1; + } + } else { + parse_err = true; + XPLMDump(path, lineNum, line) << "XSB WARNING: LIVERY command takes two arguments.\n"; + } + } + } + fclose(fi); + } else { + XPLMDump() << "XSB WARNING: package '" << inPath << "' could not be opened.\n"; + } + return parse_err; +} + +// This routine loads the related.txt file and also all packages. +bool CSL_LoadCSL(const char * inFolderPath, const char * inRelatedFile, const char * inDoc8643) +{ + bool ok = true; + + // read the list of aircraft codes + FILE * aircraft_fi = fopen(inDoc8643, "r"); + + if (gIntPrefsFunc("debug", "model_matching", 0)) + XPLMDebugString(string(string(inDoc8643) + " returned " + (aircraft_fi ? "valid" : "invalid") + " fp\n").c_str()); + + if (aircraft_fi) + { + char buf[1024]; + while (fgets_multiplatform(buf, sizeof(buf), aircraft_fi)) + { + vector tokens; + BreakStringPvt(buf, tokens, 0, "\t\r\n"); + + /* + if (gIntPrefsFunc("debug", "model_matching", 0)) { + char str[20]; + sprintf(str, "size: %i", tokens.size()); + string s = string(str) + string(": ") + buf; + XPLMDebugString(s.c_str()); + } + */ + + // Sample line. Fields are separated by tabs + // ABHCO SA-342 Gazelle GAZL H1T - + + if(tokens.size() < 5) continue; + CSLAircraftCode_t entry; + entry.icao = tokens[2]; + entry.equip = tokens[3]; + entry.category = tokens[4][0]; + + // Debugging stuff + /* + if (gIntPrefsFunc("debug", "model_matching", 0)) { + XPLMDebugString("Loaded entry: icao code "); + XPLMDebugString(entry.icao.c_str()); + XPLMDebugString(" equipment "); + XPLMDebugString(entry.equip.c_str()); + XPLMDebugString(" category "); + switch(entry.category) { + case 'L': XPLMDebugString(" light"); break; + case 'M': XPLMDebugString(" medium"); break; + case 'H': XPLMDebugString(" heavy"); break; + default: XPLMDebugString(" other"); break; + } + XPLMDebugString("\n"); + } + */ + + gAircraftCodes[entry.icao] = entry; + } + fclose(aircraft_fi); + } else { + XPLMDump() << "XSB WARNING: could not open ICAO document 8643 at " << inDoc8643 << "\n"; + ok = false; + } + + // First grab the related.txt file. + FILE * related_fi = fopen(inRelatedFile, "r"); + if (related_fi) + { + char buf[1024]; + while (fgets_multiplatform(buf, sizeof(buf), related_fi)) + { + if (buf[0] != ';') + { + vector tokens; + BreakStringPvt(buf, tokens, 0, " \t\r\n"); + string group; + for (int n = 0; n < tokens.size(); ++n) + { + if (n != 0) group += " "; + group += tokens[n]; + } + for (int n = 0; n < tokens.size(); ++n) + { + gGroupings[tokens[n]] = group; + } + } + } + fclose(related_fi); + } else { + XPLMDump() << "XSB WARNING: could not open related.txt at " << inRelatedFile << "\n"; + ok = false; + } + + // Iterate through all directories using the XPLM and load them. + + char * name_buf = (char *) malloc(16384); + char ** index_buf = (char **) malloc(65536); + long total, ret; + + char folder[1024]; + +#if APL + Posix2HFSPath(inFolderPath, folder, sizeof(folder)); +#else + strcpy(folder,inFolderPath); +#endif + XPLMGetDirectoryContents(folder, 0, name_buf, 16384, index_buf, 65536 / sizeof(char*), + &total, &ret); + + vector pckgs; + for (int r = 0; r < ret; ++r) + { +#if APL + if (index_buf[r][0] == '.') + continue; +#endif + char * foo = index_buf[r]; + string path(inFolderPath); + path += DIR_STR; + path += foo; + pckgs.push_back(path); + } + free(name_buf); + free(index_buf); + + for (int pass = 0; pass < pass_Count; ++pass) + for (int n = 0; n < pckgs.size(); ++n) + { + if (LoadOnePackage(pckgs[n], pass)) + ok = false; + } + +#if 0 + ::Microseconds((UnsignedWide*) &t2); + double delta = (t2 - t1); + delta /= 1000000.0; + char buf[256]; + sprintf(buf,"CSL full load took: %lf\n", delta); + XPLMDebugString(buf); +#endif + return ok; +} + +/************************************************************************ + * CSL MATCHING + ************************************************************************/ + + // Here's the basic idea: there are six levels of matching we can get, + // from the best (direct match of ICAO, airline and livery) to the worst + // (match an airplane's ICAO group but not ICAO, no livery or airline). + // So we will make six passes from best to worst, trying to match. For + // each pass we try each package in turn from highest to lowest priority. + +// These structs tell us how to build the matching keys for a given pass. +static int kUseICAO[] = { 1, 1, 0, 0, 1, 0 }; +static int kUseLivery[] = { 1, 0, 1, 0, 0, 0 }; +static int kUseAirline[] = { 0, 1, 0, 1, 0, 0 }; + +CSLPlane_t * CSL_MatchPlane(const char * inICAO, const char * inAirline, const char * inLivery, bool * got_livery, bool use_default) +{ + XPLMPluginID who; + int total, active; + XPLMCountAircraft(&total, &active, &who); + + // First build up our various keys and info we need to do the match. + string icao(inICAO); + string airline(inAirline ? inAirline : ""); + string livery(inLivery ? inLivery : ""); + string group; + string key; + + map::iterator group_iter = gGroupings.find(inICAO); + if (group_iter != gGroupings.end()) + group = group_iter->second; + + char buf[4096]; + + if (gIntPrefsFunc("debug", "model_matching", 0)) + { + sprintf(buf,"XSB MATCH - ICAO=%s AIRLINE=%s LIVERY=%s GROUP=%s\n", icao.c_str(), airline.c_str(), livery.c_str(), group.c_str()); + XPLMDebugString(buf); + } + + // Now we go through our six passes. + for (int n = 0; n < match_count; ++n) + { + // Build up the right key for this pass. + key = kUseICAO[n] ? icao : group; + if (kUseLivery[n]) + { + key += " "; + key += airline; + key += " "; + key += livery; + } + if (kUseAirline[n]) + { + key += " "; + key += airline; + } + + if (gIntPrefsFunc("debug", "model_matching", 0)) + { + sprintf(buf,"XSB MATCH - Group %d key %s\n", n, key.c_str()); + XPLMDebugString(buf); + } + + // Now go through each group and see if we match. + for (int p = 0; p < gPackages.size(); ++p) + { + map::iterator iter = gPackages[p].matches[n].find(key); + if (iter != gPackages[p].matches[n].end()) + if (gPackages[p].planes[iter->second].plane_type != plane_Austin || // Special check - do NOT match a plane that isn't loaded. + (gPackages[p].planes[iter->second].austin_idx != -1 && gPackages[p].planes[iter->second].austin_idx < total)) + if (gPackages[p].planes[iter->second].plane_type != plane_Obj || + gPackages[p].planes[iter->second].obj_idx != -1) + { + if (got_livery) *got_livery = (kUseLivery[n] || kUseAirline[n]); + + if (gIntPrefsFunc("debug", "model_matching", 0)) + { + sprintf(buf, "XB MATCH - Found: %s\n", gPackages[p].planes[iter->second].file_path.c_str()); + XPLMDebugString(buf); + } + + return &gPackages[p].planes[iter->second]; + } + } + } + + if (gIntPrefsFunc("debug", "model_matching", 0)) + { + XPLMDebugString("XSB MATCH - No match.\n"); + } + + + + // try the next step: + // For each aircraft, we know the equiment type "L2T" and the WTC category. + // try to find a model that has the same equipment type and WTC + + std::map::const_iterator model_it = gAircraftCodes.find(icao); + if(model_it != gAircraftCodes.end()) { + + if (gIntPrefsFunc("debug", "model_matching", 0)) + { + XPLMDebugString("XSB MATCH/acf - Looking for a "); + switch(model_it->second.category) { + case 'L': XPLMDebugString(" light "); break; + case 'M': XPLMDebugString(" medium "); break; + case 'H': XPLMDebugString(" heavy "); break; + default: XPLMDebugString(" funny "); break; + } + XPLMDebugString(model_it->second.equip.c_str()); + XPLMDebugString(" aircraft\n"); + } + + // 1. match WTC, full configuration ("L2P") + // 2. match WTC, #engines and enginetype ("2P") + // 3. match WTC, #egines ("2") + // 4. match WTC, enginetype ("P") + // 5. match WTC + for(int pass = 1; pass <= 5; ++pass) { + + if (gIntPrefsFunc("debug", "model_matching", 0)) + { + switch(pass) { + case 1: XPLMDebugString("XSB Match/acf - matching WTC and configuration\n"); break; + case 2: XPLMDebugString("XSB Match/acf - matching WTC, #engines and enginetype\n"); break; + case 3: XPLMDebugString("XSB Match/acf - matching WTC, #engines\n"); break; + case 4: XPLMDebugString("XSB Match/acf - matching WTC, enginetype\n"); break; + case 5: XPLMDebugString("XSB Match/acf - matching WTC\n"); break; + } + } + + for (int p = 0; p < gPackages.size(); ++p) + { + std::map::const_iterator it = gPackages[p].matches[4].begin(); + while(it != gPackages[p].matches[4].end()) { + + if (gPackages[p].planes[it->second].plane_type != plane_Austin || // Special check - do NOT match a plane that isn't loaded. + (gPackages[p].planes[it->second].austin_idx != -1 && gPackages[p].planes[it->second].austin_idx < total)) + if (gPackages[p].planes[it->second].plane_type != plane_Obj || + gPackages[p].planes[it->second].obj_idx != -1) + { + // we have a candidate, lets see if it matches our criteria + std::map::const_iterator m = gAircraftCodes.find(it->first); + if(m != gAircraftCodes.end()) { + // category + bool match = (m->second.category == model_it->second.category); + + // make sure we have a valid equip type if we need it + if(pass < 5 && m->second.equip.length() != 3) match = false; + + // engine type + if(match && (pass <= 2 || pass == 4)) + match = (m->second.equip[2] == model_it->second.equip[2]); + + // #engines + if(match && pass <= 3) + match = (m->second.equip[1] == model_it->second.equip[1]); + + // full configuration string + if(match && pass == 1) + match = (m->second.equip == model_it->second.equip); + + if(match) { + // bingo + if (gIntPrefsFunc("debug", "model_matching", 0)) + { + XPLMDebugString("XSB MATCH/acf - found: "); + XPLMDebugString(it->first.c_str()); + XPLMDebugString("\n"); + } + + return &gPackages[p].planes[it->second]; + } + } + } + + ++it; + } + } + } + } + + if (gIntPrefsFunc("debug", "model_matching", 0)) { + XPLMDebugString(string("gAircraftCodes.find(" + icao + ") returned no match.").c_str()); + } + + if (!strcmp(inICAO, gDefaultPlane.c_str())) return NULL; + if (!use_default) return NULL; + return CSL_MatchPlane(gDefaultPlane.c_str(), "", "", got_livery, false); +} + +void CSL_Dump(void) +{ + // DIAGNOSTICS - print out everything we know. + for (int n = 0; n < gPackages.size(); ++n) + { + XPLMDump() << "XSB CSL: Package " << n << " path = " << gPackages[n].name << "\n"; + for (int p = 0; p < gPackages[n].planes.size(); ++p) + { + XPLMDump() << "XSB CSL: Plane " << p << " = " << gPackages[n].planes[p].file_path << "\n"; + } + for (int t = 0; t < 6; ++t) + { + XPLMDump() << "XSB CSL: Table " << t << "\n"; + for (map::iterator i = gPackages[n].matches[t].begin(); i != gPackages[n].matches[t].end(); ++i) + { + XPLMDump() << "XSB CSL: " << i->first << " -> " << i->second << "\n"; + } + } + } +} + +/************************************************************************ + * CSL DRAWING + ************************************************************************/ + +int CSL_GetOGLIndex(CSLPlane_t * model) +{ + switch(model->plane_type) { + case plane_Austin: + return model->austin_idx; + case plane_Obj: + if (model->texID != 0) + return model->texID; + return OBJ_GetModelTexID(model->obj_idx); + default: + return 0; + } +} + +// Plane drawing couldn't be simpler - it's just a "switch" between all +// of our drawing techniques. +void CSL_DrawObject( + CSLPlane_t * model, + float distance, + double x, + double y, + double z, + double pitch, + double roll, + double heading, + int type, + int full, + xpmp_LightStatus lights, + XPLMPlaneDrawState_t * state) +{ + // Setup OpenGL for this plane render + if(type < plane_Count) + { + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glTranslatef(x, y, z); + glRotatef(heading, 0.0, -1.0, 0.0); + glRotatef(pitch, 01.0, 0.0, 0.0); + glRotatef(roll, 0.0, 0.0, -1.0); + } + + switch (type) + { + case plane_Austin: + { + XPLMPluginID who; + int total, active; + XPLMCountAircraft(&total, &active, &who); + if (model->austin_idx > 0 && model->austin_idx < active) + XPLMDrawAircraft(model->austin_idx, + x, y ,z, pitch, roll, heading, + full, state); + } + break; + case plane_Obj: + if (model->obj_idx != -1) + OBJ_PlotModel(model->obj_idx, model->texID, model->texLitID, full ? distance : max(distance, 10000.0f), + x, y ,z, pitch, roll, heading); + break; + case plane_Lights: + if (model->obj_idx != -1) + OBJ_DrawLights(model->obj_idx, distance, + x, y ,z, pitch, roll, heading, lights); + + break; + } + + glPopMatrix(); +} diff --git a/src/XPMPMultiplayerCSL.h b/src/XPMPMultiplayerCSL.h new file mode 100644 index 000000000..e9400b336 --- /dev/null +++ b/src/XPMPMultiplayerCSL.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2005, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef XPLMMULTIPLAYERCSL_H +#define XPLMMULTIPLAYERCSL_H + +/* + * XPLMMultiplayerCSL + * + * This unit is the master switch for managing aircraft models. It loads up all CSL packages and + * does the matching logic for finding aircraft. + * + */ + +#include "XPLMPlanes.h" +#include "XPMPMultiplayerVars.h" + +/* + * CSL_Init + * + * This routine Initializes the Multiplayer object section and sets up the lighting texture. + * + */ +bool CSL_Init( + const char* inTexturePath); +/* + * CSL_LoadCSL + * + * This routine loads all CSL packages and the related.txt file. + * + */ +bool CSL_LoadCSL( + const char * inFolderPath, // Path to CSL folder + const char * inRelated, // Path to related.txt - used by renderer for model matching + const char * inIcao8643); // Path to ICAO document 8643 (list of aircraft) + +/* + * CSL_MatchPlane + * + * Given an ICAO and optionally a livery and airline, this routine returns the best plane match, or + * NULL if there is no good plane match. If got_livery is not null, it is filled in with whether + * the match has a valid paint job or not. + * + */ +CSLPlane_t * CSL_MatchPlane(const char * inICAO, const char * inAirline, const char * inLivery, bool * got_livery, bool use_default); + +/* + * CSL_Dump + * + * This routine dumps the total state of the CSL system to the error.out file. + * + */ +void CSL_Dump(void); + +/* + * CSL_GetOGLIndex + * + * Given a model, this routine returns some kind of index number such that + * sorting all models by these indices gives the ideal OpenGL draw order. + * In other words, this index number sorts models by OGL state. + * + */ +int CSL_GetOGLIndex(CSLPlane_t * model); + +/* + * CSL_DrawObject + * + * Given a plane model rep and the params, this routine does the real drawing. The coordinate system must be pre-shifted + * to the plane's location. (This just dispatches to the appropriate drawing method). + * + */ +void CSL_DrawObject( + CSLPlane_t * model, + float distance, + double x, + double y, + double z, + double pitch, + double roll, + double heading, + int type, + int full, + xpmp_LightStatus lights, + XPLMPlaneDrawState_t * state); + + +#endif /* XPLMMULTIPLAYERCSL_H */ diff --git a/src/XPMPMultiplayerObj.cpp b/src/XPMPMultiplayerObj.cpp new file mode 100644 index 000000000..3d69aea2f --- /dev/null +++ b/src/XPMPMultiplayerObj.cpp @@ -0,0 +1,845 @@ +/* + * Copyright (c) 2005, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XPMPMultiplayerObj.h" +#include "XPMPMultiplayerVars.h" + +#include "PlatformUtils.h" +#include "XObjReadWrite.h" +#include "TexUtils.h" +#include "XOGLUtils.h" + +#include +#include +#include + +#include "XPLMGraphics.h" +#include "XPLMUtilities.h" +#include "XPLMDataAccess.h" +#include "XPLMProcessing.h" + +#define DEBUG_NORMALS 0 +#define DISABLE_SHARING 0 +#define BLEND_NORMALS 1 + +using namespace std; + +const double kMetersToNM = 0.000539956803; +// Some color constants +//const float kNavLightRed[] = {1.0, 0.0, 0.2, 0.6}; +//const float kNavLightGreen[] = {0.0, 1.0, 0.3, 0.6}; +//const float kLandingLight[] = {1.0, 1.0, 0.7, 0.6}; +//const float kStrobeLight[] = {1.0, 1.0, 1.0, 0.4}; +const float kNavLightRed[] = {1.0, 0.0, 0.2, 0.5}; +const float kNavLightGreen[] = {0.0, 1.0, 0.3, 0.5}; +const float kLandingLight[] = {1.0, 1.0, 0.7, 0.6}; +const float kStrobeLight[] = {1.0, 1.0, 1.0, 0.7}; + +static int sLightTexture = -1; + +static void MakePartialPathNativeObj(string& io_str) +{ + vector chars(io_str.begin(),io_str.end()); + MakePartialPathNative(&*chars.begin(),&*chars.begin()+chars.size()); + io_str=string(chars.begin(),chars.end()); +} + +static XPLMDataRef sFOVRef = XPLMFindDataRef("sim/graphics/view/field_of_view_deg"); +static float sFOV = 60.0; + +bool NormalizeVec(float vec[3]) +{ + float len=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]); + if (len>0.0) + { + len = 1.0 / len; + vec[0] *= len; + vec[1] *= len; + vec[2] *= len; + return true; + } + return false; +} + +void CrossVec(float a[3], float b[3], float dst[3]) +{ + dst[0] = a[1] * b[2] - a[2] * b[1] ; + dst[1] = a[2] * b[0] - a[0] * b[2] ; + dst[2] = a[0] * b[1] - a[1] * b[0] ; +} + + +/***************************************************** + Ben's Crazy Point Pool Class +******************************************************/ + +class OBJ_PointPool { +public: + OBJ_PointPool(){}; + ~OBJ_PointPool(){}; + + int AddPoint(float xyz[3], float st[2]); + void PreparePoolToDraw(); + void CalcTriNormal(int idx1, int idx2, int idx3); + void NormalizeNormals(void); + void DebugDrawNormals(); + void Purge() { mPointPool.clear(); } +private: + vector mPointPool; +}; + + + +// Adds a point to our pool and returns it's index. +// If one already exists in the same location, we +// just return that index +int OBJ_PointPool::AddPoint(float xyz[3], float st[2]) +{ +#if !DISABLE_SHARING + // Use x as the key...see if we can find it + for(int n = 0; n < mPointPool.size(); n += 8) + { + if((xyz[0] == mPointPool[n]) && + (xyz[1] == mPointPool[n+1]) && + (xyz[2] == mPointPool[n+2]) && + (st[0] == mPointPool[n+3]) && + (st[1] == mPointPool[n+4])) + return n/8; // Clients care about point # not array index + } +#endif + + // If we're here, no match was found so we add it to the pool + // Add XYZ + mPointPool.push_back(xyz[0]); mPointPool.push_back(xyz[1]); mPointPool.push_back(xyz[2]); + // Add ST + mPointPool.push_back(st[0]); mPointPool.push_back(st[1]); + // Allocate some space for the normal later + mPointPool.push_back(0.0); mPointPool.push_back(0.0); mPointPool.push_back(0.0); + return (mPointPool.size()/8)-1; +} + +// This function sets up OpenGL for our point pool +void OBJ_PointPool::PreparePoolToDraw() +{ + // Setup our triangle data (20 represents 5 elements of 4 bytes each + // namely s,t,xn,yn,zn) + glVertexPointer(3, GL_FLOAT, 32, &(*mPointPool.begin())); + // Set our texture data (24 represents 6 elements of 4 bytes each + // namely xn, yn, zn, x, y, z. We start 3 from the beginning to skip + // over x, y, z initially. + glClientActiveTextureARB(GL_TEXTURE1); + glTexCoordPointer(2, GL_FLOAT, 32, &(*(mPointPool.begin() + 3))); + glClientActiveTextureARB(GL_TEXTURE0); + glTexCoordPointer(2, GL_FLOAT, 32, &(*(mPointPool.begin() + 3))); + // Set our normal data... + glNormalPointer(GL_FLOAT, 32, &(*(mPointPool.begin() + 5))); +} + +void OBJ_PointPool::CalcTriNormal(int idx1, int idx2, int idx3) +{ + if (mPointPool[idx1*8 ]==mPointPool[idx2*8 ]&& + mPointPool[idx1*8+1]==mPointPool[idx2*8+1]&& + mPointPool[idx1*8+2]==mPointPool[idx2*8+2]) return; + if (mPointPool[idx1*8 ]==mPointPool[idx3*8 ]&& + mPointPool[idx1*8+1]==mPointPool[idx3*8+1]&& + mPointPool[idx1*8+2]==mPointPool[idx3*8+2]) return; + if (mPointPool[idx2*8 ]==mPointPool[idx3*8 ]&& + mPointPool[idx2*8+1]==mPointPool[idx3*8+1]&& + mPointPool[idx2*8+2]==mPointPool[idx3*8+2]) return; + + // idx2->idx1 cross idx1->idx3 = normal product + float v1[3], v2[3], n[3]; + v1[0] = mPointPool[idx2*8 ] - mPointPool[idx1*8 ]; + v1[1] = mPointPool[idx2*8+1] - mPointPool[idx1*8+1]; + v1[2] = mPointPool[idx2*8+2] - mPointPool[idx1*8+2]; + + v2[0] = mPointPool[idx2*8 ] - mPointPool[idx3*8 ]; + v2[1] = mPointPool[idx2*8+1] - mPointPool[idx3*8+1]; + v2[2] = mPointPool[idx2*8+2] - mPointPool[idx3*8+2]; + + // We do NOT normalize the cross product; we want larger triangles + // to make bigger normals. When we blend them, bigger sides will + // contribute more to the normals. We'll normalize the normals + // after the blend is done. + CrossVec(v1, v2, n); + mPointPool[idx1*8+5] += n[0]; + mPointPool[idx1*8+6] += n[1]; + mPointPool[idx1*8+7] += n[2]; + + mPointPool[idx2*8+5] += n[0]; + mPointPool[idx2*8+6] += n[1]; + mPointPool[idx2*8+7] += n[2]; + + mPointPool[idx3*8+5] += n[0]; + mPointPool[idx3*8+6] += n[1]; + mPointPool[idx3*8+7] += n[2]; +} + +inline void swapped_add(float& a, float& b) +{ + float a_c = a; + float b_c = b; + a += b_c; + b += a_c; +} + +void OBJ_PointPool::NormalizeNormals(void) +{ + // Average all normals of same-point, different texture points? Why is this needed? + // Well...the problem is that we get non-blended normals around the 'seam' where the ACF fuselage + // is put together...at this point the separate top and bottom texes touch. Their color will + // be the same but the S&T coords won't. If we have slightly different normals and the sun is making + // shiney specular hilites, the discontinuity is real noticiable. +#if BLEND_NORMALS + for (int n = 0; n < mPointPool.size(); n += 8) + { + for (int m = 0; m < mPointPool.size(); m += 8) + if (mPointPool[n ]==mPointPool[m ] && + mPointPool[n+1]==mPointPool[m+1] && + mPointPool[n+2]==mPointPool[m+2] && + m != n) + { + swapped_add(mPointPool[n+5], mPointPool[m+5]); + swapped_add(mPointPool[n+6], mPointPool[m+6]); + swapped_add(mPointPool[n+7], mPointPool[m+7]); + } + } +#endif + for (int n = 5; n < mPointPool.size(); n += 8) + { + NormalizeVec(&mPointPool[n]); + } +} + +// This is a debug routine that will draw each vertex's normals +void OBJ_PointPool::DebugDrawNormals() +{ + XPLMSetGraphicsState(0, 0, 0, 0, 0, 1, 0); + glColor3f(1.0, 0.0, 1.0); + glBegin(GL_LINES); + for(int n = 0; n < mPointPool.size(); n+=8) + { + glVertex3f(mPointPool[n], mPointPool[n+1], mPointPool[n+2]); + glVertex3f(mPointPool[n] + mPointPool[n+5], mPointPool[n+1] + mPointPool[n+1+5], + mPointPool[n+2] + mPointPool[n+2+5]); + } + glEnd(); +} + +/***************************************************** + Object and Struct Definitions +******************************************************/ +static map sTexes; + +struct LightInfo_t { + float xyz[3]; + int rgb[3]; +}; + +// One of these structs per LOD read from the OBJ file +struct LODObjInfo_t { + + float nearDist; // The visible range + float farDist; // of this LOD + vector triangleList; + vector lights; + OBJ_PointPool pointPool; + GLuint dl; +}; + +// One of these structs per OBJ file +struct ObjInfo_t { + + string path; + int texnum; + int texnum_lit; + XObj obj; + vector lods; +}; + +static vector sObjects; + +/***************************************************** + Utility functions to handle OBJ stuff +******************************************************/ + +int OBJ_LoadTexture(const char * inFilePath, bool inForceMaxTex) +{ + string path(inFilePath); + if (sTexes.count(path) > 0) + return sTexes[path]; + + int texNum; + XPLMGenerateTextureNumbers(&texNum, 1); + + int derez = 5 - gIntPrefsFunc("planes", "resolution", 3); + if (inForceMaxTex) + derez = 0; + bool ok = LoadTextureFromFile(path.c_str(), texNum, true, false, true, NULL, NULL, derez); + if (!ok) return 0; + + sTexes[path] = texNum; + return texNum; +} + +bool OBJ_Init(const char * inTexturePath) +{ + // Now that we've successfully loaded an aircraft, + // we can load our lighting texture + static bool firstTime = true; + if(firstTime) + { + sLightTexture = OBJ_LoadTexture(inTexturePath, true); + firstTime = false; + } + return sLightTexture != 0; +} + +// Load one model - return -1 if it can't be loaded. +int OBJ_LoadModel(const char * inFilePath) +{ + string path(inFilePath); + + for (int n = 0; n < sObjects.size(); ++n) + { + if (path == sObjects[n].path) + return n; + } + + sObjects.push_back(ObjInfo_t()); + bool ok = XObjRead(path.c_str(), sObjects.back().obj); + if (!ok) + { + sObjects.pop_back(); + return -1; + } + + MakePartialPathNativeObj(sObjects.back().obj.texture); + + sObjects.back().path = path; + string tex_path(path); + string::size_type p = tex_path.find_last_of(DIR_STR); + tex_path.erase(p+1); + tex_path += sObjects.back().obj.texture; + tex_path += ".png"; + sObjects.back().texnum = OBJ_LoadTexture(tex_path.c_str(), false); + + tex_path = path; + p = tex_path.find_last_of(DIR_STR); + tex_path.erase(p+1); + tex_path += sObjects.back().obj.texture; + tex_path += "_LIT.png"; + sObjects.back().texnum_lit = OBJ_LoadTexture(tex_path.c_str(), false); + + // We prescan all of the commands to see if there's ANY LOD. If there's + // not then we need to add one ourselves. If there is, we will find it + // naturally later. + bool foundLOD = false; + for (vector::iterator cmd = sObjects.back().obj.cmds.begin(); + cmd != sObjects.back().obj.cmds.end(); ++cmd) + { + if((cmd->cmdType == type_Attr) && (cmd->cmdID == attr_LOD)) + foundLOD = true; + } + if(foundLOD == false) + { + sObjects.back().lods.push_back(LODObjInfo_t()); + sObjects.back().lods.back().nearDist = 0; + sObjects.back().lods.back().farDist = 40000; + } + // Go through all of the commands for this object and filter out the polys + // and the lights. + for (vector::iterator cmd = sObjects.back().obj.cmds.begin(); + cmd != sObjects.back().obj.cmds.end(); ++cmd) + { + switch(cmd->cmdType) { + case type_Attr: + if(cmd->cmdID == attr_LOD) + { + // We've found a new LOD section so save this + // information in a new struct. From now on and until + // we hit this again, all data is for THIS LOD instance. + sObjects.back().lods.push_back(LODObjInfo_t()); + // Save our visible LOD range + sObjects.back().lods.back().nearDist = cmd->attributes[0]; + sObjects.back().lods.back().farDist = cmd->attributes[1]; + } + break; + case type_PtLine: + if(cmd->cmdID == obj_Light) + { + // For each light we've found, copy the data into our + // own light vector + for(int n = 0; n < cmd->rgb.size(); n++) + { + sObjects.back().lods.back().lights.push_back(LightInfo_t()); + sObjects.back().lods.back().lights.back().xyz[0] = cmd->rgb[n].v[0]; + sObjects.back().lods.back().lights.back().xyz[1] = cmd->rgb[n].v[1]; + sObjects.back().lods.back().lights.back().xyz[2] = cmd->rgb[n].v[2]; + sObjects.back().lods.back().lights.back().rgb[0] = cmd->rgb[n].rgb[0]; + sObjects.back().lods.back().lights.back().rgb[1] = cmd->rgb[n].rgb[1]; + sObjects.back().lods.back().lights.back().rgb[2] = cmd->rgb[n].rgb[2]; + } + } + break; + case type_Poly: + { + vector indexes; + // First get our point pool setup with all verticies + for(int n = 0; n < cmd->st.size(); n++) + { + float xyz[3], st[2]; + int index; + + xyz[0] = cmd->st[n].v[0]; + xyz[1] = cmd->st[n].v[1]; + xyz[2] = cmd->st[n].v[2]; + st[0] = cmd->st[n].st[0]; + st[1] = cmd->st[n].st[1]; + index = sObjects.back().lods.back().pointPool.AddPoint(xyz, st); + indexes.push_back(index); + } + + switch(cmd->cmdID) { + case obj_Tri: + for(int n = 0; n < indexes.size(); ++n) + { + sObjects.back().lods.back().triangleList.push_back(indexes[n]); + } + break; + case obj_Tri_Fan: + for(int n = 2; n < indexes.size(); n++) + { + sObjects.back().lods.back().triangleList.push_back(indexes[0 ]); + sObjects.back().lods.back().triangleList.push_back(indexes[n-1]); + sObjects.back().lods.back().triangleList.push_back(indexes[n ]); + } + break; + case obj_Tri_Strip: + case obj_Quad_Strip: + for(int n = 2; n < indexes.size(); n++) + { + if((n % 2) == 1) + { + sObjects.back().lods.back().triangleList.push_back(indexes[n - 2]); + sObjects.back().lods.back().triangleList.push_back(indexes[n]); + sObjects.back().lods.back().triangleList.push_back(indexes[n - 1]); + } + else + { + sObjects.back().lods.back().triangleList.push_back(indexes[n - 2]); + sObjects.back().lods.back().triangleList.push_back(indexes[n - 1]); + sObjects.back().lods.back().triangleList.push_back(indexes[n]); + } + } + break; + case obj_Quad: + for(int n = 3; n < indexes.size(); n += 4) + { + sObjects.back().lods.back().triangleList.push_back(indexes[n-3]); + sObjects.back().lods.back().triangleList.push_back(indexes[n-2]); + sObjects.back().lods.back().triangleList.push_back(indexes[n-1]); + sObjects.back().lods.back().triangleList.push_back(indexes[n-3]); + sObjects.back().lods.back().triangleList.push_back(indexes[n-1]); + sObjects.back().lods.back().triangleList.push_back(indexes[n ]); + } + break; + } + } + break; + } + } + + // Calculate our normals for all LOD's + for (int i = 0; i < sObjects.back().lods.size(); i++) + { + for (int n = 0; n < sObjects.back().lods[i].triangleList.size(); n += 3) + { + sObjects.back().lods[i].pointPool.CalcTriNormal( + sObjects.back().lods[i].triangleList[n], + sObjects.back().lods[i].triangleList[n+1], + sObjects.back().lods[i].triangleList[n+2]); + } + sObjects.back().lods[i].pointPool.NormalizeNormals(); + sObjects.back().lods[i].dl = 0; + } + sObjects.back().obj.cmds.clear(); + return sObjects.size()-1; +} + +/***************************************************** + Aircraft Model Drawing +******************************************************/ +// Note that texID and litTexID are OPTIONAL! They will only be filled +// in if the user wants to override the default texture specified by the +// obj file +void OBJ_PlotModel(int model, int texID, int litTexID, float inDistance, double inX, + double inY, double inZ, double inPitch, double inRoll, double inHeading) +{ + int tex, lit; + // Find out what LOD we need to draw + int lodIdx = -1; + for(int n = 0; n < sObjects[model].lods.size(); n++) + { + if((inDistance >= sObjects[model].lods[n].nearDist) && + (inDistance <= sObjects[model].lods[n].farDist)) + { + lodIdx = n; + break; + } + } + // If we didn't find a good LOD bin, we don't draw! + if(lodIdx == -1) + return; + + + static XPLMDataRef night_lighting_ref = XPLMFindDataRef("sim/graphics/scenery/percent_lights_on"); + bool use_night = XPLMGetDataf(night_lighting_ref) > 0.25; + + if (model == -1) return; + + if(texID) + { + tex = texID; + lit = litTexID; + } + else + { + tex = sObjects[model].texnum; + lit = sObjects[model].texnum_lit; + } + if (!use_night) lit = 0; + if (tex == 0) lit = 0; + XPLMSetGraphicsState(1, (tex != 0) + (lit != 0), 1, 1, 1, 1, 1); + if (tex != 0) XPLMBindTexture2d(tex, 0); + if (lit != 0) XPLMBindTexture2d(lit, 1); + + if (tex) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } + if (lit) { glActiveTextureARB(GL_TEXTURE1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); glActiveTextureARB(GL_TEXTURE0); } + + if (sObjects[model].lods[lodIdx].dl == 0) + { + sObjects[model].lods[lodIdx].dl = glGenLists(1); + + GLint xpBuffer; + // See if the card even has VBO. If it does, save xplane's pointer + // and bind to 0 for us. + if(glBindBufferARB) + { + glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &xpBuffer); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + } + // Save XPlanes OpenGL state + glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); + // Setup OpenGL pointers to our pool + sObjects[model].lods[lodIdx].pointPool.PreparePoolToDraw(); + // Enable vertex data sucking + glEnableClientState(GL_VERTEX_ARRAY); + // Enable normal array sucking + glEnableClientState(GL_NORMAL_ARRAY); + // Enable texture coordinate data sucking + glClientActiveTextureARB(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTextureARB(GL_TEXTURE0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + // Disable colors - maybe x-plane left it around. + glDisableClientState(GL_COLOR_ARRAY); + + glNewList(sObjects[model].lods[lodIdx].dl, GL_COMPILE); + // Kick OpenGL and draw baby! + glDrawElements(GL_TRIANGLES, sObjects[model].lods[lodIdx].triangleList.size(), + GL_UNSIGNED_INT, &(*sObjects[model].lods[lodIdx].triangleList.begin())); + +#if DEBUG_NORMALS + sObjects[model].lods[lodIdx].pointPool.DebugDrawNormals(); + XPLMSetGraphicsState(1, (tex != 0) + (lit != 0), 1, 1, 1, 1, 1); +#endif + + glEndList(); + + // Disable vertex data sucking + glDisableClientState(GL_VERTEX_ARRAY); + // Disable texture coordinate data sucking + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + // Disable normal array sucking + glDisableClientState(GL_NORMAL_ARRAY); + + // Restore Xplane's OpenGL State + glPopClientAttrib(); + + // If we bound before, we need to put xplane back where it was + if(glBindBufferARB) + glBindBufferARB(GL_ARRAY_BUFFER_ARB, xpBuffer); + + sObjects[model].lods[lodIdx].triangleList.clear(); + sObjects[model].lods[lodIdx].pointPool.Purge(); + } + glCallList(sObjects[model].lods[lodIdx].dl); + + +} + +/***************************************************** + Textured Lights Drawing + + Draw one or more lights on our OBJ. + RGB of 11,11,11 is a RED NAV light + RGB of 22,22,22 is a GREEN NAV light + RGB of 33,33,33 is a Red flashing BEACON light + RGB of 44,44,44 is a White flashing STROBE light + RGB of 55,55,55 is a landing light +******************************************************/ +void OBJ_BeginLightDrawing() +{ + sFOV = XPLMGetDataf(sFOVRef); + + // Setup OpenGL for the drawing + XPLMSetGraphicsState(1, 1, 0, 1, 1 , 1, 0); + XPLMBindTexture2d(sLightTexture, 0); +} + +void OBJ_DrawLights(int model, float inDistance, double inX, double inY, + double inZ, double inPitch, double inRoll, double inHeading, + xpmp_LightStatus lights) +{ + bool navLights = lights.navLights == 1; + bool bcnLights = lights.bcnLights == 1; + bool strbLights = lights.strbLights == 1; + bool landLights = lights.landLights == 1; + + int offset = lights.timeOffset; + + // flash frequencies + if(bcnLights) { + bcnLights = false; + int x = (int)(XPLMGetElapsedTime() * 1000 + offset) % 1200; + switch(lights.flashPattern) { + case xpmp_Lights_Pattern_EADS: + // EADS pattern: two flashes every 1.2 seconds + if(x < 120 || ((x > 240 && x < 360))) bcnLights = true; + break; + + case xpmp_Lights_Pattern_GA: + // GA pattern: 900ms / 1200ms + if((((int)(XPLMGetElapsedTime() * 1000 + offset) % 2100) < 900)) bcnLights = true; + break; + + case xpmp_Lights_Pattern_Default: + default: + // default pattern: one flash every 1.2 seconds + if(x < 120) bcnLights = true; + break; + } + + } + if(strbLights) { + strbLights = false; + int x = (int)(XPLMGetElapsedTime() * 1000 + offset) % 1700; + switch(lights.flashPattern) { + case xpmp_Lights_Pattern_EADS: + if(x < 80 || (x > 260 && x < 340)) strbLights = true; + break; + + case xpmp_Lights_Pattern_GA: + // similar to the others.. but a little different frequency :) + x = (int)(XPLMGetElapsedTime() * 1000 + offset) % 1900; + if(x < 100) strbLights = true; + break; + + case xpmp_Lights_Pattern_Default: + default: + if(x < 80) strbLights = true; + break; + } + } + + // Find out what LOD we need to draw + int lodIdx = -1; + for(int n = 0; n < sObjects[model].lods.size(); n++) + { + if((inDistance >= sObjects[model].lods[n].nearDist) && + (inDistance <= sObjects[model].lods[n].farDist)) + { + lodIdx = n; + break; + } + } + // If we didn't find a good LOD bin, we don't draw! + if(lodIdx == -1) + return; + + double size, distance; + // Where are we looking? + XPLMCameraPosition_t cameraPos; + XPLMReadCameraPosition(&cameraPos); + + // We can have 1 or more lights on each aircraft + for(int n = 0; n < sObjects[model].lods[lodIdx].lights.size(); n++) + { + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + // First we translate to our coordinate system and move the origin + // to the center of our lights. + glTranslatef(sObjects[model].lods[lodIdx].lights[n].xyz[0], + sObjects[model].lods[lodIdx].lights[n].xyz[1], + sObjects[model].lods[lodIdx].lights[n].xyz[2]); + + // Now we undo the rotation of the plane + glRotated(-inRoll, 0.0, 0.0, -1.0); + glRotated(-inPitch, 1.0, 0.0, 0.0); + glRotated(-inHeading, 0.0, -1.0, 0.0); + + // Now we undo the rotation of the camera + // NOTE: The order and sign of the camera is backwards + // from what we'd expect (the plane rotations) because + // the camera works backwards. If you pan right, everything + // else moves left! + glRotated(cameraPos.heading, 0.0, -1.0, 0.0); + glRotated(cameraPos.pitch, 1.0, 0.0, 0.0); + glRotated(cameraPos.roll, 0.0, 0.0, -1.0); + + // Find our distance from the camera + float dx = cameraPos.x - inX; + float dy = cameraPos.y - inY; + float dz = cameraPos.z - inZ; + distance = sqrt((dx * dx) + (dy * dy) + (dz * dz)); + + // Convert to NM + distance *= kMetersToNM; + + // Scale based on our FOV and Zoom. I did my initial + // light adjustments at a FOV of 60 so thats why + // I divide our current FOV by 60 to scale it appropriately. + distance *= sFOV/60.0; + distance /= cameraPos.zoom; + + // Calculate our light size. This is piecewise linear. I noticed + // that light size changed more rapidly when closer than 3nm so + // I have a separate equation for that. + if(distance <= 3.6) + size = (10 * distance) + 1; + else + size = (6.7 * distance) + 12; + + // Finally we can draw our lights + // Red Nav + glBegin(GL_QUADS); + if((sObjects[model].lods[lodIdx].lights[n].rgb[0] == 11) && + (sObjects[model].lods[lodIdx].lights[n].rgb[1] == 11) && + (sObjects[model].lods[lodIdx].lights[n].rgb[2] == 11)) + { + if(navLights) { + glColor4fv(kNavLightRed); + glTexCoord2f(0, 0.5); glVertex2f(-(size/2.0), -(size/2.0)); + glTexCoord2f(0, 1.0); glVertex2f(-(size/2.0), (size/2.0)); + glTexCoord2f(0.25, 1.0); glVertex2f((size/2.0), (size/2.0)); + glTexCoord2f(0.25, 0.5); glVertex2f((size/2.0), -(size/2.0)); + } + } + // Green Nav + else if((sObjects[model].lods[lodIdx].lights[n].rgb[0] == 22) && + (sObjects[model].lods[lodIdx].lights[n].rgb[1] == 22) && + (sObjects[model].lods[lodIdx].lights[n].rgb[2] == 22)) + { + if(navLights) { + glColor4fv(kNavLightGreen); + glTexCoord2f(0, 0.5); glVertex2f(-(size/2.0), -(size/2.0)); + glTexCoord2f(0, 1.0); glVertex2f(-(size/2.0), (size/2.0)); + glTexCoord2f(0.25, 1.0); glVertex2f((size/2.0), (size/2.0)); + glTexCoord2f(0.25, 0.5); glVertex2f((size/2.0), -(size/2.0)); + } + } + // Beacon + else if((sObjects[model].lods[lodIdx].lights[n].rgb[0] == 33) && + (sObjects[model].lods[lodIdx].lights[n].rgb[1] == 33) && + (sObjects[model].lods[lodIdx].lights[n].rgb[2] == 33)) + { + if(bcnLights) + { + glColor4fv(kNavLightRed); + glTexCoord2f(0, 0.5); glVertex2f(-(size/2.0), -(size/2.0)); + glTexCoord2f(0, 1.0); glVertex2f(-(size/2.0), (size/2.0)); + glTexCoord2f(0.25, 1.0); glVertex2f((size/2.0), (size/2.0)); + glTexCoord2f(0.25, 0.5); glVertex2f((size/2.0), -(size/2.0)); + } + } + // Strobes + else if((sObjects[model].lods[lodIdx].lights[n].rgb[0] == 44) && + (sObjects[model].lods[lodIdx].lights[n].rgb[1] == 44) && + (sObjects[model].lods[lodIdx].lights[n].rgb[2] == 44)) + { + if(strbLights) + { + glColor4fv(kStrobeLight); + glTexCoord2f(0.25, 0.0); glVertex2f(-(size/1.5), -(size/1.5)); + glTexCoord2f(0.25, 0.5); glVertex2f(-(size/1.5), (size/1.5)); + glTexCoord2f(0.50, 0.5); glVertex2f((size/1.5), (size/1.5)); + glTexCoord2f(0.50, 0.0); glVertex2f((size/1.5), -(size/1.5)); + } + } + // Landing Lights + else if((sObjects[model].lods[lodIdx].lights[n].rgb[0] == 55) && + (sObjects[model].lods[lodIdx].lights[n].rgb[1] == 55) && + (sObjects[model].lods[lodIdx].lights[n].rgb[2] == 55)) + { + if(landLights) { + // BEN SEZ: modulate the _alpha to make this dark, not + // the light color. Otherwise if the sky is fairly light the light + // will be darker than the sky, which looks f---ed during the day. + float color[4]; + color[0] = kLandingLight[0]; + if(color[0] < 0.0) color[0] = 0.0; + color[1] = kLandingLight[1]; + if(color[0] < 0.0) color[0] = 0.0; + color[2] = kLandingLight[2]; + if(color[0] < 0.0) color[0] = 0.0; + color[3] = kLandingLight[3] * ((distance * -0.05882) + 1.1764); + glColor4fv(color); + glTexCoord2f(0.25, 0.0); glVertex2f(-(size/2.0), -(size/2.0)); + glTexCoord2f(0.25, 0.5); glVertex2f(-(size/2.0), (size/2.0)); + glTexCoord2f(0.50, 0.5); glVertex2f((size/2.0), (size/2.0)); + glTexCoord2f(0.50, 0.0); glVertex2f((size/2.0), -(size/2.0)); + } + } else { + // rear nav light and others? I guess... + if(navLights) { + glColor3f( + sObjects[model].lods[lodIdx].lights[n].rgb[0] * 0.1, + sObjects[model].lods[lodIdx].lights[n].rgb[1] * 0.1, + sObjects[model].lods[lodIdx].lights[n].rgb[2] * 0.1); + glTexCoord2f(0, 0.5); glVertex2f(-(size/2.0), -(size/2.0)); + glTexCoord2f(0, 1.0); glVertex2f(-(size/2.0), (size/2.0)); + glTexCoord2f(0.25, 1.0); glVertex2f((size/2.0), (size/2.0)); + glTexCoord2f(0.25, 0.5); glVertex2f((size/2.0), -(size/2.0)); + } + } + glEnd(); + // Put OpenGL back how we found it + glPopMatrix(); + } +} + +int OBJ_GetModelTexID(int model) +{ + return sObjects[model].texnum; +} diff --git a/src/XPMPMultiplayerObj.h b/src/XPMPMultiplayerObj.h new file mode 100644 index 000000000..280dd18b4 --- /dev/null +++ b/src/XPMPMultiplayerObj.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef XPLMMULTIPLAYEROBJ_H +#define XPLMMULTIPLAYEROBJ_H + +#include "XPMPMultiplayer.h" // for light status +#include "XObjDefs.h" +#include "XPLMCamera.h" + +bool OBJ_Init(const char * inTexturePath); + +// Load one model - return -1 if it can't be loaded. +int OBJ_LoadModel(const char * inFilePath); + +// MODEL DRAWING +// Note that texID and litTexID are OPTIONAL! They will only be filled +// in if the user wants to override the default texture specified by the +// obj file +void OBJ_PlotModel(int model, int texID, int litTexID, float inDistance, double inX, double inY, + double inZ, double inPitch, double inRoll, double inHeading); + +// TEXTURED LIGHTS DRAWING +void OBJ_BeginLightDrawing(); +void OBJ_DrawLights(int model, float inDistance, double inX, double inY, + double inZ, double inPitch, double inRoll, double inHeading, + xpmp_LightStatus lights); + +// Texture loading +int OBJ_LoadTexture(const char * inFilePath, bool inForceMaxRes); +int OBJ_GetModelTexID(int model); + + +#endif diff --git a/src/XPMPMultiplayerVars.cpp b/src/XPMPMultiplayerVars.cpp new file mode 100644 index 000000000..a268f5356 --- /dev/null +++ b/src/XPMPMultiplayerVars.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2005, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "XPMPMultiplayerVars.h" +#include + + +int (* gIntPrefsFunc)(const char *, const char *, int) = NULL; +float (* gFloatPrefsFunc)(const char *, const char *, float) = NULL; + +XPMPPlaneVector gPlanes; +XPMPPlaneNotifierVector gObservers; +XPMPRenderPlanes_f gRenderer = NULL; +void * gRendererRef; +int gDumpOneRenderCycle = 0; +int gEnableCount = 1; + +vector gPackages; +map gGroupings; +map gPackageNames; + +string gDefaultPlane; +map gAircraftCodes; diff --git a/src/XPMPMultiplayerVars.h b/src/XPMPMultiplayerVars.h new file mode 100644 index 000000000..dbc825e25 --- /dev/null +++ b/src/XPMPMultiplayerVars.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2005, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef XPLMMULTIPLAYERVARS_H +#define XPLMMULTIPLAYERVARS_H + +/* + * This file contains the various internal definitions + * and globals for the model rendering code. + * + */ + +#include +#include +#include +#include + +#include "XObjDefs.h" + +using namespace std; + +#include "XPMPMultiplayer.h" + +template +inline +const T& +XPMP_TMIN(const T& a, const T& b) +{ + return b < a ? b : a; +} + +template +inline +const T& +XPMP_TMAX(const T& a, const T& b) +{ + return a < b ? b : a; +} + + +const double kFtToMeters = 0.3048; +const double kMaxDistTCAS = 40.0 * 6080.0 * kFtToMeters; + + +/****************** MODEL MATCHING CRAP ***************/ + +enum { + plane_Austin, + plane_Obj, + plane_Lights, + plane_Count +}; + +// This plane struct represents one model in one CSL packpage. +// It has a type, a single file path for whatever we have to load, +// and then implementation-specifc stuff. +struct CSLPlane_t { + int plane_type; // What kind are we? + string file_path; // Where do we load from + bool moving_gear; // Does gear retract? + // plane_Austin + int austin_idx; + // plane_Obj + int obj_idx; + // Optional Texture + int texID; + // Optional Lit Texture + int texLitID; +}; + +// These enums define the six levels of matching we might possibly +// make. For each level of matching, we use a single string as a key. +// (The string's contents vary with model - examples are shown.) +enum { + match_icao_airline_livery = 0, // B738 SWA SHAMU + match_icao_airline, // B738 SWA + match_group_airline_livery, // B731 B732 B733 B734 B735 B736 B737 B738 B739 SWA SHAMU + match_group_airline, // B731 B732 B733 B734 B735 B736 B737 B738 B739 SWA + match_icao, // B738 + match_group, // B731 B732 B733 B734 B735 B736 B737 B738 B739 + match_count +}; + +// A CSL package - a vector of planes and six maps from the above matching +// keys to the internal index of the plane. +struct CSLPackage_t { + + string name; + vector planes; + map matches[match_count]; + +}; + +extern vector gPackages; + +extern map gGroupings; + +extern map gPackageNames; + + +/**************** Model matching using ICAO doc 8643 + (http://www.icao.int/anb/ais/TxtFiles/Doc8643.txt) ***********/ + +struct CSLAircraftCode_t { + string icao; // aircraft ICAO code + string equip; // equipment code (L1T, L2J etc) + char category; // L, M, H, V (vertical = helo) +}; + +extern map gAircraftCodes; + +/**************** PLANE OBJECTS ********************/ + +// This plane struct reprents one instance of a +// multiplayer plane. +struct XPMPPlane_t { + + // Modeling properties + string icao; + string airline; + string livery; + CSLPlane_t * model; // May be null if no good match + bool good_livery; // is our paint correctly matched? + + // This callback is used to pull data from the client for posiitons, etc. + XPMPPlaneData_f dataFunc; + void * ref; + + // This is last known data we got for the plane, with timestamps. + int posAge; + XPMPPlanePosition_t pos; + int surfaceAge; + XPMPPlaneSurfaces_t surface; + int radarAge; + XPMPPlaneRadar_t radar; + +}; + +typedef XPMPPlane_t * XPMPPlanePtr; +typedef vector XPMPPlaneVector; + +// Notifiers - clients can install callbacks and be told when a plane's +// data changes. +typedef pair XPMPPlaneNotifierPair; +typedef pair XPMPPlaneNotifierTripple; +typedef vector XPMPPlaneNotifierVector; + +// Prefs funcs - the client provides callbacks to pull ini key values +// for various functioning. + +extern int (* gIntPrefsFunc)(const char *, const char *, int); +extern float (* gFloatPrefsFunc)(const char *, const char *, float); + +extern XPMPPlaneVector gPlanes; // All planes +extern XPMPPlaneNotifierVector gObservers; // All notifiers +extern XPMPRenderPlanes_f gRenderer; // The actual rendering func +extern void * gRendererRef; // The actual rendering func +extern int gDumpOneRenderCycle; // Debug +extern int gEnableCount; // Hack - see TCAS support + +extern string gDefaultPlane; // ICAO of default plane + +#endif diff --git a/src/XPMPPlaneRenderer.cpp b/src/XPMPPlaneRenderer.cpp new file mode 100644 index 000000000..256d2f2f9 --- /dev/null +++ b/src/XPMPPlaneRenderer.cpp @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2004, Ben Supnik and Chris Serio. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XPMPPlaneRenderer.h" +#include "XPMPMultiplayer.h" +#include "XPMPMultiplayerCSL.h" +#include "XPMPMultiplayerVars.h" +#include "XPMPMultiplayerObj.h" + +#include "XPLMGraphics.h" +#include "XPLMDisplay.h" +#include "XPLMCamera.h" +#include "XPLMPlanes.h" +#include "XPLMUtilities.h" +#include "XPLMDataAccess.h" + +#include +#include + +#if IBM +#include +#elif APL +#include +#else +#include +#endif + +#include +#include +#include +#include + +// Turn this on to get a lot of diagnostic info on who's visible, etc. +#define DEBUG_RENDERER 0 +// Turn this on to put rendering stats in datarefs for realtime observatoin. +#define RENDERER_STATS 0 + +// Maximum altitude difference in feet for TCAS blips +#define MAX_TCAS_ALTDIFF 5000 + +std::vector gMultiRef_X; +std::vector gMultiRef_Y; +std::vector gMultiRef_Z; + +/* UTILITY FUNCTIONS */ + +static inline double sqr(double a) { return a * a; } +static inline double CalcDist3D(double x1, double y1, double z1, double x2, double y2, double z2) +{ + return sqrt(sqr(x2-x1) + sqr(y2-y1) + sqr(z2-z1)); +} + + +static inline double CalcAngle(double dy, double dx) +{ + double angle; + if (dx == 0.0) + angle = (dy > 0.0) ? 0.0 : 180.0; + else + angle = 90.0 - (atan(dy/dx) * 180.0 / 3.14159265); + if (dx < 0.0) + angle += 180.0; + return angle; +} + +static inline double DiffAngle(double a1, double a2) +{ + double diff = (a2 - a1); + if (diff >= 180.0) + diff -= 360.0; + if (diff <= -180.0) + diff += 360.0; + return fabs(diff); +} + + +#if RENDERER_STATS + +static int GetRendererStat(void * inRefcon) +{ + return *((int *) inRefcon); +} + +#endif + +static int gTotPlanes = 0; // Counters +static int gACFPlanes = 0; // Number of Austin's planes we drew in full +static int gNavPlanes = 0; // Number of Austin's planes we drew with lights only +static int gOBJPlanes = 0; // Number of our OBJ planes we drew in full +static int gHackFOVLast = 0; + +static XPLMDataRef gFOVDataRef = NULL; // Current FOV for culling. +static XPLMDataRef gVisDataRef = NULL; // Current air visiblity for culling. +static XPLMDataRef gAltitudeRef = NULL; // Current aircraft altitude (for TCAS) +static float gOverRes = 1.0; // Wide-screen support. (May be messed up.) + + +void XPMPInitDefaultPlaneRenderer(void) +{ + // SETUP - mostly just fetch datarefs. + int width; + XPLMGetScreenSize(&width, NULL); + gOverRes = ((double) width) / 1024.0; + + gFOVDataRef = XPLMFindDataRef("sim/graphics/view/field_of_view_deg"); + if (gFOVDataRef == NULL) + XPLMDebugString("WARNING: Default renderer could not find FOV data in the sim.\n"); + gVisDataRef = XPLMFindDataRef("sim/graphics/view/visibility_effective_m"); + if (gVisDataRef == NULL) gVisDataRef = XPLMFindDataRef("sim/weather/visibility_effective_m"); + if (gVisDataRef == NULL) + XPLMDebugString("WARNING: Default renderer could not find effective visibility in the sim.\n"); + + if(gAltitudeRef == NULL) gAltitudeRef = XPLMFindDataRef("sim/flightmodel/position/elevation"); + +#if RENDERER_STATS + XPLMRegisterDataAccessor("hack/renderer/planes", xplmType_Int, 0, GetRendererStat, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &gTotPlanes, NULL); + XPLMRegisterDataAccessor("hack/renderer/navlites", xplmType_Int, 0, GetRendererStat, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &gNavPlanes, NULL); + XPLMRegisterDataAccessor("hack/renderer/objects", xplmType_Int, 0, GetRendererStat, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &gOBJPlanes, NULL); + XPLMRegisterDataAccessor("hack/renderer/acfs", xplmType_Int, 0, GetRendererStat, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &gACFPlanes, NULL); + XPLMRegisterDataAccessor("hack/renderer/fov", xplmType_Int, 0, GetRendererStat, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &gHackFOVLast, NULL); +#endif + + // We don't know how many multiplayer planes there are - fetch as many as we can. + + int n = 1; + char buf[100]; + XPLMDataRef d; + while (1) + { + sprintf(buf,"sim/multiplayer/position/plane%d_x", n); + d = XPLMFindDataRef(buf); + if (!d) break; + gMultiRef_X.push_back(d); + sprintf(buf,"sim/multiplayer/position/plane%d_y", n); + d = XPLMFindDataRef(buf); + if (!d) break; + gMultiRef_Y.push_back(d); + sprintf(buf,"sim/multiplayer/position/plane%d_z", n); + d = XPLMFindDataRef(buf); + if (!d) break; + gMultiRef_Z.push_back(d); + ++n; + } +} + +// PlaneToRender struct: we prioritize planes radially by distance, so... +// we use this struct to remember one visible plane. Once we've +// found all visible planes, we draw the closest ones. + +struct PlaneToRender_t { + float x; // Positional info + float y; + float z; + float pitch; + float heading; + float roll; + CSLPlane_t * model; // What model are we? + bool full; // Do we need to draw the full plane or just lites? + bool cull; // Are we visible on screen? + bool tcas; // Are we visible on TCAS? + XPLMPlaneDrawState_t state; // Flaps, gear, etc. + float dist; + xpmp_LightStatus lights; // lights status +}; +typedef std::map RenderMap; + + +void XPMPDefaultPlaneRenderer(void) +{ + long planeCount = XPMPCountPlanes(); +#if DEBUG_RENDERER + char buf[50]; + sprintf(buf,"Renderer Planes: %d\n", planeCount); + XPLMDebugString(buf); +#endif + if (planeCount == 0) // Quick exit if no one's around. + { + if (gDumpOneRenderCycle) + { + gDumpOneRenderCycle = false; + XPLMDebugString("No planes this cycle.\n"); + } + return; + } + + if (gFOVDataRef == NULL) // No FOV - we're probably totally screwed up. + return; + + // Culling - read the camera pos«and figure out what's visible. + + XPLMCameraPosition_t cameraPos; + double fov; + + XPLMReadCameraPosition(&cameraPos); + fov = XPLMGetDataf(gFOVDataRef); + double maxDist = XPLMGetDataf(gVisDataRef); + + double kFullPlaneDist = gOverRes * (5280.0 / 3.2) * (gFloatPrefsFunc ? gFloatPrefsFunc("planes","full_distance", 3.0) : 3.0); // Only draw planes fully within 3 miles. + int kMaxFullPlanes = gIntPrefsFunc ? gIntPrefsFunc("planes","max_full_count", 100) : 100; // Draw no more than 100 full planes! + + // Field of view modification. We don't yet handle camera roll because I'm too stupid + // to do the math. (I took linear algebra but came out of the course knowing less than + // when I went in. So instead we...assume that our field of view is vertical, apply + // a 5:3 aspect ratio to widen it and a 10% fudge factor to account for airplanes + // not being point objects. The 5:3 is based on allowing for the worst case, that + // we're rolled to make a perfect diagonal making our monitor as wide as possible.d + // We divide by camera zoom so that when we're zoomed in we're not taking people + // that have been zoomed out of our peripheral vision. + fov = fov * 5.0 / 4.0 / cameraPos.zoom; + + gTotPlanes = planeCount; + gNavPlanes = gACFPlanes = gOBJPlanes = 0; + + int modelCount, active, plugin, tcas; + XPLMCountAircraft(&modelCount, &active, &plugin); + tcas = modelCount - 1; // This is how many tcas blips we can have! + + RenderMap myPlanes; + + /************************************************************************************ + * CULLING AND STATE CALCULATION LOOP + ************************************************************************************/ + + if (gDumpOneRenderCycle) + { + XPLMDebugString("Dumping one cycle map of planes.\n"); + char fname[256], bigbuf[1024], foo[32]; + for (int n = 1; n < modelCount; ++n) + { + XPLMGetNthAircraftModel(n, fname, bigbuf); + sprintf(foo, " [%d] - ", n); + XPLMDebugString(foo); + XPLMDebugString(fname); + XPLMDebugString(" - "); + XPLMDebugString(bigbuf); + XPLMDebugString("\n"); + } + } + + // Go through every plane. We're going to figure out if it is visible and if so remember it for drawing later. + for (long index = 0; index < planeCount; ++index) + { + XPMPPlaneID id = XPMPGetNthPlane(index); + + XPMPPlanePosition_t pos; + pos.size = sizeof(pos); + + if (XPMPGetPlaneData(id, xpmpDataType_Position, &pos) != xpmpData_Unavailable) + { + // First figure out where the plane is! + + double x,y,z; + XPLMWorldToLocal(pos.lat, pos.lon, pos.elevation * kFtToMeters, &x, &y, &z); + + double distMeters = CalcDist3D(x,y,z,cameraPos.x, cameraPos.y, cameraPos.z); + if (cameraPos.zoom != 0.0) + distMeters /= cameraPos.zoom; // If we're 2x zoomed, pretend the AC is half as far away. + + // If the plane is farther than our TCAS range, it's just not visible. Drop it! + if (distMeters > kMaxDistTCAS) + continue; + + // Only draw if it's in range. + bool cull = (distMeters > maxDist); + + XPMPPlaneRadar_t radar; + radar.size = sizeof(radar); + bool tcas = true; + if (XPMPGetPlaneData(id, xpmpDataType_Radar, &radar) != xpmpData_Unavailable) + if (radar.mode == xpmpTransponderMode_Standby) + tcas = false; + + // check for altitude - if difference exceeds 3000ft, don't show + double acft_alt = XPLMGetDatad(gAltitudeRef) / kFtToMeters; + double alt_diff = pos.elevation - acft_alt; + if(alt_diff < 0) alt_diff *= -1; + if(alt_diff > MAX_TCAS_ALTDIFF) tcas = false; + + // Calculate the heading from the camera to the target (hor, vert). + // Calculate the angles between the camera angles and the real angles. + // Cull if we exceed half the FOV. + + double headingToTarget = CalcAngle(cameraPos.z - z, x - cameraPos.x); + double pitchToTarget = CalcAngle(sqrt(sqr(x - cameraPos.x) + sqr(cameraPos.z - z)), y - cameraPos.y); + + double headOff = DiffAngle(headingToTarget, cameraPos.heading); + double pitchOff = DiffAngle(pitchToTarget,cameraPos.pitch); + +#if DEBUG_RENDERER + char cullBuf[1024]; + sprintf(cullBuf, "Target Pos = %f,%f,%f, Camera Pos = %f,%f,%f.\n", + x,y,z,cameraPos.x,cameraPos.y,cameraPos.z); + XPLMDebugString(cullBuf); + sprintf(cullBuf, "Camera p=%f,h=%f, object p=%f,h=%f,diff p=%f,h=%f.\n", + cameraPos.pitch, cameraPos.heading, pitchToTarget, headingToTarget, pitchOff, headOff); + XPLMDebugString(cullBuf); +#endif + + + float fov_fudged = fov + atan(200.0 / distMeters) * 180.0 / 3.141592565; +#if RENDERER_STATS + gHackFOVLast = fov_fudged; +#endif + // View frustum check - if we're off screen, we don't draw. But remember us - we may be visible on TCAS. + if ((headOff > (fov_fudged / 2.0)) || + (pitchOff > (fov_fudged / 2.0))) + { + cull = true; + } + + // Full plane or lites based on distance. + bool drawFullPlane = (distMeters < kFullPlaneDist); + +#if DEBUG_RENDERER + + char icao[128], livery[128]; + char debug[512]; + + XPMPGetPlaneICAOAndLivery(id, icao, livery); + sprintf(debug,"Queueing plane %d (%s/%s) at lle %f, %f, %f (xyz=%f, %f, %f) pitch=%f,roll=%f,heading=%f,model=1.\n", index, icao, livery, + pos.lat, pos.lon, pos.elevation, + x, y, z, pos.pitch, pos.roll, pos.heading); + XPLMDebugString(debug); +#endif + + // Stash one render record with the plane's position, etc. + { + PlaneToRender_t renderRecord; + renderRecord.x = x; + renderRecord.y = y; + renderRecord.z = z; + renderRecord.pitch = pos.pitch; + renderRecord.heading = pos.heading; + renderRecord.roll = pos.roll; + renderRecord.model=((XPMPPlanePtr)id)->model; + renderRecord.cull = cull; // NO other planes. Doing so causes a lot of things to go nuts! + renderRecord.tcas = tcas; + + XPMPPlaneSurfaces_t surfaces; + surfaces.size = sizeof(surfaces); + if (XPMPGetPlaneData(id, xpmpDataType_Surfaces, &surfaces) != xpmpData_Unavailable) + { + renderRecord.state.structSize = sizeof(renderRecord.state); + renderRecord.state.gearPosition = surfaces.gearPosition ; + renderRecord.state.flapRatio = surfaces.flapRatio ; + renderRecord.state.spoilerRatio = surfaces.spoilerRatio ; + renderRecord.state.speedBrakeRatio = surfaces.speedBrakeRatio ; + renderRecord.state.slatRatio = surfaces.slatRatio ; + renderRecord.state.wingSweep = surfaces.wingSweep ; + renderRecord.state.thrust = surfaces.thrust ; + renderRecord.state.yolkPitch = surfaces.yolkPitch ; + renderRecord.state.yolkHeading = surfaces.yolkHeading ; + renderRecord.state.yolkRoll = surfaces.yolkRoll ; + + renderRecord.lights.lightFlags = surfaces.lights.lightFlags; + + } else { + renderRecord.state.structSize = sizeof(renderRecord.state); + renderRecord.state.gearPosition = (pos.elevation < 70) ? 1.0 : 0.0; + renderRecord.state.flapRatio = (pos.elevation < 70) ? 1.0 : 0.0; + renderRecord.state.spoilerRatio = renderRecord.state.speedBrakeRatio = renderRecord.state.slatRatio = renderRecord.state.wingSweep = 0.0; + renderRecord.state.thrust = (pos.pitch > 30) ? 1.0 : 0.6; + renderRecord.state.yolkPitch = pos.pitch / 90.0; + renderRecord.state.yolkHeading = pos.heading / 180.0; + renderRecord.state.yolkRoll = pos.roll / 90.0; + + // use some smart defaults + renderRecord.lights.bcnLights = 1; + renderRecord.lights.navLights = 1; + + } + if (renderRecord.model && !renderRecord.model->moving_gear) + renderRecord.state.gearPosition = 1.0; + renderRecord.full = drawFullPlane; + renderRecord.dist = distMeters; + + myPlanes.insert(RenderMap::value_type(distMeters, renderRecord)); + + } // State calculation + + } // Plane has data available + + } // Per-plane loop + + if (gDumpOneRenderCycle) + XPLMDebugString("End of cycle dump.\n"); + + /************************************************************************************ + * ACTUAL RENDERING LOOP + ************************************************************************************/ + + // We're going to go in and render the first N planes in full, and the rest as lites. + // We're also going to put the x-plane multiplayer vars in place for the first N + // TCAS-visible planes, so they show up on our moving map. + // We do this in two stages: building up what to do, then doing it in the optimal + // OGL order. + + int renderedCounter = 0; + + vector planes_obj_lites; + multimap planes_austin; + multimap planes_obj; + + vector::iterator planeIter; + multimap::iterator planeMapIter; + + // In our first iteration pass we'll go through all planes and handle TCAS, draw planes that have no + // CSL model, and put CSL planes in the right 'bucket'. + + for (RenderMap::iterator iter = myPlanes.begin(); iter != myPlanes.end(); ++iter) + { + // This is the case where we draw a real plane. + if (!iter->second.cull) + { + // Max plane enforcement - once we run out of the max number of full planes the + // user allows, force only lites for framerate + if (gACFPlanes >= kMaxFullPlanes) + iter->second.full = false; + +#if DEBUG_RENDERER + char debug[512]; + sprintf(debug,"Drawing plane: %s at %f,%f,%f (%fx%fx%f full=%d\n", + iter->second.model ? iter->second.model->file_path.c_str() : "", iter->second.x, iter->second.y, iter->second.z, + iter->second.pitch, iter->second.roll, iter->second.heading, iter->second.full ? 1 : 0); + XPLMDebugString(debug); +#endif + + if (iter->second.model) + { + if (iter->second.model->plane_type == plane_Austin) + { + planes_austin.insert(multimap::value_type(CSL_GetOGLIndex(iter->second.model), &iter->second)); + } + else if (iter->second.model->plane_type == plane_Obj) + { + planes_obj.insert(multimap::value_type(CSL_GetOGLIndex(iter->second.model), &iter->second)); + planes_obj_lites.push_back(&iter->second); + } + + } else { + // If it's time to draw austin's planes but this one + // doesn't have a model, we draw anything. + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glTranslatef(iter->second.x, iter->second.y, iter->second.z); + glRotatef(iter->second.heading, 0.0, -1.0, 0.0); + glRotatef(iter->second.pitch, 01.0, 0.0, 0.0); + glRotatef(iter->second.roll, 0.0, 0.0, -1.0); + + // Safety check - if plane 1 isn't even loaded do NOT draw, do NOT draw plane 0. + // Using the user's planes can cause the internal flight model to get f-cked up. + // Using a non-loaded plane can trigger internal asserts in x-plane. + if (modelCount > 1) + XPLMDrawAircraft(1, + (float) iter->second.x, (float) iter->second.y, (float) iter->second.z, + iter->second.pitch, iter->second.roll, iter->second.heading, + iter->second.full ? 1 : 0, &iter->second.state); + + glPopMatrix(); + } + + } + + // TCAS handling - if the plane needs to be drawn on TCAS and we haven't yet, move one of Austin's planes. + if (iter->second.tcas && renderedCounter < gMultiRef_X.size()) + { + XPLMSetDataf(gMultiRef_X[renderedCounter], iter->second.x); + XPLMSetDataf(gMultiRef_Y[renderedCounter], iter->second.y); + XPLMSetDataf(gMultiRef_Z[renderedCounter], iter->second.z); + ++renderedCounter; + } + } + + // PASS 1 - draw Austin's planes. + + for (planeMapIter = planes_austin.begin(); planeMapIter != planes_austin.end(); ++planeMapIter) + { + CSL_DrawObject( planeMapIter->second->model, + planeMapIter->second->dist, + planeMapIter->second->x, + planeMapIter->second->y, + planeMapIter->second->z, + planeMapIter->second->pitch, + planeMapIter->second->roll, + planeMapIter->second->heading, + plane_Austin, + planeMapIter->second->full ? 1 : 0, + planeMapIter->second->lights, + &planeMapIter->second->state); + + if (planeMapIter->second->full) + ++gACFPlanes; + else + ++gNavPlanes; + } + + // PASS 2 - draw OBJs + + for (planeMapIter = planes_obj.begin(); planeMapIter != planes_obj.end(); ++planeMapIter) + { + CSL_DrawObject( + planeMapIter->second->model, + planeMapIter->second->dist, + planeMapIter->second->x, + planeMapIter->second->y, + planeMapIter->second->z, + planeMapIter->second->pitch, + planeMapIter->second->roll, + planeMapIter->second->heading, + plane_Obj, + planeMapIter->second->full ? 1 : 0, + planeMapIter->second->lights, + &planeMapIter->second->state); + ++gOBJPlanes; + } + + // PASS 3 - draw OBJ lights. + + if (!planes_obj_lites.empty()) + { + OBJ_BeginLightDrawing(); + for (planeIter = planes_obj_lites.begin(); planeIter != planes_obj_lites.end(); ++planeIter) + { + // this thing draws the lights of a model + CSL_DrawObject( (*planeIter)->model, + (*planeIter)->dist, + (*planeIter)->x, + (*planeIter)->y, + (*planeIter)->z, + (*planeIter)->pitch, + (*planeIter)->roll, + (*planeIter)->heading, + plane_Lights, + (*planeIter)->full ? 1 : 0, + (*planeIter)->lights, + &(*planeIter)->state); + } + } + + // Final hack - leave a note to ourselves for how many of Austin's planes we relocated to do TCAS. + if (tcas > renderedCounter) + tcas = renderedCounter; + gEnableCount = (tcas+1); + + gDumpOneRenderCycle = 0; +} diff --git a/src/XUtils.cpp b/src/XUtils.cpp new file mode 100644 index 000000000..23bebf736 --- /dev/null +++ b/src/XUtils.cpp @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2004, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#include "XUtils.h" +#include +#include +#include "XObjDefs.h" +#include +#include "PlatformUtils.h" +//#include +#include +#include + +#if !defined(XUTILS_EXCLUDE_MAC_CRAP) && defined(__MACH__) +#define XUTILS_EXCLUDE_MAC_CRAP 1 +#endif + +#if APL +//using namespace Metrowerks; +#endif + +static char * my_fgets(char * s, int n, FILE * file) +{ + char * p = s; + int c; + + if (--n < 0) + return(NULL); + + if (n) + do + { + c = fgetc(file); + + if (c == EOF) + if (/*feof(file) &&*/ p != s) + break; + else + { + return(NULL); + } + + *p++ = c; + } + while (c != '\n' && c != '\r' && --n); + + *p = 0; + + return(s); +} + + + +StTextFileScanner::StTextFileScanner(const char * file, bool skip) : + mFile(fopen(file, "r")), + mDone(false), + mSkipBlanks(skip) +{ + read_next(); +} + +StTextFileScanner::~StTextFileScanner() +{ + if (mFile) + fclose(mFile); +} + +bool StTextFileScanner::done() +{ + return mDone; +} + +void StTextFileScanner::next() +{ + read_next(); +} + +string StTextFileScanner::get() +{ + return mBuf; +} + +void StTextFileScanner::read_next(void) +{ + mBuf.clear(); + mDone = true; + + char buf[4096]; + + while (mFile && /*!feof(mFile) &&*/ my_fgets(buf, sizeof(buf), mFile)) + { + int len = strlen(buf); + while ((len > 0) && (buf[len-1] == '\r' || buf[len-1] == '\n')) + { + buf[len-1] = 0; + --len; + } + + if (buf[0] == '\r' || buf[0] == '\n') + mBuf = buf+1; + else + mBuf = buf; + + if (!mBuf.empty() || !mSkipBlanks) + { + mDone = false; + return; + } + } +} + +void BreakString(const string& line, vector& words) +{ + words.clear(); + string::const_iterator i = line.begin(); + while (i < line.end()) + { + string::const_iterator s = i; + while (s < line.end() && isspace(*s)) + ++s; + + string::const_iterator e = s; + while (e < line.end() && !isspace(*e)) + ++e; + + if (s < e) + words.push_back(string(s,e)); + + i = e; + } +} + +void StringToUpper(string& s) +{ + for (string::iterator i = s.begin(); i != s.end(); ++i) + *i = toupper(*i); +} + +bool HasExtNoCase(const string& inStr, const char * inExt) +{ + string s(inStr); + string e(inExt); + StringToUpper(s); + StringToUpper(e); + + + if (s.rfind(e) == (s.length() - e.length())) + return true; + return false; +} + +void ChangePolyCmdCW(XObjCmd& ioCmd) +{ + vector v; + for (vector::reverse_iterator riter = ioCmd.st.rbegin(); + riter != ioCmd.st.rend(); ++riter) + { + v.push_back(*riter); + } + ioCmd.st = v; +} + +bool GetNextNoComments(StTextFileScanner& f, string& s) +{ + while(!f.done()) + { + s = f.get(); + f.next(); + if (s.empty() || s[0] != '#') + return true; + } + return false; +} + +double GetObjRadius(const XObj& inObj) +{ + double dist = 0, d; + for (vector::const_iterator c = inObj.cmds.begin(); + c != inObj.cmds.end(); ++c) + { + for (vector::const_iterator v = c->st.begin(); + v != c->st.end(); ++v) + { + d = sqrt(v->v[0] * v->v[0] + + v->v[1] * v->v[1] + + v->v[2] * v->v[2]); + if (d > dist) dist = d; + } + + for (vector::const_iterator p = c->rgb.begin(); + p != c->rgb.end(); ++p) + { + d = sqrt(p->v[0] * p->v[0] + + p->v[1] * p->v[1] + + p->v[2] * p->v[2]); + if (d > dist) dist = d; + } + } + return dist; +} + +int PickRandom(vector& chances) +{ + double v = (double) (rand() % RAND_MAX) / (double) RAND_MAX; + + for (int n = 0; n < chances.size(); ++n) + { + if (v < chances[n]) + return n; + v -= chances[n]; + } + return chances.size(); +} + +bool RollDice(double inProb) +{ + if (inProb <= 0.0) return false; + if (inProb >= 1.0) return true; + double v = (double) (rand() % RAND_MAX) / (double) RAND_MAX; + return v < inProb; +} + +double RandRange(double mmin, double mmax) +{ + if (mmin >= mmax) + return mmin; + double v = (double) rand() / (double) RAND_MAX; + return mmin + ((mmax - mmin) * v); +} + +double RandRangeBias(double mmin, double mmax, double biasRatio, double randomAmount) +{ + double span = mmax - mmin; + double lower_rat = biasRatio * (1.0 - randomAmount); + double upper_rat = lower_rat + randomAmount; + return RandRange(mmin + span * lower_rat,mmin + span * upper_rat); +} + + +void StripPath(string& ioPath) +{ + string::size_type sep = ioPath.rfind(DIR_CHAR); + if (sep != ioPath.npos) + ioPath = ioPath.substr(sep+1,ioPath.npos); +} + +void StripPathCP(string& ioPath) +{ + string::size_type sep; + sep = ioPath.rfind(':'); + if (sep != ioPath.npos) + ioPath = ioPath.substr(sep+1,ioPath.npos); + sep = ioPath.rfind('\\'); + if (sep != ioPath.npos) + ioPath = ioPath.substr(sep+1,ioPath.npos); +} + +void ExtractPath(string& ioPath) +{ + string::size_type sep = ioPath.rfind(DIR_CHAR); + if (sep != ioPath.npos) + ioPath = ioPath.substr(0, sep); +} + +#if APL + +#if !defined(XUTILS_EXCLUDE_MAC_CRAP) + +#include + +OSErr FindSuperFolder(const FSSpec& inItem, FSSpec& outFolder) +{ + CInfoPBRec paramBlock; + OSErr err; + + paramBlock.dirInfo.ioCompletion = NULL; + paramBlock.dirInfo.ioNamePtr = (StringPtr) (&(outFolder.name)); + paramBlock.dirInfo.ioVRefNum = inItem.vRefNum; + paramBlock.dirInfo.ioFDirIndex = -1; + paramBlock.dirInfo.ioDrDirID = inItem.parID; + + err = ::PBGetCatInfoSync(¶mBlock); + if (err != noErr) + return err; + + outFolder.vRefNum = paramBlock.dirInfo.ioVRefNum; + outFolder.parID= paramBlock.dirInfo.ioDrParID; + return noErr; +} + +void AppPath(string& outString) +{ + ProcessSerialNumber psn = { 0, kCurrentProcess }; + ProcessInfoRec info = { 0 }; + FSSpec spec; + Str255 name; + info.processInfoLength = sizeof(info); + info.processAppSpec = &spec; + info.processName = name; + GetProcessInformation(&psn, &info); + FSSpec_2_String(spec, outString); +} + +void FSSpec_2_String(const FSSpec& inSpec, string& outString) +{ + outString.clear(); + + FSSpec foo(inSpec); + FSSpec foo2; + + while (1) + { + if (outString.empty()) + outString = std::string(foo.name+1, foo.name+foo.name[0]+1); + else + outString = std::string(foo.name+1, foo.name+foo.name[0]+1) + std::string(":") + outString; + if (FindSuperFolder(foo, foo2) != noErr) + break; + foo = foo2; + } +} + +#endif +#endif + +void ExtractFixedRecordString( + const string& inLine, + int inBegin, + int inEnd, + string& outString) +{ + int sp = inBegin-1; + int ep = inEnd; + if (ep > inLine.length()) ep = inLine.length(); + if (sp > inLine.length()) sp = inLine.length(); + + while ((sp < ep) && (inLine[sp] == ' ')) + ++sp; + + while ((ep > sp) && (inLine[ep-1] == ' ')) + --ep; + + outString = inLine.substr(sp, ep - sp); +} + +bool ExtractFixedRecordLong( + const string& inLine, + int inBegin, + int inEnd, + long& outLong) +{ + string foo; + ExtractFixedRecordString(inLine, inBegin, inEnd, foo); + if (foo.empty()) return false; + outLong = strtol(foo.c_str(), NULL, 10); + return true; +} + +bool ExtractFixedRecordUnsignedLong( + const string& inLine, + int inBegin, + int inEnd, + unsigned long& outUnsignedLong) +{ + string foo; + ExtractFixedRecordString(inLine, inBegin, inEnd, foo); + if (foo.empty()) return false; + outUnsignedLong = strtoul(foo.c_str(), NULL, 10); + return true; +} + +#pragma mark - + +struct XPointPool::XPointPoolImp { + + struct p_info { + float xyz[3]; + float st[2]; + }; + vector pts; + map index; + + void clear() + { + pts.clear(); + index.clear(); + } + + int count(void) + { + return pts.size(); + } + + int accumulate(const float xyz[3], const float st[2]) + { + static char buf[256]; + sprintf(buf,"%08X%08X%08X|%08x%08x", + *(reinterpret_cast(xyz+0)), + *(reinterpret_cast(xyz+1)), + *(reinterpret_cast(xyz+2)), + *(reinterpret_cast(st +0)), + *(reinterpret_cast(st +1))); + string key(buf); + map::iterator i = index.find(key); + if (i != index.end()) return i->second; + p_info p; + memcpy(p.xyz, xyz, sizeof(p.xyz)); + memcpy(p.st, st, sizeof(p.st)); + pts.push_back(p); + index.insert(map::value_type(key, pts.size())); + pts.push_back(p); + return pts.size()-1; + } + + void get(int i, float xyz[3], float st[2]) + { + p_info& p = pts[i]; + memcpy(xyz,p.xyz,sizeof(p.xyz)); + memcpy(st,p.st,sizeof(p.st)); + } +}; + +XPointPool::XPointPool() +{ + mImp = new XPointPoolImp; +} + +XPointPool::~XPointPool() +{ + delete mImp; +} + +void XPointPool::clear() +{ + mImp->clear(); +} + +int XPointPool::accumulate(const float xyz[3], const float st[2]) +{ + return mImp->accumulate(xyz, st); +} + +void XPointPool::get(int index, float xyz[3], float st[2]) +{ + mImp->get(index,xyz,st); +} + +int XPointPool::count(void) +{ + return mImp->count(); +} + +void DecomposeObjCmd(const XObjCmd& inCmd, vector& outCmds, int maxValence) +{ + XObjCmd c; + c.cmdType = type_Poly; + c.cmdID = obj_Tri; + switch(inCmd.cmdID) { + case obj_Tri: + // Triangles never need breaking down. + outCmds.push_back(inCmd); + break; + case obj_Quad: + case obj_Quad_Hard: + case obj_Smoke_Black: + case obj_Smoke_White: + case obj_Movie: + // Quads - split into triangles if necessary. + if (maxValence > 3) { + outCmds.push_back(inCmd); + outCmds.back().cmdID = obj_Quad; + } else { + outCmds.push_back(inCmd); + outCmds.back().cmdID = obj_Tri; + outCmds.back().st.erase(outCmds.back().st.begin()+3); + outCmds.push_back(inCmd); + outCmds.back().cmdID = obj_Tri; + outCmds.back().st.erase(outCmds.back().st.begin()+1); + } + break; + case obj_Polygon: + // Polygons might be ok. But if we have to break them down, + // we generate N-2 triangles in a fan configuration. + if (maxValence < inCmd.st.size()) + { + c.st.push_back(inCmd.st[0]); + c.st.push_back(inCmd.st[1]); + c.st.push_back(inCmd.st[2]); + for (int n = 2; n < inCmd.st.size(); ++n) + { + c.st[1] = inCmd.st[n-1]; + c.st[2] = inCmd.st[n ]; + outCmds.push_back(c); + } + } else + outCmds.push_back(inCmd); + break; + case obj_Tri_Strip: + // Triangle strips - every other triangle's vertices + // are backward! + c.st.push_back(inCmd.st[0]); + c.st.push_back(inCmd.st[1]); + c.st.push_back(inCmd.st[2]); + for (int n = 2; n < inCmd.st.size(); ++n) + { + if (n%2) + { + c.st[0] = inCmd.st[n-2]; + c.st[1] = inCmd.st[n ]; + c.st[2] = inCmd.st[n-1]; + outCmds.push_back(c); + } else { + c.st[0] = inCmd.st[n-2]; + c.st[1] = inCmd.st[n-1]; + c.st[2] = inCmd.st[n ]; + outCmds.push_back(c); + } + } + break; + case obj_Tri_Fan: + // Tri fan - run around the triangle fan emitting triangles. + c.st.push_back(inCmd.st[0]); + c.st.push_back(inCmd.st[1]); + c.st.push_back(inCmd.st[2]); + for (int n = 2; n < inCmd.st.size(); ++n) + { + c.st[1] = inCmd.st[n-1]; + c.st[2] = inCmd.st[n ]; + outCmds.push_back(c); + } + break; + case obj_Quad_Strip: + // Quad strips can become either quads or triangles!! + if (maxValence > 3) + { + c.cmdID = obj_Quad; + c.st.push_back(inCmd.st[0]); + c.st.push_back(inCmd.st[1]); + c.st.push_back(inCmd.st[2]); + c.st.push_back(inCmd.st[3]); + for (int n = 2; n < inCmd.st.size(); n += 2) + { + c.st[0] = inCmd.st[n-2]; + c.st[1] = inCmd.st[n-1]; + c.st[2] = inCmd.st[n+1]; + c.st[3] = inCmd.st[n ]; + outCmds.push_back(c); + } + } else { + c.st.push_back(inCmd.st[0]); + c.st.push_back(inCmd.st[1]); + c.st.push_back(inCmd.st[2]); + for (int n = 2; n < inCmd.st.size(); ++n) + { + if (n%2) + { + c.st[0] = inCmd.st[n-2]; + c.st[1] = inCmd.st[n ]; + c.st[2] = inCmd.st[n-1]; + outCmds.push_back(c); + } else { + c.st[0] = inCmd.st[n-2]; + c.st[1] = inCmd.st[n-1]; + c.st[2] = inCmd.st[n ]; + outCmds.push_back(c); + } + } + } + break; + default: + outCmds.push_back(inCmd); + } +} + +void DecomposeObj(const XObj& inObj, XObj& outObj, int maxValence) +{ + outObj.cmds.clear(); + outObj.texture = inObj.texture; + for (vector::const_iterator cmd = inObj.cmds.begin(); + cmd != inObj.cmds.end(); ++cmd) + { + vector newCmds; + DecomposeObjCmd(*cmd, newCmds, maxValence); + outObj.cmds.insert(outObj.cmds.end(), newCmds.begin(), newCmds.end()); + } +} diff --git a/src/XUtils.h b/src/XUtils.h new file mode 100644 index 000000000..71ebc2655 --- /dev/null +++ b/src/XUtils.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2004, Laminar Research. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef XUTILS_H +#define XUTILS_H + +struct XObjCmd; +struct XObj; + +#include +#include +using namespace std; + +class StTextFileScanner { +public: + + StTextFileScanner(const char * inFileName, bool skip_blanks); + ~StTextFileScanner(); + + void skip_blanks(bool skip_blanks); + bool done(); + void next(); + string get(); + +private: + + void read_next(void); + + FILE * mFile; + string mBuf; + bool mDone; + bool mSkipBlanks; +}; + +void BreakString(const string& line, vector& words); + +void StringToUpper(string&); + +bool HasExtNoCase(const string& inStr, const char * inExt); + +void ChangePolyCmdCW(XObjCmd& ioCmd); + +bool GetNextNoComments(StTextFileScanner& f, string& s); + +// WARNING: this is a dumb radius, a radius from 0,0,0. It is not +// the radius of a bounding sphere! Why it is in this translation +// unit is also rather questionable. +double GetObjRadius(const XObj& inObj); + +void StripPath(string& ioPath); +void StripPathCP(string& ioPath); +void ExtractPath(string& ioPath); + +int PickRandom(vector& chances); +bool RollDice(double inProb); +double RandRange(double mmin, double mmax); +double RandRangeBias(double mmin, double mmax, double biasRatio, double randomAmount); + +#if APL && !defined(XUTILS_EXCLUDE_MAC_CRAP) + +#include +#include + +void AppPath(string& outString); +OSErr FindSuperFolder(const FSSpec& inItem, FSSpec& outFolder); +void FSSpec_2_String(const FSSpec& inSpec, string& outString); +#endif + +void ExtractFixedRecordString( + const string& inLine, + int inBegin, + int inEnd, + string& outString); + +bool ExtractFixedRecordLong( + const string& inLine, + int inBegin, + int inEnd, + long& outLong); + +bool ExtractFixedRecordUnsignedLong( + const string& inLine, + int inBegin, + int inEnd, + unsigned long& outUnsignedLong); + +class XPointPool { +public: + + XPointPool(); + ~XPointPool(); + void clear(); + int accumulate(const float xyz[3], const float st[2]); + int count(void); + void get(int index, float xyz[3], float st[2]); + +private: + + XPointPool(const XPointPool&); + XPointPool& operator=(const XPointPool&); + + struct XPointPoolImp; + + XPointPoolImp * mImp; + +}; + +void DecomposeObjCmd(const XObjCmd& inCmd, vector& outCmd, int maxValence); +void DecomposeObj(const XObj& inObj, XObj& outObj, int maxValence); + +#endif \ No newline at end of file diff --git a/zconf.h b/zconf.h new file mode 100644 index 000000000..7ada00424 --- /dev/null +++ b/zconf.h @@ -0,0 +1,279 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2002 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.1 2004/04/17 01:09:04 bsupnik Exp $ */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) +# ifndef __32BIT__ +# define __32BIT__ +# endif +#endif +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#if defined(MSDOS) && !defined(__32BIT__) +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) +# define STDC +#endif +#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) +# ifndef STDC +# define STDC +# endif +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Old Borland C incorrectly complains about missing returns: */ +#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) +# define NEED_DUMMY_RETURN +#endif + + +/* 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 */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +#endif +#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) +# ifndef __32BIT__ +# define SMALL_MEDIUM +# define FAR _far +# endif +#endif + +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if defined(ZLIB_DLL) +# if defined(_WINDOWS) || defined(WINDOWS) +# ifdef FAR +# undef FAR +# endif +# include +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR _cdecl _export +# endif +# endif +# if defined (__BORLANDC__) +# if (__BORLANDC__ >= 0x0500) && defined (WIN32) +# include +# define ZEXPORT __declspec(dllexport) WINAPI +# define ZEXPORTRVA __declspec(dllexport) WINAPIV +# else +# if defined (_Windows) && defined (__DLL__) +# define ZEXPORT _export +# define ZEXPORTVA _export +# endif +# endif +# endif +#endif + +#if defined (__BEOS__) +# if defined (ZLIB_DLL) +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +#endif + +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif +#ifndef ZEXTERN +# define ZEXTERN extern +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(MACOS) && !defined(TARGET_OS_MAC) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# define z_off_t off_t +#endif +#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 +#ifndef z_off_t +# define z_off_t long +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(inflate_blocks,"INBL") +# pragma map(inflate_blocks_new,"INBLNE") +# pragma map(inflate_blocks_free,"INBLFR") +# pragma map(inflate_blocks_reset,"INBLRE") +# pragma map(inflate_codes_free,"INCOFR") +# pragma map(inflate_codes,"INCO") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_flush,"INFLU") +# pragma map(inflate_mask,"INMA") +# pragma map(inflate_set_dictionary,"INSEDI2") +# pragma map(inflate_copyright,"INCOPY") +# pragma map(inflate_trees_bits,"INTRBI") +# pragma map(inflate_trees_dynamic,"INTRDY") +# pragma map(inflate_trees_fixed,"INTRFI") +# pragma map(inflate_trees_free,"INTRFR") +#endif + +#endif /* _ZCONF_H */ diff --git a/zlib.h b/zlib.h new file mode 100644 index 000000000..52cb529f6 --- /dev/null +++ b/zlib.h @@ -0,0 +1,893 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.4, March 11th, 2002 + + Copyright (C) 1995-2002 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). +*/ + +#ifndef _ZLIB_H +#define _ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.1.4" + +/* + 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. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + 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 */ + +ZEXTERN const char * ZEXPORT 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. + */ + +/* +ZEXTERN int ZEXPORT 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(). +*/ + + +ZEXTERN int ZEXPORT 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 far (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). +*/ + + +ZEXTERN int ZEXPORT 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). +*/ + + +/* +ZEXTERN int ZEXPORT 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.) +*/ + + +ZEXTERN int ZEXPORT 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 far (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. +*/ + + +ZEXTERN int ZEXPORT 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. +*/ + +/* +ZEXTERN int ZEXPORT 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(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *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(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +/* +ZEXTERN int ZEXPORT 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.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *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(). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *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. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *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. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *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; + +ZEXTERN gzFile ZEXPORT 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). */ + +ZEXTERN gzFile ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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). */ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN int ZEXPORTVA 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). +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN char * ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN int ZEXPORT 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. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t 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. +*/ + +ZEXTERN int ZEXPORT 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) +*/ + +ZEXTERN z_off_t ZEXPORT 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) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT 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). +*/ + +ZEXTERN const char * ZEXPORT 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. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *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(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *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(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT 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)) + + +#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* _ZLIB_H */