Initial commit.

This commit is contained in:
Jim Gray
2013-04-04 14:32:05 -07:00
parent ba5c81da32
commit d71d53e8ec
2180 changed files with 1393544 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
#pragma once
#if !defined(GENERICPARSER2_H_INC)
#define GENERICPARSER2_H_INC
#ifdef DEBUG_LINKING
#pragma message("...including GenericParser2.h")
#endif
#include "disablewarnings.h"
#ifdef USE_LOCAL_GENERICPARSER
#include <memory.h>
#include <malloc.h>
#include <string.h>
#define trap_Z_Malloc(x, y) malloc(x)
#define trap_Z_Free(x) free(x)
#endif
class CTextPool;
class CGPObject;
class CTextPool
{
private:
char *mPool;
CTextPool *mNext;
int mSize, mUsed;
public:
CTextPool(int initSize = 10240);
~CTextPool(void);
CTextPool *GetNext(void) { return mNext; }
void SetNext(CTextPool *which) { mNext = which; }
char *GetPool(void) { return mPool; }
int GetUsed(void) { return mUsed; }
char *AllocText(char *text, bool addNULL = true, CTextPool **poolPtr = 0);
};
void CleanTextPool(CTextPool *pool);
class CGPObject
{
protected:
const char *mName;
CGPObject *mNext, *mInOrderNext, *mInOrderPrevious;
public:
CGPObject(const char *initName);
const char *GetName(void) { return mName; }
CGPObject *GetNext(void) { return mNext; }
void SetNext(CGPObject *which) { mNext = which; }
CGPObject *GetInOrderNext(void) { return mInOrderNext; }
void SetInOrderNext(CGPObject *which) { mInOrderNext = which; }
CGPObject *GetInOrderPrevious(void) { return mInOrderPrevious; }
void SetInOrderPrevious(CGPObject *which) { mInOrderPrevious = which; }
bool WriteText(CTextPool **textPool, const char *text);
};
class CGPValue : public CGPObject
{
private:
CGPObject *mList;
public:
CGPValue(const char *initName, const char *initValue = 0);
~CGPValue(void);
CGPValue *GetNext(void) { return (CGPValue *)mNext; }
CGPValue *Duplicate(CTextPool **textPool = 0);
bool IsList(void);
const char *GetTopValue(void);
CGPObject *GetList(void) { return mList; }
void AddValue(const char *newValue, CTextPool **textPool = 0);
bool Parse(char **dataPtr, CTextPool **textPool);
bool Write(CTextPool **textPool, int depth);
};
class CGPGroup : public CGPObject
{
private:
CGPValue *mPairs, *mInOrderPairs;
CGPValue *mCurrentPair;
CGPGroup *mSubGroups, *mInOrderSubGroups;
CGPGroup *mCurrentSubGroup;
CGPGroup *mParent;
bool mWriteable;
void SortObject(CGPObject *object, CGPObject **unsortedList, CGPObject **sortedList,
CGPObject **lastObject);
public:
CGPGroup(const char *initName = "Top Level", CGPGroup *initParent = 0);
~CGPGroup(void);
CGPGroup *GetNext(void) { return (CGPGroup *)mNext; }
int GetNumSubGroups(void);
int GetNumPairs(void);
void Clean(void);
CGPGroup *Duplicate(CTextPool **textPool = 0, CGPGroup *initParent = 0);
void SetWriteable(const bool writeable) { mWriteable = writeable; }
CGPValue *GetPairs(void) { return mPairs; }
CGPValue *GetInOrderPairs(void) { return mInOrderPairs; }
CGPGroup *GetSubGroups(void) { return mSubGroups; }
CGPGroup *GetInOrderSubGroups(void) { return mInOrderSubGroups; }
CGPValue *AddPair(const char *name, const char *value, CTextPool **textPool = 0);
void AddPair(CGPValue *NewPair);
CGPGroup *AddGroup(const char *name, CTextPool **textPool = 0);
void AddGroup(CGPGroup *NewGroup);
CGPGroup *FindSubGroup(const char *name);
bool Parse(char **dataPtr, CTextPool **textPool);
bool Write(CTextPool **textPool, int depth);
const char *FindPairValue(const char *key, const char *defaultVal = 0);
};
class CGenericParser2
{
private:
CGPGroup mTopLevel;
CTextPool *mTextPool;
bool mWriteable;
public:
CGenericParser2(void);
~CGenericParser2(void);
void SetWriteable(const bool writeable) { mWriteable = writeable; }
CGPGroup *GetBaseParseGroup(void) { return &mTopLevel; }
bool Parse(char **dataPtr, bool cleanFirst = true, bool writeable = false);
bool Parse(char *dataPtr, bool cleanFirst = true, bool writeable = false)
{
return Parse(&dataPtr, cleanFirst, writeable);
}
void Clean(void);
bool Write(CTextPool *textPool);
};
// The following groups of routines are used for a C interface into GP2.
// C++ users should just use the objects as normally and not call these routines below
//
// CGenericParser2 (void *) routines
void *GP_Parse(char **dataPtr, bool cleanFirst, bool writeable);
void GP_Clean(void *GP2);
void GP_Delete(void **GP2);
void *GP_GetBaseParseGroup(void *GP2);
// CGPGroup (void *) routines
const char *GPG_GetName(void *GPG);
void *GPG_GetNext(void *GPG);
void *GPG_GetInOrderNext(void *GPG);
void *GPG_GetInOrderPrevious(void *GPG);
void *GPG_GetPairs(void *GPG);
void *GPG_GetInOrderPairs(void *GPG);
void *GPG_GetSubGroups(void *GPG);
void *GPG_GetInOrderSubGroups(void *GPG);
void *GPG_FindSubGroup(void *GPG, const char *name);
const char *GPG_FindPairValue(void *GPG, const char *key, const char *defaultVal);
// CGPValue (void *) routines
const char *GPV_GetName(void *GPV);
void *GPV_GetNext(void *GPV);
void *GPV_GetInOrderNext(void *GPV);
void *GPV_GetInOrderPrevious(void *GPV);
bool GPV_IsList(void *GPV);
const char *GPV_GetTopValue(void *GPV);
void *GPV_GetList(void *GPV);
#endif // GENERICPARSER2_H_INC

998
tools/ModView/ModView.dsp Normal file
View File

@@ -0,0 +1,998 @@
# Microsoft Developer Studio Project File - Name="ModView" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 60000
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=ModView - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "ModView.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "ModView.mak" CFG="ModView - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "ModView - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "ModView - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/Tools/ModView", NYDCAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "ModView - Win32 Release"
# PROP BASE Use_MFC 5
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 5
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /D "NDEBUG" /D "_MODVIEW" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /FR /Yu"stdafx.h" /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
# ADD LINK32 opengl32.lib glu32.lib winmm.lib /nologo /subsystem:windows /debug /machine:I386
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# PROP BASE Use_MFC 5
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 5
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "_MODVIEW" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /FR /Yu"stdafx.h" /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 opengl32.lib glu32.lib winmm.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "ModView - Win32 Release"
# Name "ModView - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\anims.cpp
# End Source File
# Begin Source File
SOURCE=.\clipboard.cpp
# End Source File
# Begin Source File
SOURCE=.\CommArea.cpp
# End Source File
# Begin Source File
SOURCE=.\drag.cpp
# End Source File
# Begin Source File
SOURCE=.\generic_stuff.cpp
# End Source File
# Begin Source File
SOURCE=.\GetString.cpp
# End Source File
# Begin Source File
SOURCE=.\gl_bits.cpp
# End Source File
# Begin Source File
SOURCE=.\glm_code.cpp
# End Source File
# Begin Source File
SOURCE=.\image.cpp
# End Source File
# Begin Source File
SOURCE=.\jpeg_interface.cpp
# End Source File
# Begin Source File
SOURCE=.\MainFrm.cpp
# End Source File
# Begin Source File
SOURCE=.\matcomp.cpp
# End Source File
# Begin Source File
SOURCE=.\mc_compress2.cpp
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\model.cpp
# End Source File
# Begin Source File
SOURCE=.\ModView.cpp
# End Source File
# Begin Source File
SOURCE=.\ModView.rc
# End Source File
# Begin Source File
SOURCE=.\ModViewDoc.cpp
# End Source File
# Begin Source File
SOURCE=.\ModViewTreeView.cpp
# End Source File
# Begin Source File
SOURCE=.\ModViewView.cpp
# End Source File
# Begin Source File
SOURCE=.\oldskins.cpp
# End Source File
# Begin Source File
SOURCE=.\parser.cpp
# End Source File
# Begin Source File
SOURCE=.\R_GLM.cpp
# End Source File
# Begin Source File
SOURCE=.\R_Image.cpp
# End Source File
# Begin Source File
SOURCE=.\R_MD3.cpp
# End Source File
# Begin Source File
SOURCE=.\R_MDR.cpp
# End Source File
# Begin Source File
SOURCE=.\R_Model.cpp
# End Source File
# Begin Source File
SOURCE=.\R_Surface.cpp
# End Source File
# Begin Source File
SOURCE=.\script.cpp
# End Source File
# Begin Source File
SOURCE=.\sequence.cpp
# End Source File
# Begin Source File
SOURCE=.\shader.cpp
# End Source File
# Begin Source File
SOURCE=.\skins.cpp
# End Source File
# Begin Source File
SOURCE=.\SOF2NPCViewer.cpp
# End Source File
# Begin Source File
SOURCE=.\Splash.cpp
# End Source File
# Begin Source File
SOURCE=.\StdAfx.cpp
# ADD CPP /Yc"stdafx.h"
# End Source File
# Begin Source File
SOURCE=.\TEXT.CPP
# End Source File
# Begin Source File
SOURCE=.\Textures.cpp
# End Source File
# Begin Source File
SOURCE=.\wintalk.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\anims.h
# End Source File
# Begin Source File
SOURCE=.\clipboard.h
# End Source File
# Begin Source File
SOURCE=.\CommArea.h
# End Source File
# Begin Source File
SOURCE=.\drag.h
# End Source File
# Begin Source File
SOURCE=.\generic_stuff.h
# End Source File
# Begin Source File
SOURCE=.\GetString.h
# End Source File
# Begin Source File
SOURCE=.\gl_bits.h
# End Source File
# Begin Source File
SOURCE=.\glm_code.h
# End Source File
# Begin Source File
SOURCE=.\image.h
# End Source File
# Begin Source File
SOURCE=.\includes.h
# End Source File
# Begin Source File
SOURCE=.\jpeg_interface.h
# End Source File
# Begin Source File
SOURCE=.\MainFrm.h
# End Source File
# Begin Source File
SOURCE=.\matcomp.h
# End Source File
# Begin Source File
SOURCE=.\mc_compress2.h
# End Source File
# Begin Source File
SOURCE=.\md3_format.h
# End Source File
# Begin Source File
SOURCE=.\mdr_format.h
# End Source File
# Begin Source File
SOURCE=.\mdx_format.h
# End Source File
# Begin Source File
SOURCE=.\model.h
# End Source File
# Begin Source File
SOURCE=.\ModView.h
# End Source File
# Begin Source File
SOURCE=.\ModViewDoc.h
# End Source File
# Begin Source File
SOURCE=.\ModViewTreeView.h
# End Source File
# Begin Source File
SOURCE=.\ModViewView.h
# End Source File
# Begin Source File
SOURCE=.\oldskins.h
# End Source File
# Begin Source File
SOURCE=.\parser.h
# End Source File
# Begin Source File
SOURCE=.\R_Common.h
# End Source File
# Begin Source File
SOURCE=.\R_GLM.h
# End Source File
# Begin Source File
SOURCE=.\R_Image.h
# End Source File
# Begin Source File
SOURCE=.\R_MD3.h
# End Source File
# Begin Source File
SOURCE=.\R_MDR.h
# End Source File
# Begin Source File
SOURCE=.\R_Model.h
# End Source File
# Begin Source File
SOURCE=.\R_Surface.h
# End Source File
# Begin Source File
SOURCE=.\Resource.h
# End Source File
# Begin Source File
SOURCE=.\script.h
# End Source File
# Begin Source File
SOURCE=.\sequence.h
# End Source File
# Begin Source File
SOURCE=.\shader.h
# End Source File
# Begin Source File
SOURCE=.\skins.h
# End Source File
# Begin Source File
SOURCE=.\SOF2NPCViewer.h
# End Source File
# Begin Source File
SOURCE=.\special_defines.h
# End Source File
# Begin Source File
SOURCE=.\Splash.h
# End Source File
# Begin Source File
SOURCE=.\StdAfx.h
# End Source File
# Begin Source File
SOURCE=.\stl.h
# End Source File
# Begin Source File
SOURCE=.\TEXT.H
# End Source File
# Begin Source File
SOURCE=.\textures.h
# End Source File
# Begin Source File
SOURCE=.\todo.h
# End Source File
# Begin Source File
SOURCE=.\wintalk.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\res\ModView.ico
# End Source File
# Begin Source File
SOURCE=.\res\ModView.rc2
# End Source File
# Begin Source File
SOURCE=.\res\ModViewDoc.ico
# End Source File
# Begin Source File
SOURCE=.\Splsh16.bmp
# End Source File
# Begin Source File
SOURCE=.\res\Toolbar.bmp
# End Source File
# End Group
# Begin Group "JPEG Source"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\jpeg6\jcomapi.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdapimin.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdapistd.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdatasrc.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdcoefct.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdcolor.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jddctmgr.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdhuff.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdinput.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdmainct.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdmarker.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdmaster.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdpostct.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdsample.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdtrans.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jerror.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jidctflt.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jmemmgr.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jmemnobs.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jutils.c
!IF "$(CFG)" == "ModView - Win32 Release"
# ADD CPP /FR
# SUBTRACT CPP /YX /Yc /Yu
!ELSEIF "$(CFG)" == "ModView - Win32 Debug"
# ADD CPP /Fr
# SUBTRACT CPP /YX /Yc /Yu
!ENDIF
# End Source File
# End Group
# Begin Group "JPEG Headers"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\jpeg6\jconfig.h
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdct.h
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jdhuff.h
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jerror.h
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jinclude.h
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jmemsys.h
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jmorecfg.h
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jpegint.h
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jpeglib.h
# End Source File
# Begin Source File
SOURCE=.\jpeg6\jversion.h
# End Source File
# End Group
# Begin Group "PNG"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\png\png.cpp
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\png\png.h
# End Source File
# End Group
# Begin Group "ZLIB"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\zlib\adler32.c
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\crc32.cpp
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\deflate.c
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\deflate.h
# End Source File
# Begin Source File
SOURCE=.\zlib\infblock.c
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\infblock.h
# End Source File
# Begin Source File
SOURCE=.\zlib\infcodes.c
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\infcodes.h
# End Source File
# Begin Source File
SOURCE=.\zlib\inffast.c
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\inffast.h
# End Source File
# Begin Source File
SOURCE=.\zlib\inffixed.h
# End Source File
# Begin Source File
SOURCE=.\zlib\inflate.c
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\inftrees.c
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\inftrees.h
# End Source File
# Begin Source File
SOURCE=.\zlib\infutil.c
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\infutil.h
# End Source File
# Begin Source File
SOURCE=.\zlib\trees.c
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\trees.h
# End Source File
# Begin Source File
SOURCE=.\zlib\zconf.h
# End Source File
# Begin Source File
SOURCE=.\zlib\zlib.h
# End Source File
# Begin Source File
SOURCE=.\zlib\zutil.c
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\zlib\zutil.h
# End Source File
# End Group
# Begin Group "Foreign Muck Source"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\files.cpp
# End Source File
# Begin Source File
SOURCE=.\GenericParser2.cpp
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# End Group
# Begin Group "Foreign Muck Headers"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\common_headers.h
# End Source File
# Begin Source File
SOURCE=.\disablewarnings.h
# End Source File
# Begin Source File
SOURCE=.\files.h
# End Source File
# Begin Source File
SOURCE=.\GenericParser2.h
# End Source File
# End Group
# Begin Source File
SOURCE=.\ReadMe.txt
# End Source File
# End Target
# End Project
# Section ModView : {72ADFD78-2C39-11D0-9903-00A0C91BC942}
# 1:10:IDB_SPLASH:102
# 2:21:SplashScreenInsertKey:4.0
# End Section

37
tools/ModView/ModView.dsw Normal file
View File

@@ -0,0 +1,37 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "ModView"=.\ModView.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/Tools/ModView", NYDCAAAA
.
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
begin source code control
"$/Tools/ModView", NYDCAAAA
.
end source code control
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@@ -0,0 +1 @@
Microsoft C/C++ MSF 7.00

21
tools/ModView/ModView.sln Normal file
View File

@@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 7.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModView", "ModView.vcproj", "{46983300-8605-4618-8A33-AA2205010989}"
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
ConfigName.0 = Debug
ConfigName.1 = Release
EndGlobalSection
GlobalSection(ProjectDependencies) = postSolution
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{46983300-8605-4618-8A33-AA2205010989}.Debug.ActiveCfg = Debug|Win32
{46983300-8605-4618-8A33-AA2205010989}.Debug.Build.0 = Debug|Win32
{46983300-8605-4618-8A33-AA2205010989}.Release.ActiveCfg = Release|Win32
{46983300-8605-4618-8A33-AA2205010989}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

1078
tools/ModView/ModView.vcproj Normal file

File diff suppressed because it is too large Load Diff

172
tools/ModView/Splash.cpp Normal file
View File

@@ -0,0 +1,172 @@
// CG: This file was added by the Splash Screen component.
// Splash.cpp : implementation file
//
#include "stdafx.h" // e. g. stdafx.h
#include "resource.h" // e.g. resource.h
#include "Splash.h" // e.g. splash.h
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Splash Screen class
BOOL CSplashWnd::c_bShowSplashWnd;
CSplashWnd* CSplashWnd::c_pSplashWnd;
CSplashWnd::CSplashWnd()
{
}
CSplashWnd::~CSplashWnd()
{
// Clear the static window pointer.
ASSERT(c_pSplashWnd == this);
c_pSplashWnd = NULL;
}
BEGIN_MESSAGE_MAP(CSplashWnd, CWnd)
//{{AFX_MSG_MAP(CSplashWnd)
ON_WM_CREATE()
ON_WM_PAINT()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// the default string here was just centred by eye, if it gets changed it'll need adjusting to fit the box centre...
//
#define SPLASH_DEFAULT_TEXT " ( Wait... )"
bool gbSplashScreenRunning = false;
bool gbSplashNotNeededByApp = false;
bool gbSplashScreenNotNeededByTimer = false;
CString strSplashText = SPLASH_DEFAULT_TEXT;
void CSplashWnd::StatusMessage(LPCSTR psMessage) // can be NULL for "not bothered"
{
strSplashText = psMessage ? psMessage : SPLASH_DEFAULT_TEXT;
strSplashText.TrimRight(); // remove trailing CRs which show up as black marks
c_pSplashWnd->RedrawWindow();
}
void CSplashWnd::EnableSplashScreen(BOOL bEnable /*= TRUE*/)
{
c_bShowSplashWnd = bEnable;
}
void CSplashWnd::ShowSplashScreen(CWnd* pParentWnd /*= NULL*/)
{
if (!c_bShowSplashWnd || c_pSplashWnd != NULL)
return;
// Allocate a new splash screen, and create the window.
c_pSplashWnd = new CSplashWnd;
if (!c_pSplashWnd->Create(pParentWnd))
delete c_pSplashWnd;
else
c_pSplashWnd->UpdateWindow();
}
BOOL CSplashWnd::PreTranslateAppMessage(MSG* pMsg)
{
if (c_pSplashWnd == NULL)
return FALSE;
/*
// If we get a keyboard or mouse message, hide the splash screen.
if (pMsg->message == WM_KEYDOWN ||
pMsg->message == WM_SYSKEYDOWN ||
pMsg->message == WM_LBUTTONDOWN ||
pMsg->message == WM_RBUTTONDOWN ||
pMsg->message == WM_MBUTTONDOWN ||
pMsg->message == WM_NCLBUTTONDOWN ||
pMsg->message == WM_NCRBUTTONDOWN ||
pMsg->message == WM_NCMBUTTONDOWN)
{
c_pSplashWnd->HideSplashScreen(false);
return TRUE; // message handled here
}
*/
return FALSE; // message not handled
}
BOOL CSplashWnd::Create(CWnd* pParentWnd /*= NULL*/)
{
if (!m_bitmap.LoadBitmap(IDB_SPLASH))
return FALSE;
BITMAP bm;
m_bitmap.GetBitmap(&bm);
return CreateEx(0,
AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
NULL, WS_POPUP | WS_VISIBLE, 0, 0, bm.bmWidth, bm.bmHeight, pParentWnd->GetSafeHwnd(), NULL);
}
void CSplashWnd::HideSplashScreen(bool bCalledFromApp)
{
if (bCalledFromApp)
{
gbSplashNotNeededByApp = true;
return;
}
if (gbSplashNotNeededByApp && gbSplashScreenNotNeededByTimer)
{
// Destroy the window, and update the mainframe.
c_pSplashWnd->DestroyWindow();
AfxGetMainWnd()->UpdateWindow();
}
}
void CSplashWnd::PostNcDestroy()
{
// Free the C++ class.
delete this;
gbSplashScreenRunning = false;
}
int CSplashWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// Center the window.
CenterWindow();
// Set a timer to destroy the splash screen.
SetTimer(1, 1000, NULL);
gbSplashScreenRunning = true;
return 0;
}
void CSplashWnd::OnPaint()
{
CPaintDC dc(this);
CDC dcImage;
if (!dcImage.CreateCompatibleDC(&dc))
return;
BITMAP bm;
m_bitmap.GetBitmap(&bm);
// Paint the image.
CBitmap* pOldBitmap = dcImage.SelectObject(&m_bitmap);
dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCCOPY);
dcImage.SelectObject(pOldBitmap);
dc.TextOut(58/*bm.bmWidth/2*/,180/*bm.bmHeight/2*/, strSplashText);
}
void CSplashWnd::OnTimer(UINT nIDEvent)
{
gbSplashScreenNotNeededByTimer = true;
HideSplashScreen(false);
}

57
tools/ModView/Splash.h Normal file
View File

@@ -0,0 +1,57 @@
// CG: This file was added by the Splash Screen component.
#ifndef _SPLASH_SCRN_
#define _SPLASH_SCRN_
// Splash.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// Splash Screen class
class CSplashWnd : public CWnd
{
// Construction
protected:
CSplashWnd();
// Attributes:
public:
CBitmap m_bitmap;
// Operations
public:
static void EnableSplashScreen(BOOL bEnable = TRUE);
static void ShowSplashScreen(CWnd* pParentWnd = NULL);
static BOOL PreTranslateAppMessage(MSG* pMsg);
static void StatusMessage(LPCSTR psMessage);
static void HideSplashScreen(bool bCalledFromApp);
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSplashWnd)
//}}AFX_VIRTUAL
// Implementation
public:
~CSplashWnd();
virtual void PostNcDestroy();
protected:
BOOL Create(CWnd* pParentWnd = NULL);
static BOOL c_bShowSplashWnd;
static CSplashWnd* c_pSplashWnd;
// Generated message map functions
protected:
//{{AFX_MSG(CSplashWnd)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnPaint();
afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#endif

BIN
tools/ModView/Splsh16.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View File

View File

414
tools/ModView/anims.cpp Normal file
View File

@@ -0,0 +1,414 @@
// Filename:- anims.cpp
//
// Module to read basic animation-description files...
//
// Currently reads either "<name>.frames" and/or "animtion.cfg" files...
//
#include "stdafx.h"
#include "includes.h"
//
#include "sequence.h"
//
#include "anims.h"
bool Anims_ReadFile_FRAMES(ModelContainer_t *pContainer, LPCSTR psLocalFilename_GLA)
{
LPCSTR psFilename = va("%s%s.frames",gamedir,Filename_WithoutExt(psLocalFilename_GLA));
FILE *fHandle = fopen(psFilename,"rt");
if (fHandle)
{
// file format is like this per XSI...
//
// models/test/m4/m44keith.xsi
// {
// startframe "0"
// duration "2"
// }
//
// so...
Sequence_t Sequence;
bool bStartFrameRead = false;
bool bDurationRead = false;
bool bFPSRead = false;
char sLine[1024];
while (fgets(sLine,sizeof(sLine)-1,fHandle)!=NULL)
{
if (bStartFrameRead && bDurationRead && bFPSRead)
{
pContainer->SequenceList.push_back(Sequence);
bStartFrameRead = false;
bDurationRead = false;
bFPSRead = false;
}
sLine[sizeof(sLine)-1]='\0';
strlwr(sLine);
// :-)
CString str(sLine);
str.TrimLeft();
str.TrimRight();
str.Replace("\"","");
strcpy(sLine,str);
if (strstr(sLine,".xsi"))
{
Sequence_Clear(&Sequence);
strcpy(Sequence.sName,Filename_WithoutPath(Filename_WithoutExt(sLine)));
// these can be really long...
strncpy(Sequence.sNameWithPath,Filename_WithoutExt(sLine),sizeof(Sequence.sNameWithPath));
Sequence.sNameWithPath[sizeof(Sequence.sNameWithPath)-1]='\0';
}
else
if (strnicmp(sLine,"startframe",strlen("startframe"))==0)
{
CString str(&sLine[strlen("startframe")]);
str.Replace("\"","");
Sequence.iStartFrame = atoi(str);
bStartFrameRead = true;
}
else
if (strnicmp(sLine,"duration",strlen("duration"))==0)
{
CString str(&sLine[strlen("duration")]);
str.Replace("\"","");
Sequence.iFrameCount = atoi(str);
bDurationRead = true;
}
else
if (strnicmp(sLine,"fps",strlen("fps"))==0)
{
CString str(&sLine[strlen("fps")]);
str.Replace("\"","");
Sequence.iFPS = atoi(str);
bFPSRead = true;
}
}
fclose(fHandle);
}
return !!(pContainer->SequenceList.size());
}
// Code pasted from MD3View and hacked about a bit..............
//
// this has now been re-written to only add to pulldown menus when all menus have been scanned, this way
// I can strcat frame info to the seq names while keeping a smooth tabbing line...
//
// Note that this function can automatically read either ID format or Raven format files transparently...
//
/*
typedef struct
{
string sName;
int iStartFrame;
int iFrameCount;
int iLoopFrame;
int iFrameSpeed;
bool bMultiSeq;
} Sequence_t;
*/
/*
typedef struct
{
char sName[MAX_QPATH]; // eg "run1"
int iStartFrame;
int iFrameCount;
int iLoopFrame; // -1 for no wrap, else framenum to add to iStartFrame
// int iFrameSpeed;
// bool bMultiSeq;
bool bIsDefault; // only true if no anim/enum file found
} Sequence_t;
*/
static bool LoadAnimationCFG(LPCSTR psFullPath, ModelContainer_t *pContainer, FILE *handle)//, HDC hDC) // hDC for text metrics
{
// int iLongestTextMetric = 0;
// SIZE Size;
bool bOk = false;
// FILE *handle = fopen(psFullPath,"rt");
if (handle)
{
static char sLineBuffer[2048];
int iFirstFrameAfterBoth = -1; // stuff I need to do for ID's non-folded frame numbers
int iFirstFrameAfterTorso= -1;
while (1)
{
ZEROMEM(sLineBuffer);
if (!fgets(sLineBuffer,sizeof(sLineBuffer),handle))
{
if (ferror(handle))
{
ErrorBox(va("Error while reading \"%s\"!",psFullPath));
// ClearAnimationCFG();
}
break; // whether error or EOF
}
char sComment[2048] = {0}; // keep comments now because of the way ID cfg files work
// zap any comments...
//
char *p = strstr(sLineBuffer,"//");
if (p)
{
strcpy(sComment,p+2);
*p=0;
}
// update, to read ID cfg files, we need to skip over some stuff that Raven ones don't have...
//
// our cfg files don't have "sex" (how depressingly apt...)
//
if (strnicmp(sLineBuffer,"sex",3)==0)
continue;
//
// or this other crap either...
//
if (strnicmp(sLineBuffer,"footsteps",9)==0)
continue;
if (strnicmp(sLineBuffer,"headoffset",10)==0)
continue;
if (strnicmp(sLineBuffer,"soundpath",9)==0)
continue;
Sequence_t seq;
memset(&seq,0,sizeof(seq));
char sLine[2048];
int iElementsDone = sscanf( sLineBuffer, "%s %d %d %d %d", &sLine, &seq.iStartFrame, &seq.iFrameCount, &seq.iLoopFrame, &seq.iFPS );
if (iElementsDone == EOF)
continue; // probably skipping over a comment line
bool bElementsScannedOk = false;
if (iElementsDone == 5)
{
// then it must be a Raven line...
//
bElementsScannedOk = true;
// mdview.bAnimIsMultiPlayerFormat = false;
}
else
{
// try scanning it as an ID line...
//
iElementsDone = sscanf( sLineBuffer, "%d %d %d %d", &seq.iStartFrame, &seq.iFrameCount, &seq.iLoopFrame, &seq.iFPS );
if (iElementsDone == 4)
{
// mdview.bAnimIsMultiPlayerFormat = true;
// scanned an ID line in ok, now convert it to Raven format...
//
iElementsDone = sscanf( sComment, "%s", &sLine ); // grab anim name from original saved comment
if (iElementsDone == 1)
{
// ... and convert their loop format to ours...
//
if (seq.iLoopFrame == 0)
{
seq.iLoopFrame = -1;
}
else
{
seq.iLoopFrame = seq.iFrameCount - seq.iLoopFrame;
}
// now do the folding number stuff since ID don't do it in their files...
//
if ( !strnicmp(sLine,"TORSO_",6) && iFirstFrameAfterBoth == -1)
{
iFirstFrameAfterBoth = seq.iStartFrame;
}
if ( !strnicmp(sLine,"LEGS_",5))
{
if (iFirstFrameAfterTorso == -1)
{
iFirstFrameAfterTorso = seq.iStartFrame;
}
// now correct the leg framenumber...
//
if (iFirstFrameAfterBoth != -1) // if it did, then there'd be no torso frames, so no adj nec.
{
seq.iStartFrame -= (iFirstFrameAfterTorso - iFirstFrameAfterBoth);
}
}
bElementsScannedOk = true;
}
}
}
if (bElementsScannedOk)
{
strcpy(seq.sName,sLine);//seq.sName = sLine;
pContainer->SequenceList.push_back(seq);
//
// this line seems to be ok...
//
// OutputDebugString(va("%s %d %d %d %d\n",seq.sName.c_str(), seq.iStartFrame, seq.iFrameCount, seq.iLoopFrame, seq.iFrameSpeed ));
// "both" or "torso" get added to 'upper' menu...
//
/* if ( (!strnicmp(seq.sName.c_str(),"BOTH_",5)) || (!strnicmp(seq.sName.c_str(),"TORSO_",6)) )
{
Sequences_UpperAnims.push_back(seq);
if (iAnimLockLongestString < strlen(seq.sName.c_str()))
iAnimLockLongestString = strlen(seq.sName.c_str());
if (GetTextExtentPoint( hDC, // HDC hdc, // handle to device context
seq.sName.c_str(), // LPCTSTR lpString, // pointer to text string
strlen(seq.sName.c_str()), // int cbString, // number of characters in string
&Size // LPSIZE lpSize // pointer to structure for string size
)
)
{
if (iLongestTextMetric < Size.cx)
iLongestTextMetric = Size.cx;
}
// Menu_UpperAnims_AddItem(seq.sName.c_str());
}
// "both" or "legs" get added to 'lower' menu...
//
if ( (!strnicmp(seq.sName.c_str(),"BOTH_",5)) || (!strnicmp(seq.sName.c_str(),"LEGS_",5)) )
{
Sequences_LowerAnims.push_back(seq);
if (iAnimLockLongestString < strlen(seq.sName.c_str()))
iAnimLockLongestString = strlen(seq.sName.c_str());
if (GetTextExtentPoint( hDC, // HDC hdc, // handle to device context
seq.sName.c_str(), // LPCTSTR lpString, // pointer to text string
strlen(seq.sName.c_str()), // int cbString, // number of characters in string
&Size // LPSIZE lpSize // pointer to structure for string size
)
)
{
if (iLongestTextMetric < Size.cx)
iLongestTextMetric = Size.cx;
}
// Menu_LowerAnims_AddItem(seq.sName.c_str());
}
*/
}
else
{
// so do we report this as an error or what?
//
ErrorBox(sLineBuffer);
}
}
fclose(handle);
/*
// now add to menus... (this code is awful, it was simple at first then mutated with feature-add)
//
char sLine[2048];
vector< Sequence_t >::iterator it;
for (it=Sequences_UpperAnims.begin(); it!=Sequences_UpperAnims.end(); it++)
{
sprintf(sLine,(*it).sName.c_str());
while (1)
{
GetTextExtentPoint( hDC, // HDC hdc, // handle to device context
sLine, // LPCTSTR lpString, // pointer to text string
strlen(sLine), // int cbString, // number of characters in string
&Size // LPSIZE lpSize // pointer to structure for string size
);
if (Size.cx >= iLongestTextMetric)
break;
strcat(sLine," ");
}
Menu_UpperAnims_AddItem(va("%s (%d...%d)%s",sLine,(*it).iStartFrame,((*it).iStartFrame+(*it).iFrameCount)-1,((*it).iLoopFrame==-1)?"":va(" Loop %d",(*it).iStartFrame+(*it).iLoopFrame)));
}
for (it=Sequences_LowerAnims.begin(); it!=Sequences_LowerAnims.end(); it++)
{
sprintf(sLine,(*it).sName.c_str());
while (1)
{
GetTextExtentPoint( hDC, // HDC hdc, // handle to device context
sLine, // LPCTSTR lpString, // pointer to text string
strlen(sLine), // int cbString, // number of characters in string
&Size // LPSIZE lpSize // pointer to structure for string size
);
if (Size.cx >= iLongestTextMetric)
break;
strcat(sLine," ");
}
Menu_LowerAnims_AddItem(va("%s (%d...%d)%s",sLine,(*it).iStartFrame,((*it).iStartFrame+(*it).iFrameCount)-1,((*it).iLoopFrame==-1)?"":va(" Loop %d",(*it).iStartFrame+(*it).iLoopFrame)));
}
*/
/*
// a bit of sanity checking, to cope with something Bob tried to do... :-)
//
Sequence_t* pSeq = NULL;
gl_model* pModel;
if ((pModel = pModel_Lower)!=0)
{
pSeq = Animation_GetLowerSequence(Animation_GetNumLowerSequences()-1);
ReportFrameMismatches(pSeq,pModel);
}
if ((pModel = pModel_Upper)!=0)
{
pSeq = Animation_GetUpperSequence(Animation_GetNumUpperSequences()-1);
ReportFrameMismatches(pSeq,pModel);
}
*/
}
//return bOk;
return !!(pContainer->SequenceList.size());
}
bool Anims_ReadFile_ANIMATION_CFG(ModelContainer_t *pContainer, LPCSTR psLocalFilename_GLA)
{
LPCSTR psFilename = va("%s%s/animation.cfg",gamedir,Filename_PathOnly(psLocalFilename_GLA));
FILE *fHandle = fopen(psFilename,"rt");
if (fHandle)
{
if (LoadAnimationCFG(psFilename, pContainer, fHandle))
{
//
}
fclose(fHandle);
}
return !!(pContainer->SequenceList.size());
}

16
tools/ModView/anims.h Normal file
View File

@@ -0,0 +1,16 @@
// Filename:- anims.h
//
#ifndef ANIMS_H
#define ANIMS_H
bool Anims_ReadFile_ANIMATION_CFG(ModelContainer_t *pContainer, LPCSTR psLocalFilename_GLA);
bool Anims_ReadFile_FRAMES (ModelContainer_t *pContainer, LPCSTR psLocalFilename_GLA);
#endif // #ifndef ANIMS_H
///////////////// eof /////////////

437
tools/ModView/clipboard.cpp Normal file
View File

@@ -0,0 +1,437 @@
// Filename:- clipboard.cpp
//
#include "stdafx.h"
#include "includes.h"
//#include <windows.h>
//#include <stdio.h>
//#include <assert.h>
//#include "oddbits.h"
#include "text.h"
//
#include "clipboard.h"
#define APP_HWND AppVars.hWnd
BOOL ClipBoard_SendDIB(LPVOID pvData, int iBytes)
{
HGLOBAL hXferBuffer = GlobalAlloc((UINT)GMEM_MOVEABLE|GMEM_DDESHARE,(DWORD)iBytes);
if (hXferBuffer)
{
char *psLockedDest = (char*) GlobalLock(hXferBuffer);
memcpy(psLockedDest,pvData,iBytes);
GlobalUnlock(psLockedDest);
if (OpenClipboard(APP_HWND))
{
EmptyClipboard(); // empty it (all handles to NULL);
if((SetClipboardData((UINT)CF_DIB,hXferBuffer))==NULL)
{
CloseClipboard();
ErrorBox("ClipBoard_SendDIB(): Dammit, some sort of problem writing to the clipboard...");
return FALSE; // hmmmm... Oh well.
}
CloseClipboard();
return TRUE;
}
}
ErrorBox(va("ClipBoard_SendDIB(): Dammit, I can't allocate %d bytes for some strange reason (reboot, then try again, else tell me - Ste)",iBytes));
return FALSE;
}
BOOL Clipboard_SendString(LPCSTR psString)
{
HGLOBAL hXferBuffer = GlobalAlloc((UINT)GMEM_MOVEABLE|GMEM_DDESHARE,(DWORD)strlen(psString)+1);
if (hXferBuffer)
{
char *psLockedDest = (char*) GlobalLock(hXferBuffer);
memcpy(psLockedDest,psString,strlen(psString)+1);
GlobalUnlock(psLockedDest);
if (OpenClipboard(APP_HWND))
{
EmptyClipboard(); // empty it (all handles to NULL);
if((SetClipboardData((UINT)CF_TEXT,hXferBuffer))==NULL)
{
CloseClipboard();
ErrorBox("Clipboard_SendString(): Dammit, some sort of problem writing to the clipboard...");
return FALSE; // hmmmm... Oh well.
}
CloseClipboard();
return TRUE;
}
}
ErrorBox(va("Clipboard_SendString(): Dammit, I can't allocate %d bytes for some strange reason (reboot, then try again, else tell me - Ste)",strlen(psString)+1));
return FALSE;
}
////////////////////////////////////////////////////////////////////////
//
// from this point on is a bunch of crap that's not strictly clipboard stuff,
// but is used only in conjunction with it and therefore may as well go here.
//
// This also includes another some more BMP code. This is here purely because
// we need to be able to write BMPs, not just read them as the other code does...
//
#include <pshpack1.h>
typedef struct
{
BYTE r,g,b; // R&B different order to windoze's RGBTRIPLE struct
} GLRGBBYTES,*LPGLRGBBYTES;
#include <poppack.h>
typedef struct
{
BITMAPINFOHEADER BMPInfoHeader;
RGBTRIPLE RGBData[1]; // a label just for addressing purposes, the actual array size depends on screen dims
} MEMORYBMP, *PMEMORYBMP;
static bool BMP_FlipTrueColour(LPCSTR psFilename);
static int iBMP_PixelWriteOffset;
static PMEMORYBMP pBMP = NULL;
static int iBMP_MallocSize;
//
static FILE *fhBMP = 0;
bool BMP_GetMemDIB(void *&pvAddress, int &iBytes)
{
if (pBMP)
{
pvAddress = pBMP;
iBytes = iBMP_MallocSize;
return true;
}
return false;
}
void BMP_Free(void)
{
if (pBMP)
{
free(pBMP);
pBMP = NULL;
}
}
// open 24-bit RGB file either to disk or memory
//
// if psFileName == NULL, open memory file instead
//
static bool BMP_Open(LPCSTR psFilename, int iWidth, int iHeight)
{
BITMAPFILEHEADER BMPFileHeader;
BITMAPINFOHEADER BMPInfoHeader;
int iPadBytes = (4-((iWidth * sizeof(RGBTRIPLE))%4))&3;
int iWidthBytes = (iWidth * sizeof(RGBTRIPLE))+iPadBytes;
BMP_Free();
fhBMP = NULL;
if (psFilename)
{
extern void CreatePath (const char *path);
CreatePath(psFilename);
fhBMP = fopen(psFilename,"wb");
if (!(int)fhBMP)
return false;
}
else
{
iBMP_MallocSize = sizeof(BITMAPINFOHEADER) + (iWidthBytes * iHeight);
pBMP = (PMEMORYBMP) malloc ( iBMP_MallocSize );
if (!pBMP)
return false;
}
memset(&BMPFileHeader, 0, sizeof(BITMAPFILEHEADER));
BMPFileHeader.bfType=(WORD)('B'+256*'M');
// int iPad= ((sizeof(RGBTRIPLE)*iWidth)%3)*iHeight;
// BMPFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+(sizeof(RGBTRIPLE)*iWidth*iHeight);//+iPad;
BMPFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+(iWidthBytes * iHeight);
BMPFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); // No palette
if (fhBMP)
{
fwrite (&BMPFileHeader,sizeof(BMPFileHeader),1,fhBMP);
}
else
{
// memory version doesn't use the BITMAPFILEHEADER structure
}
memset(&BMPInfoHeader, 0, sizeof(BITMAPINFOHEADER));
BMPInfoHeader.biSize=sizeof(BITMAPINFOHEADER);
BMPInfoHeader.biWidth=iWidth;
BMPInfoHeader.biHeight=iHeight;
BMPInfoHeader.biPlanes=1;
BMPInfoHeader.biBitCount=24;
BMPInfoHeader.biCompression=BI_RGB;
BMPInfoHeader.biSizeImage=0;// BMPFileHeader.bfSize - (sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)); // allowed for BI_RGB bitmaps
BMPInfoHeader.biXPelsPerMeter=0; // don't know about these
BMPInfoHeader.biYPelsPerMeter=0;
BMPInfoHeader.biClrUsed=0;
BMPInfoHeader.biClrImportant=0;
if (fhBMP)
{
fwrite (&BMPInfoHeader,sizeof(BMPInfoHeader),1,fhBMP);
}
else
{
pBMP->BMPInfoHeader = BMPInfoHeader; // struct copy
iBMP_PixelWriteOffset = 0;
}
return true;
}
static bool BMP_WritePixel(byte Red, byte Green, byte Blue)
{
RGBTRIPLE Trip = {0,0,0};
Trip.rgbtRed = Red;
Trip.rgbtGreen = Green;
Trip.rgbtBlue = Blue;
if (fhBMP)
{
fwrite(&Trip, sizeof(RGBTRIPLE), 1, fhBMP);
}
else
{
RGBTRIPLE *pDest = (RGBTRIPLE *) ((byte *)pBMP->RGBData + iBMP_PixelWriteOffset);
*pDest = Trip;
iBMP_PixelWriteOffset += sizeof(RGBTRIPLE);
}
return true;
}
// BMP files need padding to 4-byte boundarys after writing each scan line... (which sucks, and messes up pixel indexing)
//
static bool BMP_WriteLinePadding(int iPixelsPerLine)
{
static char cPad[4]={0};
int iPadBytes = (4-((iPixelsPerLine * sizeof(RGBTRIPLE))%4))&3;
if (iPadBytes)
{
if (fhBMP)
{
fwrite( &cPad, iPadBytes, 1, fhBMP);
}
else
{
iBMP_PixelWriteOffset += iPadBytes; // <g>, can't be bothered padding with zeroes
}
}
return true;
}
// BMP files are stored upside down, but if we're writing this out as a result of doing an OpenGL pixel read, then
// the src buffer will be upside down anyway, so I added this flip-bool -Ste
//
// (psFilename can be NULL for mem files)
//
static bool BMP_Close(LPCSTR psFilename, bool bFlipFinal)
{
if (fhBMP)
{
fclose (fhBMP);
fhBMP = NULL;
}
else
{
#if 1
int iPadBytes = (4-((pBMP->BMPInfoHeader.biWidth * sizeof(RGBTRIPLE))%4))&3;
int iWidthBytes = (pBMP->BMPInfoHeader.biWidth * sizeof(RGBTRIPLE))+iPadBytes;
assert(iBMP_PixelWriteOffset == iWidthBytes * pBMP->BMPInfoHeader.biHeight);
assert((iBMP_PixelWriteOffset + (int)sizeof(BITMAPINFOHEADER)) == iBMP_MallocSize);
#endif
}
if (bFlipFinal)
{
if (psFilename)
{
if (!BMP_FlipTrueColour(psFilename))
return false;
}
}
return true;
}
static bool BMP_FlipTrueColour(LPCSTR psFilename)
{
BITMAPFILEHEADER BMPFileHeader;
BITMAPINFOHEADER BMPInfoHeader;
RGBTRIPLE *RGBTriples, *tTopLine, *tBottomLine;//, *AfterLastLine;
BYTE *byTopLine, *byBottomLine, *byAfterLastLine;
RGBTRIPLE Trip;
int x,y;
int iPadBytes,iRealWidth;
// reopen it to flip it
fhBMP=fopen(psFilename,"rb"); // checked fopen
if (!(int)fhBMP)
return false;
fread (&BMPFileHeader,sizeof(BMPFileHeader),1,fhBMP);
fread (&BMPInfoHeader,sizeof(BMPInfoHeader),1,fhBMP);
iPadBytes = (4-((BMPInfoHeader.biWidth * sizeof(RGBTRIPLE))%4))&3;
iRealWidth=(sizeof(RGBTRIPLE)*BMPInfoHeader.biWidth)+iPadBytes;
RGBTriples=(RGBTRIPLE *)malloc(iRealWidth*BMPInfoHeader.biHeight);
fread (RGBTriples,iRealWidth*BMPInfoHeader.biHeight,1,fhBMP);
fclose (fhBMP);
byTopLine=(BYTE *)RGBTriples;
byAfterLastLine=byTopLine+iRealWidth*BMPInfoHeader.biHeight;
// actually flip it
for (y=0; y<BMPInfoHeader.biHeight/2; y++)
{
byBottomLine=byAfterLastLine-((y+1)*iRealWidth);
tTopLine=(RGBTRIPLE *)byTopLine;
tBottomLine=(RGBTRIPLE *)byBottomLine;
for (x=0; x<BMPInfoHeader.biWidth; x++)
{
Trip=tTopLine[x];
tTopLine[x]=tBottomLine[x];
tBottomLine[x]=Trip;
}
byTopLine+=iRealWidth;
}
// rewrite it flipped
fhBMP=fopen(psFilename,"wb"); // checked fopen
fwrite (&BMPFileHeader,sizeof(BMPFileHeader),1,fhBMP);
fwrite (&BMPInfoHeader,sizeof(BMPInfoHeader),1,fhBMP);
fwrite (RGBTriples,(iRealWidth)*BMPInfoHeader.biHeight,1,fhBMP);
fclose (fhBMP);
free(RGBTriples);
return true;
}
// if psFilename == NULL, takes a memory screenshot in DIB format (for copying to clipboard)
//
bool ScreenShot(LPCSTR psFilename, // else NULL = take memory snapshot (for clipboard)
LPCSTR psCopyrightMessage, // /* = NULL */
int iWidth, // /* = <screenwidth> */
int iHeight // /* = <screenheight> */
)
{
bool bReturn = false;
int iOldPack;
glGetIntegerv(GL_PACK_ALIGNMENT,&iOldPack);
glPixelStorei(GL_PACK_ALIGNMENT,1);
void *pvGLPixels = malloc (iWidth * iHeight * 3); // 3 = R,G,B
if (pvGLPixels)
{
if (psCopyrightMessage)
{
bool bOldInhibit = gbTextInhibit;
gbTextInhibit = false;
Text_DisplayFlat(psCopyrightMessage, 0, (iHeight-TEXT_DEPTH)-1,255,255,255); // y-1 = aesthetic only
gbTextInhibit = bOldInhibit;
}
glReadPixels( 0, // x
0, // y (from bottom left)
iWidth, // width
iHeight, // height
GL_RGB, // format
GL_UNSIGNED_BYTE, // type
pvGLPixels // buffer ptr
);
// save area is valid size...
//
if (BMP_Open(psFilename, iWidth, iHeight))
{
for (int y=0; y<iHeight; y++)
{
LPGLRGBBYTES
lpGLRGBBytes = (LPGLRGBBYTES) pvGLPixels;
lpGLRGBBytes+= y * iWidth;
for (int x=0; x<iWidth; x++, lpGLRGBBytes++)
{
BMP_WritePixel(lpGLRGBBytes->r,lpGLRGBBytes->g,lpGLRGBBytes->b);
}
BMP_WriteLinePadding(iWidth); // arg is # pixels per row
}
BMP_Close(psFilename,false); // false = bFlipFinal
bReturn = true;
}
free(pvGLPixels);
pvGLPixels = NULL; // yeah...yeah
}
glPixelStorei(GL_PACK_ALIGNMENT,iOldPack);
return bReturn;
}
//////////////// eof ////////////////

20
tools/ModView/clipboard.h Normal file
View File

@@ -0,0 +1,20 @@
// Filename:- clipboard.h
//
#ifndef CLIPBOARD_H
#define CLIPBOARD_H
BOOL Clipboard_SendString(LPCSTR psString);
BOOL ClipBoard_SendDIB(LPVOID pvData, int iBytes);
// other stuff that's not actually clipboard, but is called only in conjunction with it anyway...
//
bool ScreenShot(LPCSTR psFilename = NULL, LPCSTR psCopyrightMessage = NULL, int iWidth = g_iScreenWidth, int iHeight = g_iScreenHeight);
bool BMP_GetMemDIB(void *&pvAddress, int &iBytes);
void BMP_Free(void);
#endif
/////////////////// eof //////////////////

482
tools/ModView/commarea.cpp Normal file
View File

@@ -0,0 +1,482 @@
// Filename:- CommArea.cpp
//
// contains low-level code for shared-memory inter-program comms
//
#include "stdafx.h"
#include "includes.h"
//#include <winbase.h>
//
#include "CommArea.h"
#define sCOMMAREA_NAME "COMMAREA_MODVIEW"
#define iCOMMAREA_VERSION 1
typedef enum
{
cst_READY=0, // nothing pending
cst_SERVERREQ, // server has request for client
cst_CLIENTREQ, // client has request for server
cst_CLIENTERR, // client failed a request, check PassedData.sError[]
cst_SERVERERR, // server failed a request, check PassedData.sError[]
cst_WAIT, // raised by either side while filling in details of stuff
//
// these last 2 I could probably get rid of and replace by just setting back to cst_READY, but for now...
//
cst_CLIENTOK, // client completed a request
cst_SERVEROK, // server completed a request
} CommStatus_e;
typedef struct
{
// message passing... (arb. buffer sizes, can be increased if you bump the version number as well)
//
char sCommand[1024]; // used to pass text command (case insensitive)
byte bData[65536]; //
int iDataSize;
// other...
//
char sError[4096]; // used for reporting problems
} PassedData_t;
typedef struct
{
// verification fields...
//
int iVersion; // version of this struct, should match in client and server
int iSize; // size of this struct, belt and braces safety
//
// the semaphore field...
//
CommStatus_e eStatus;
// message passing... (arb. buffer sizes, can be increased if you bump the version number as well)
//
PassedData_t PassedData;
} CommArea_t;
static CommArea_t CommArea_USEONLYDURINGINIT, *gpMappedCommArea = NULL;
static HANDLE hFileMap = NULL;
static bool bIAmServer = false;
// special copy that I can put all recieved data into so that the acknowledging a message doesn't let the other
// app zap the results with a new message while you're busy copying the data elsewhere...
//
static PassedData_t LocalData;
// by having a common string at the front of my error strings I can allow the caller to detect
// whether they're messages produced by me or by Windows (and allow for stripping the common piece if desired)
//
#define sERROR_COMMAREAUNINITIALISED "CommArea: function called while comms not initialised, or init failed"
#define sERROR_COMMANDSTRINGTOOLONG "CommArea: command string too long"
#define sERROR_COMMANDDATATOOLONG "CommArea: command data too long"
#define sERROR_BADCOMMANDACKTIME "CommArea: command acknowledge called but no command was pending"
#define sERROR_BADCOMMANDCLEARTIME "CommArea: command-clear called while no error or ack pending - commands lost?"
#define sERROR_NOTASKPENDING "CommArea: error report attempted while task not pending"
#define sERROR_BUSY "CommArea: busy"
static PassedData_t *CommArea_LocaliseData(void)
{
LocalData = gpMappedCommArea->PassedData;
return &LocalData;
}
// buffer-size query for caller-app to setup args legally (if wanting to send big commands and unsure of space)...
//
int CommArea_GetMaxDataSize(void)
{
return sizeof(LocalData.bData);
}
int CommArea_GetMaxCommandStrlen(void)
{
return sizeof(LocalData.sCommand);
}
// getting this size wrong while sending error strings will never cause problems, they're just clipped
//
int CommArea_GetMaxErrorStrlen(void)
{
return sizeof(LocalData.sError);
}
void CommArea_ShutDown(void)
{
if (gpMappedCommArea)
{
UnmapViewOfFile( gpMappedCommArea );
gpMappedCommArea = NULL;
}
if (hFileMap)
{
CloseHandle(hFileMap);
hFileMap = NULL;
}
}
static LPCSTR CommArea_MapViewOfFile(void)
{
gpMappedCommArea = (CommArea_t *) MapViewOfFile(hFileMap, // HANDLE hFileMappingObject, // file-mapping object to map into
FILE_MAP_ALL_ACCESS,// DWORD dwDesiredAccess, // access mode
0, // DWORD dwFileOffsetHigh, // high-order 32 bits of file offset
0, // DWORD dwFileOffsetLow, // low-order 32 bits of file offset
0 // DWORD dwNumberOfBytesToMap // number of bytes to map
);
return gpMappedCommArea ? NULL : SystemErrorString();
}
// return is either error message, or NULL for success...
//
LPCSTR CommArea_ServerInitOnceOnly(void)
{
LPCSTR psError = NULL;
hFileMap = CreateFileMapping( INVALID_HANDLE_VALUE, // HANDLE hFile // handle to file to map
NULL, // LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
PAGE_READWRITE, // DWORD flProtect, // protection for mapping object
0, // DWORD dwMaximumSizeHigh, // high-order 32 bits of object size
sizeof(CommArea_USEONLYDURINGINIT), // DWORD dwMaximumSizeLow, // low-order 32 bits of object size
sCOMMAREA_NAME // LPCTSTR lpName // name of file-mapping object
);
DWORD dwError = GetLastError();
if (hFileMap == NULL || dwError == ERROR_ALREADY_EXISTS)
{
psError = SystemErrorString(dwError);
}
else
{
// ok so far, so get a map view of it...
//
psError = CommArea_MapViewOfFile();
if (!psError)
{
// Yeeehaaa.... let's init this baby...
//
ZEROMEMPTR(gpMappedCommArea);
gpMappedCommArea->iVersion = iCOMMAREA_VERSION;
gpMappedCommArea->iSize = sizeof(*gpMappedCommArea);
bIAmServer = true;
}
}
if (psError)
{
CommArea_ShutDown();
}
return psError;
}
// return is either error message, or NULL for success...
//
LPCSTR CommArea_ClientInitOnceOnly(void)
{
LPCSTR psError = NULL;
hFileMap = OpenFileMapping( FILE_MAP_ALL_ACCESS, // DWORD dwDesiredAccess, // access mode
true, // BOOL bInheritHandle, // inherit flag
sCOMMAREA_NAME // LPCTSTR lpName // pointer to name of file-mapping object
);
if (!hFileMap)
{
psError = SystemErrorString();
}
else
{
// ok so far, so get a map view of it...
//
psError = CommArea_MapViewOfFile();
if (!psError)
{
// let's give it a quick check for version differences...
//
static char sError[1024];
if (gpMappedCommArea->iVersion != iCOMMAREA_VERSION)
{
sprintf(sError,"CommArea version # mismatch, found %d but expected %d!",gpMappedCommArea->iVersion, iCOMMAREA_VERSION);
psError = sError;
}
else
{
if (gpMappedCommArea->iSize != sizeof(*gpMappedCommArea))
{
sprintf(sError,"CommArea struct size mismatch, found %d but expected %d!",gpMappedCommArea->iSize, sizeof(*gpMappedCommArea));
psError = sError;
}
else
{
// Yeeehaaa.... everything ok...
//
bIAmServer = false; // unnec. but clearer
}
}
}
}
if (psError)
{
CommArea_ShutDown();
}
return psError;
}
// can be safely called even when init failed...
//
bool CommArea_IsIdle(void)
{
if (!gpMappedCommArea)
return true;
return gpMappedCommArea->eStatus == cst_READY
/*
||
gpMappedCommArea->eStatus == cst_CLIENTOK ||
gpMappedCommArea->eStatus == cst_SERVEROK
*/
;
}
// call to query if any new commands are waiting for us, and return local (non-shared) ptrs if so.
//
// return = command string, else NULL for none
//
// This can be safely called even if the OnceOnlyInit call failed
//
LPCSTR CommArea_IsCommandWaiting(byte **ppbDataPassback, int *piDatasizePassback)
{
assert(ppbDataPassback);
assert(piDatasizePassback);
if (gpMappedCommArea && gpMappedCommArea->eStatus == (bIAmServer ? cst_CLIENTREQ : cst_SERVERREQ) )
{
// make local (non-shared) copy of the data so we can access via ptrs without next command overwriting it...
//
CommArea_LocaliseData();
*ppbDataPassback = &LocalData.bData[0];
*piDatasizePassback = LocalData.iDataSize;
return LocalData.sCommand;
}
return NULL;
}
// call this only (and always) after you send a command to tell you when the other app has finished responding to it
//
// return = response string (may be blank), else NULL for none (optional data fields are filled in if supplied)
//
LPCSTR CommArea_IsAckWaiting(byte **ppbDataPassback /* = NULL */, int *piDatasizePassback /* = NULL */)
{
assert(gpMappedCommArea);
if (gpMappedCommArea && gpMappedCommArea->eStatus == (bIAmServer ? cst_CLIENTOK : cst_SERVEROK) )
{
// make local (non-shared) copy of the data so we can access via ptrs without next command overwriting it...
//
CommArea_LocaliseData();
if ( ppbDataPassback)
*ppbDataPassback = &LocalData.bData[0];
if ( piDatasizePassback)
*piDatasizePassback = LocalData.iDataSize;
return LocalData.sCommand;
}
return NULL;
}
// check outgoing data for size-exceeding, and copy to send buffer if everything ok...
//
// return = errmess or NULL for ok
//
static LPCSTR CommArea_SetupAndLegaliseOutgoingData(LPCSTR psCommand, byte *pbData, int iDataSize)
{
if (!gpMappedCommArea)
return sERROR_COMMAREAUNINITIALISED;
if (psCommand && strlen(psCommand) > sizeof(gpMappedCommArea->PassedData.sCommand)-1)
return sERROR_COMMANDSTRINGTOOLONG;
if (pbData && iDataSize > sizeof(gpMappedCommArea->PassedData.bData))
return sERROR_COMMANDDATATOOLONG;
// seems ok, so copy it to outgoing...
//
CommStatus_e ePrevStatus = gpMappedCommArea->eStatus;
gpMappedCommArea->eStatus = cst_WAIT;
{
if (psCommand)
{
strcpy(gpMappedCommArea->PassedData.sCommand,psCommand);
}
else
{
strcpy(gpMappedCommArea->PassedData.sCommand,"");
}
if (pbData)
{
memcpy(gpMappedCommArea->PassedData.bData, pbData, iDataSize);
}
else
{
//ZEROMEM(gpMappedCommArea->PassedData.bData); // not actually necessary
}
gpMappedCommArea->PassedData.iDataSize = iDataSize;
}
gpMappedCommArea->eStatus = ePrevStatus;
return NULL;
}
// you can ignore the return code from this if you only call it sensibly, ie when you know you've just completed a
// command task
//
// NOTE: if there's an error then the acknowledge is NOT sent!!!!
//
LPCSTR CommArea_CommandAck(LPCSTR psCommand /* = NULL */, byte *pbData /* = NULL */, int iDataSize /* = 0 */)
{
assert(gpMappedCommArea );
if (gpMappedCommArea && gpMappedCommArea->eStatus == (bIAmServer ? cst_CLIENTREQ : cst_SERVERREQ) )
{
LPCSTR psError = CommArea_SetupAndLegaliseOutgoingData(psCommand, pbData, iDataSize);
if (psError)
{
assert(0);
return psError;
}
gpMappedCommArea->eStatus = (bIAmServer ? cst_SERVEROK : cst_CLIENTOK);
return NULL;
}
assert(0);
return sERROR_BADCOMMANDACKTIME;
}
// Call this to query for any pending error messages from the other program
//
// return = error, else NULL for none
//
// This can be safely called even if the OnceOnlyInit call failed
//
LPCSTR CommArea_IsErrorWaiting(void)
{
if (gpMappedCommArea && gpMappedCommArea->eStatus == (bIAmServer ? cst_CLIENTERR : cst_SERVERERR) )
{
return CommArea_LocaliseData()->sError;
}
return NULL;
}
// Only call this after you've sent a command, then received either an acknowledgement or an error
//
// You can ignore the return error from this if you only call it sensibly, ie when you know there was an error
// that wanted displaying...
//
LPCSTR CommArea_CommandClear(void)
{
assert(gpMappedCommArea );
if (gpMappedCommArea &&
(
gpMappedCommArea->eStatus == (bIAmServer ? cst_CLIENTERR : cst_SERVERERR)
||
gpMappedCommArea->eStatus == (bIAmServer ? cst_CLIENTOK : cst_SERVEROK)
)
)
{
gpMappedCommArea->eStatus = cst_READY;
return NULL;
}
return sERROR_BADCOMMANDCLEARTIME;
}
// Call to report an error, this should only be done on receipt of a command that your app had a problem obeying...
//
// You can ignore the return code from this if you only call it sensibly, ie when you know you're just reporting an error
//
// NOTE: if there's an error (like you're calling this at the wrong time) then this error is NOT sent!!!!
//
LPCSTR CommArea_CommandError(LPCSTR psError)
{
assert(gpMappedCommArea);
if (gpMappedCommArea && gpMappedCommArea->eStatus == (bIAmServer ? cst_CLIENTREQ : cst_SERVERREQ) )
{
gpMappedCommArea->eStatus = cst_WAIT;
{
strncpy(gpMappedCommArea->PassedData.sError, psError, sizeof(gpMappedCommArea->PassedData.sError)-1);
gpMappedCommArea->PassedData.sError[sizeof(gpMappedCommArea->PassedData.sError)-1] = '\0';
}
gpMappedCommArea->eStatus = (bIAmServer ? cst_SERVERERR : cst_CLIENTERR);
return NULL;
}
return sERROR_NOTASKPENDING;
}
// return NULL = success, else error message... (pbData can be NULL if desired, ditto iDataSize)
//
LPCSTR CommArea_IssueCommand(LPCSTR psCommand, byte *pbData /* = NULL */, int iDataSize /* = 0 */)
{
if (!CommArea_IsIdle())
return sERROR_BUSY;
assert(gpMappedCommArea);
if (!gpMappedCommArea)
return sERROR_COMMAREAUNINITIALISED;
LPCSTR psError = CommArea_SetupAndLegaliseOutgoingData(psCommand, pbData, iDataSize);
if (psError)
{
assert(0);
return psError;
}
gpMappedCommArea->eStatus = (bIAmServer ? cst_SERVERREQ : cst_CLIENTREQ);
return NULL;
}
////////////////////// eof ////////////////

42
tools/ModView/commarea.h Normal file
View File

@@ -0,0 +1,42 @@
// Filename:- CommArea.h
//
// headers for inter-program communication
//
#ifndef COMMAREA_H
#define COMMAREA_H
// setup functions...
//
LPCSTR CommArea_ServerInitOnceOnly(void);
LPCSTR CommArea_ClientInitOnceOnly(void);
void CommArea_ShutDown(void);
//
// size-limit internal buffer-query functions...
//
int CommArea_GetMaxDataSize(void);
int CommArea_GetMaxCommandStrlen(void);
int CommArea_GetMaxErrorStrlen(void);
//
// message-pending query functions...
//
bool CommArea_IsIdle(void);
LPCSTR CommArea_IsCommandWaiting(byte **ppbDataPassback, int *piDatasizePassback);
LPCSTR CommArea_IsErrorWaiting(void);
LPCSTR CommArea_IsAckWaiting(byte **ppbDataPassback = NULL, int *piDatasizePassback = NULL);
//
// message-acknowledge functions...
//
LPCSTR CommArea_CommandAck(LPCSTR psCommand = NULL, byte *pbData = NULL, int iDataSize = 0);
LPCSTR CommArea_CommandClear(void);
LPCSTR CommArea_CommandError(LPCSTR psError);
//
// message/command-send functions...
//
LPCSTR CommArea_IssueCommand(LPCSTR psCommand, byte *pbData = NULL, int iDataSize = 0);
#endif // #ifndef COMMAREA_H
/////////////// eof /////////////

View File

@@ -0,0 +1,23 @@
// Filename:- common_headers.h
//
// Rick's GP2 file (which is shared across projects) wanted a header file called this, so...
//
#ifndef COMMON_HEADERS_H
#define COMMON_HEADERS_H
#include <string.h>
#include <malloc.h>
#define trap_Z_Malloc(_size, _tag) malloc(_size) // dunno if GP2 need calloc or malloc, so...
#define trap_Z_Free(_mem) free(_mem)
//#define TAG_GP2 0
#endif // #ifndef COMMON_HEADERS_H
/////////////////// eof //////////////

View File

@@ -0,0 +1,521 @@
// MainFrm.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "commtest.h"
#include "../tools/modview/wintalk.h"
#include "commtestDoc.h"
#include "commtestview.h"
#include <assert.h>
#include "bits.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMainFrame
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
ON_COMMAND(ID_ERRORBOX_OFF, OnErrorboxOff)
ON_COMMAND(ID_ERRORBOX_ON, OnErrorboxOn)
ON_COMMAND(ID_EDIT_M4, OnEditM4)
ON_COMMAND(ID_STARTANIM, OnStartanim)
ON_COMMAND(ID_STARTANIMWRAP, OnStartanimwrap)
ON_COMMAND(ID_STOPANIM, OnStopanim)
ON_COMMAND(ID_LOCK_SEQUENCES, OnLockSequences)
ON_COMMAND(ID_UNLOCKALLSEQS, OnUnlockallseqs)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{
// TODO: add member initialization code here
}
CMainFrame::~CMainFrame()
{
}
CMainFrame* gCMainFrame = NULL;
HWND g_hWnd;
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
g_hWnd = m_hWnd;
gCMainFrame = this; // eeeuuwww!!!!!
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers
char *va(char *format, ...);
void R_OurTree_AddRemoteItemToThisParent(TreeItemData_t TreeItemData, HTREEITEM hTreeItem_Parent, HTREEITEM hTreeItem_Remote )
{
LPCSTR psAnswer;
// get remote item text...
//
if (!WinTalk_IssueCommand(va("modeltree_getitemtextpure %d",hTreeItem_Remote),NULL,0,&psAnswer))
{
// should never happen...
//
assert(0);
psAnswer = "Error!";
}
// generate new tree item...
//
HTREEITEM hTreeItem_This = gpCommTestView->GetTreeCtrl().InsertItem ( psAnswer, hTreeItem_Parent);
gpCommTestView->GetTreeCtrl().SetItemData( hTreeItem_This, TreeItemData.uiData);
// check remote version of this for children...
//
if (WinTalk_IssueCommand(va("modeltree_getchilditem %d",hTreeItem_Remote),NULL,0,&psAnswer))
{
HTREEITEM hTreeItemRemote_Child = (HTREEITEM) atoi(psAnswer);
if (hTreeItemRemote_Child)
{
R_OurTree_AddRemoteItemToThisParent( TreeItemData, hTreeItem_This, hTreeItemRemote_Child);
}
}
// check remote version of this for sibling...
//
if (WinTalk_IssueCommand(va("modeltree_getnextsiblingitem %d",hTreeItem_Remote),NULL,0,&psAnswer))
{
HTREEITEM hTreeItemRemote_Sibling = (HTREEITEM) atoi(psAnswer);
if (hTreeItemRemote_Sibling)
{
R_OurTree_AddRemoteItemToThisParent( TreeItemData, hTreeItem_Parent, hTreeItemRemote_Sibling);
}
}
}
//
void ExpandTreeItem( HTREEITEM hTreeItem )
{
gpCommTestView->GetTreeCtrl().Expand( hTreeItem, TVE_EXPAND );
}
void R_ApplyToTreeItem( void (*pFunction) ( HTREEITEM hTreeItem ), HTREEITEM hTreeItem )
{
if (hTreeItem)
{
// process item...
//
pFunction(hTreeItem);
// recurse child...
//
R_ApplyToTreeItem( pFunction, gpCommTestView->GetTreeCtrl().GetChildItem( hTreeItem ) );
// recurse sibling...
//
R_ApplyToTreeItem( pFunction, gpCommTestView->GetTreeCtrl().GetNextSiblingItem( hTreeItem ) );
}
}
bool R_IsDescendantOf(HTREEITEM hTreeItem_This, HTREEITEM hTreeItem_Ancestor)
{
if (hTreeItem_This == hTreeItem_Ancestor)
return true;
HTREEITEM hTreeItem_Parent = gpCommTestView->GetTreeCtrl().GetParentItem(hTreeItem_This);
if (hTreeItem_Parent)
{
return R_IsDescendantOf(hTreeItem_Parent, hTreeItem_Ancestor);
}
return false;
}
// made global so they can be accessed from another module...
//
HTREEITEM ghTreeItem_ModelName = NULL;
HTREEITEM ghTreeItem_Surfaces= NULL;
HTREEITEM ghTreeItem_Bones = NULL;
ModelHandle_t ghLastLoadedModel = NULL;
ModelHandle_t ghPrimaryModel = NULL;
int giPrimaryModel_NumSequences=0;
void OurTree_Generate(LPCSTR psModelName, ModelHandle_t hModel, HTREEITEM hTreeItemParent = TVI_ROOT);
void OurTree_Generate(LPCSTR psModelName, ModelHandle_t hModel, HTREEITEM hTreeItemParent)
{
ghLastLoadedModel = hModel;
if (hTreeItemParent == TVI_ROOT) // loading primary model?
gpCommTestView->GetTreeCtrl().DeleteAllItems();
TreeItemData_t TreeItemData={0};
TreeItemData.iModelHandle = hModel;
TreeItemData.iItemType = TREEITEMTYPE_MODELNAME;
ghTreeItem_ModelName = gpCommTestView->GetTreeCtrl().InsertItem(psModelName, hTreeItemParent);
gpCommTestView->GetTreeCtrl().SetItemData(ghTreeItem_ModelName,TreeItemData.uiData);
TreeItemData.iItemType = TREEITEMTYPE_SURFACEHEADER;
ghTreeItem_Surfaces = gpCommTestView->GetTreeCtrl().InsertItem("Surfaces", ghTreeItem_ModelName);
gpCommTestView->GetTreeCtrl().SetItemData(ghTreeItem_Surfaces, TreeItemData.uiData);
TreeItemData.iItemType = TREEITEMTYPE_BONEHEADER;
ghTreeItem_Bones = gpCommTestView->GetTreeCtrl().InsertItem("Bones", ghTreeItem_ModelName);
gpCommTestView->GetTreeCtrl().SetItemData(ghTreeItem_Bones, TreeItemData.uiData);
TreeItemData.iItemType = TREEITEMTYPE_BONEALIASHEADER;
HTREEITEM hTreeItem_Aliases=gpCommTestView->GetTreeCtrl().InsertItem("Bone Aliases",ghTreeItem_ModelName);
gpCommTestView->GetTreeCtrl().SetItemData(hTreeItem_Aliases, TreeItemData.uiData);
// ok, now we need to remote-ask ModView for the HTREEITEM values for its Bone and Surface items...
//
LPCSTR psAnswer = NULL;
// if (WinTalk_IssueCommand(va("modeltree_getrootsurface %s",va("%d",hModel)),NULL,0,&psAnswer))
if (WinTalk_IssueCommand(va("modeltree_getrootsurface %d",hModel),NULL,0,&psAnswer))
{
HTREEITEM hTreeItemRemote_RootSurface = (HTREEITEM) atoi(psAnswer);
// if (WinTalk_IssueCommand(va("modeltree_getrootbone %s",va("%d",hModel)),NULL,0,&psAnswer))
if (WinTalk_IssueCommand(va("modeltree_getrootbone %d",hModel),NULL,0,&psAnswer))
{
HTREEITEM hTreeItemRemote_RootBone = (HTREEITEM) atoi(psAnswer);
TreeItemData.iItemType = TREEITEMTYPE_GLM_SURFACE;
R_OurTree_AddRemoteItemToThisParent(TreeItemData, ghTreeItem_Surfaces, hTreeItemRemote_RootSurface );
TreeItemData.iItemType = TREEITEMTYPE_GLM_BONE;
R_OurTree_AddRemoteItemToThisParent(TreeItemData, ghTreeItem_Bones, hTreeItemRemote_RootBone );
// add bone aliases...
if (WinTalk_IssueCommand(va("model_getnumbonealiases %d",hModel),NULL,0,&psAnswer))
{
int iNumBoneAliases = atoi(psAnswer);
for (int iBoneAlias = 0; iBoneAlias < iNumBoneAliases; iBoneAlias++)
{
if (WinTalk_IssueCommand(va("model_getbonealias %d %d",hModel,iBoneAlias),NULL,0,&psAnswer))
{
CString strRealName(psAnswer);
int iLoc = strRealName.Find(" ",0);
if (iLoc!=-1)
{
CString strAliasName(strRealName.Mid(iLoc+1));
strRealName = strRealName.Left(iLoc); // I don't actually use this in this app, but FYI.
OutputDebugString(va("alias %d/%d: real = '%s', alias = '%s'\n",iBoneAlias,iNumBoneAliases,(LPCSTR)strRealName,(LPCSTR)strAliasName));
TreeItemData.iItemType = TREEITEMTYPE_GLM_BONEALIAS;
HTREEITEM hTreeItemTemp = gpCommTestView->GetTreeCtrl().InsertItem(strAliasName, hTreeItem_Aliases);
gpCommTestView->GetTreeCtrl().SetItemData( hTreeItemTemp, TreeItemData.uiData);
}
else
{
assert(0);
}
}
else
{
assert(0);
}
}
}
else
{
assert(0);
}
// query sequence info, and add to tree if present...
//
if (WinTalk_IssueCommand(va("model_getnumsequences %s",va("%d",hModel)),NULL,0,&psAnswer))
{
int iNumSequences = atoi(psAnswer);
if (hModel == ghPrimaryModel)
{
giPrimaryModel_NumSequences = iNumSequences;
}
if (iNumSequences)
{
TreeItemData.iItemType = TREEITEMTYPE_SEQUENCEHEADER;
HTREEITEM hTreeItem_Sequences = gpCommTestView->GetTreeCtrl().InsertItem("Sequences",ghTreeItem_ModelName);
gpCommTestView->GetTreeCtrl().SetItemData(hTreeItem_Sequences, TreeItemData.uiData);
for (int iSeq=0; iSeq<iNumSequences; iSeq++)
{
if (WinTalk_IssueCommand(va("model_getsequence %s %d",va("%d",hModel),iSeq),NULL,0,&psAnswer))
{
TreeItemData.iItemType = TREEITEMTYPE_SEQUENCE;
TreeItemData.iItemNumber= iSeq;
HTREEITEM hTreeItem_Sequence = gpCommTestView->GetTreeCtrl().InsertItem (psAnswer, hTreeItem_Sequences);
gpCommTestView->GetTreeCtrl().SetItemData(hTreeItem_Sequence, TreeItemData.uiData);
}
else
{
assert(0);
}
}
TreeItemData.iItemNumber = 0;
}
// add BoltOns tree item header...
//
TreeItemData.iItemType = TREEITEMTYPE_BOLTONSHEADER;
HTREEITEM hTreeItemBolts= gpCommTestView->GetTreeCtrl().InsertItem("BoltOns", ghTreeItem_ModelName);
gpCommTestView->GetTreeCtrl().SetItemData(hTreeItemBolts, TreeItemData.uiData);
}
else
{
assert(0);
}
}
else
{
assert(0);
}
}
else
{
assert(0);
}
R_ApplyToTreeItem( ExpandTreeItem, gpCommTestView->GetTreeCtrl().GetRootItem() );
gpCommTestView->GetTreeCtrl().SelectSetFirstVisible(gpCommTestView->GetTreeCtrl().GetRootItem());
}
// returns actual filename only, no path
//
char *Filename_WithoutPath(LPCSTR psFilename)
{
static char sString[MAX_PATH];
/*
LPCSTR p = strrchr(psFilename,'\\');
if (!p++)
{
p = strrchr(psFilename,'/');
if (!p++)
p=psFilename;
}
strcpy(sString,p);
*/
LPCSTR psCopyPos = psFilename;
while (*psFilename)
{
if (*psFilename == '/' || *psFilename == '\\')
psCopyPos = psFilename+1;
psFilename++;
}
strcpy(sString,psCopyPos);
return sString;
}
bool gbInhibit = false;
void CMainFrame::LoadModel(LPCSTR psFullPathedFileName)
{
gbInhibit = true;
LPCSTR psAnswer = NULL;
if (WinTalk_IssueCommand(va("model_loadprimary %s",psFullPathedFileName),NULL,0,&psAnswer))
{
ModelHandle_t hModel = (ModelHandle_t) atoi(psAnswer);
ghPrimaryModel = hModel; // do this BEFORE OurTree_Generate()
OurTree_Generate(Filename_WithoutPath(psFullPathedFileName),hModel);
}
else
{
ghPrimaryModel = NULL; // do this BEFORE OurTree_Generate()
gpCommTestView->GetTreeCtrl().DeleteAllItems();
}
gbInhibit = false;
}
extern HTREEITEM R_ModelTree_FindItemWithThisData(HTREEITEM hTreeItem, UINT32 uiData2Match);
void CMainFrame::BoltModel(ModelHandle_t hModel, LPCSTR psBoltName, LPCSTR psFullPathedName)
{
LPCSTR psAnswer = NULL;
if (WinTalk_IssueCommand(va("model_loadbolton %d %s %s",hModel,psBoltName,psFullPathedName),NULL,0,&psAnswer))
{
ModelHandle_t hModel_BoltOn = (ModelHandle_t) atoi(psAnswer);
TreeItemData_t TreeItemData = {0};
TreeItemData.iModelHandle = hModel;
TreeItemData.iItemType = TREEITEMTYPE_BOLTONSHEADER;
HTREEITEM hTreeItem_BoltOns = R_ModelTree_FindItemWithThisData(NULL, TreeItemData.uiData);
OurTree_Generate(Filename_WithoutPath(psFullPathedName),hModel_BoltOn,hTreeItem_BoltOns);
}
}
void CMainFrame::OnEditCopy()
{
LoadModel("S:/base/models/test/conetree4/conetree4.glm");
}
void CMainFrame::OnEditPaste()
{
LoadModel("S:/base/models/test/jake/jake.glm");
}
void CMainFrame::OnEditCut()
{
LoadModel("S:/base/models/test/baddir/badname.glm");
}
void CMainFrame::OnEditM4()
{
LoadModel("S:/base/models/test/m4/m4.glm");
}
void CMainFrame::OnErrorboxOff()
{
WinTalk_IssueCommand("errorbox_disable");
}
void CMainFrame::OnErrorboxOn()
{
WinTalk_IssueCommand("errorbox_enable");
}
void CMainFrame::OnStartanim()
{
WinTalk_IssueCommand("startanim");
}
void CMainFrame::OnStartanimwrap()
{
WinTalk_IssueCommand("startanimwrap");
}
void CMainFrame::OnStopanim()
{
WinTalk_IssueCommand("stopanim");
}
void CMainFrame::OnLockSequences()
{
if (ghPrimaryModel && giPrimaryModel_NumSequences)
{
static int iLockSeq = -1;
if (++iLockSeq >= giPrimaryModel_NumSequences)
{
iLockSeq = 0;
}
WinTalk_IssueCommand(va("model_locksequence %d, %d", ghPrimaryModel, iLockSeq));
}
}
void CMainFrame::OnUnlockallseqs()
{
if (ghPrimaryModel)
{
WinTalk_IssueCommand(va("model_unlocksequences %d",ghPrimaryModel));
}
}

View File

@@ -0,0 +1,72 @@
// MainFrm.h : interface of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////
#include "bits.h"
#if !defined(AFX_MAINFRM_H__61504888_AF87_11D4_8A97_00500424438B__INCLUDED_)
#define AFX_MAINFRM_H__61504888_AF87_11D4_8A97_00500424438B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CMainFrame : public CFrameWnd
{
protected: // create from serialization only
CMainFrame();
DECLARE_DYNCREATE(CMainFrame)
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMainFrame)
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
void LoadModel(LPCSTR psFullPathedFileName);
void BoltModel(ModelHandle_t hModel, LPCSTR psBoltName, LPCSTR psFullPathedName);
protected: // control bar embedded members
CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnEditCopy();
afx_msg void OnEditPaste();
afx_msg void OnEditCut();
afx_msg void OnErrorboxOff();
afx_msg void OnErrorboxOn();
afx_msg void OnEditM4();
afx_msg void OnStartanim();
afx_msg void OnStartanimwrap();
afx_msg void OnStopanim();
afx_msg void OnLockSequences();
afx_msg void OnUnlockallseqs();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAINFRM_H__61504888_AF87_11D4_8A97_00500424438B__INCLUDED_)

View File

@@ -0,0 +1,105 @@
========================================================================
MICROSOFT FOUNDATION CLASS LIBRARY : commtest
========================================================================
AppWizard has created this commtest application for you. This application
not only demonstrates the basics of using the Microsoft Foundation classes
but is also a starting point for writing your application.
This file contains a summary of what you will find in each of the files that
make up your commtest application.
commtest.dsp
This file (the project file) contains information at the project level and
is used to build a single project or subproject. Other users can share the
project (.dsp) file, but they should export the makefiles locally.
commtest.h
This is the main header file for the application. It includes other
project specific headers (including Resource.h) and declares the
CCommtestApp application class.
commtest.cpp
This is the main application source file that contains the application
class CCommtestApp.
commtest.rc
This is a listing of all of the Microsoft Windows resources that the
program uses. It includes the icons, bitmaps, and cursors that are stored
in the RES subdirectory. This file can be directly edited in Microsoft
Visual C++.
commtest.clw
This file contains information used by ClassWizard to edit existing
classes or add new classes. ClassWizard also uses this file to store
information needed to create and edit message maps and dialog data
maps and to create prototype member functions.
res\commtest.ico
This is an icon file, which is used as the application's icon. This
icon is included by the main resource file commtest.rc.
res\commtest.rc2
This file contains resources that are not edited by Microsoft
Visual C++. You should place all resources not editable by
the resource editor in this file.
/////////////////////////////////////////////////////////////////////////////
For the main frame window:
MainFrm.h, MainFrm.cpp
These files contain the frame class CMainFrame, which is derived from
CFrameWnd and controls all SDI frame features.
res\Toolbar.bmp
This bitmap file is used to create tiled images for the toolbar.
The initial toolbar and status bar are constructed in the CMainFrame
class. Edit this toolbar bitmap using the resource editor, and
update the IDR_MAINFRAME TOOLBAR array in commtest.rc to add
toolbar buttons.
/////////////////////////////////////////////////////////////////////////////
AppWizard creates one document type and one view:
commtestDoc.h, commtestDoc.cpp - the document
These files contain your CCommtestDoc class. Edit these files to
add your special document data and to implement file saving and loading
(via CCommtestDoc::Serialize).
commtestView.h, commtestView.cpp - the view of the document
These files contain your CCommtestView class.
CCommtestView objects are used to view CCommtestDoc objects.
/////////////////////////////////////////////////////////////////////////////
Other standard files:
StdAfx.h, StdAfx.cpp
These files are used to build a precompiled header (PCH) file
named commtest.pch and a precompiled types file named StdAfx.obj.
Resource.h
This is the standard header file, which defines new resource IDs.
Microsoft Visual C++ reads and updates this file.
/////////////////////////////////////////////////////////////////////////////
Other notes:
AppWizard uses "TODO:" to indicate parts of the source code you
should add to or customize.
If your application uses MFC in a shared DLL, and your application is
in a language other than the operating system's current language, you
will need to copy the corresponding localized resources MFC42XXX.DLL
from the Microsoft Visual C++ CD-ROM onto the system or system32 directory,
and rename it to be MFCLOC.DLL. ("XXX" stands for the language abbreviation.
For example, MFC42DEU.DLL contains resources translated to German.) If you
don't do this, some of the UI elements of your application will remain in the
language of the operating system.
/////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,6 @@
// stdafx.cpp : source file that includes just the standard includes
// commtest.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"

View File

@@ -0,0 +1,27 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__61504886_AF87_11D4_8A97_00500424438B__INCLUDED_)
#define AFX_STDAFX_H__61504886_AF87_11D4_8A97_00500424438B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#include <afxcview.h>
#endif // _AFX_NO_AFXCMN_SUPPORT
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__61504886_AF87_11D4_8A97_00500424438B__INCLUDED_)

View File

@@ -0,0 +1,61 @@
// Filename:- bits.h
//
// some leftover stuff to get this compiling,
// mainly from model.h in modview but I couldn't include that directly here
// NOTE:!!!! It's ok for this to be ot of sync with the version in modview, there's no communication of the
// actual values. This is important to realise, even if this is only a test app.
#ifndef BITS_H
#define BITS_H
typedef int ModelHandle_t;
typedef struct
{
union
{
struct
{
unsigned int iItemType : 8; // allows 256 item types (see #defines below)
unsigned int iModelHandle : 8; // allows 256 models
unsigned int iItemNumber : 16; // allows 65536 surfaces, bones, sequences etc
};
//
UINT32 uiData;
};
} TreeItemData_t;
// max 256 of these...
//
typedef enum
{
TREEITEMTYPE_NULL=0, // nothing, ie usually a reasonable default for clicking on emptry tree space
TREEITEMTYPE_MODELNAME, // "modelname"
TREEITEMTYPE_SURFACEHEADER, // "surfaces"
TREEITEMTYPE_BONEHEADER, // "bones"
TREEITEMTYPE_BONEALIASHEADER, // "bone aliases"
TREEITEMTYPE_SEQUENCEHEADER, // "sequences"
TREEITEMTYPE_BOLTONSHEADER, // "BoltOns"
//
// Ones beyond here should have updated code in ModelTree_GetItemText() to handle pure enquiries if nec.
//
TREEITEMTYPE_GLM_SURFACE, // a surface (index in bottom bits, currently allows 65535 surfaces)
TREEITEMTYPE_GLM_BONE, // a bone (index in bottom bits, currently allows 65535 bones)
TREEITEMTYPE_GLM_BONEALIAS, // a bone alias (index in bottom bits, currently allows 65535 aliases)
TREEITEMTYPE_SEQUENCE, // a sequence (index in bottom bits, currently allows 65535 bones)
} TreeTypes_e;
#define GetYesNo(psQuery) (!!(AfxMessageBox(psQuery, MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES))
#endif // #ifndef BITS_H
///////////////////////// eof /////////////////////

View File

@@ -0,0 +1,172 @@
// commtest.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "commtest.h"
#include "../tools/modview/commarea.h"
#include "../tools/modview/wintalk.h"
#include "MainFrm.h"
#include "commtestDoc.h"
#include "commtestView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CCommtestApp
BEGIN_MESSAGE_MAP(CCommtestApp, CWinApp)
//{{AFX_MSG_MAP(CCommtestApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCommtestApp construction
CCommtestApp::CCommtestApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CCommtestApp object
CCommtestApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CCommtestApp initialization
bool gbCommInitialised = false;
BOOL CCommtestApp::InitInstance()
{
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CCommtestDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CCommtestView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
CommArea_ClientInitOnceOnly();
gbCommInitialised = true;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
// No message handlers
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// App command to run the dialog
void CCommtestApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
// CCommtestApp message handlers
int CCommtestApp::ExitInstance()
{
CommArea_ShutDown();
return CWinApp::ExitInstance();
}
BOOL CCommtestApp::OnIdle(LONG lCount)
{
WinTalk_HandleMessages();
return CWinApp::OnIdle(lCount);
}

View File

@@ -0,0 +1,190 @@
# Microsoft Developer Studio Project File - Name="commtest" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=commtest - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "commtest.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "commtest.mak" CFG="commtest - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "commtest - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "commtest - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/Tools/ModView/commtest", LGECAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "commtest - Win32 Release"
# PROP BASE Use_MFC 5
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 5
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
# ADD LINK32 /nologo /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "commtest - Win32 Debug"
# PROP BASE Use_MFC 5
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 5
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /Yu"stdafx.h" /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "commtest - Win32 Release"
# Name "commtest - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\Tools\ModView\CommArea.cpp
# End Source File
# Begin Source File
SOURCE=..\Tools\ModView\CommArea.h
# End Source File
# Begin Source File
SOURCE=.\commtest.cpp
# End Source File
# Begin Source File
SOURCE=.\commtest.rc
# End Source File
# Begin Source File
SOURCE=.\commtestDoc.cpp
# End Source File
# Begin Source File
SOURCE=.\commtestView.cpp
# End Source File
# Begin Source File
SOURCE=.\MainFrm.cpp
# End Source File
# Begin Source File
SOURCE=.\StdAfx.cpp
# ADD CPP /Yc"stdafx.h"
# End Source File
# Begin Source File
SOURCE=.\wintalk.cpp
# End Source File
# Begin Source File
SOURCE=..\Tools\ModView\wintalk.h
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\bits.h
# End Source File
# Begin Source File
SOURCE=.\commtest.h
# End Source File
# Begin Source File
SOURCE=.\commtestDoc.h
# End Source File
# Begin Source File
SOURCE=.\commtestView.h
# End Source File
# Begin Source File
SOURCE=.\MainFrm.h
# End Source File
# Begin Source File
SOURCE=.\Resource.h
# End Source File
# Begin Source File
SOURCE=.\StdAfx.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\res\commtest.ico
# End Source File
# Begin Source File
SOURCE=.\res\commtest.rc2
# End Source File
# Begin Source File
SOURCE=.\res\commtestDoc.ico
# End Source File
# Begin Source File
SOURCE=.\res\Toolbar.bmp
# End Source File
# End Group
# Begin Source File
SOURCE=.\ReadMe.txt
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,51 @@
// commtest.h : main header file for the COMMTEST application
//
#if !defined(AFX_COMMTEST_H__61504884_AF87_11D4_8A97_00500424438B__INCLUDED_)
#define AFX_COMMTEST_H__61504884_AF87_11D4_8A97_00500424438B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CCommtestApp:
// See commtest.cpp for the implementation of this class
//
class CCommtestApp : public CWinApp
{
public:
CCommtestApp();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCommtestApp)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
virtual BOOL OnIdle(LONG lCount);
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CCommtestApp)
afx_msg void OnAppAbout();
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_COMMTEST_H__61504884_AF87_11D4_8A97_00500424438B__INCLUDED_)

View File

@@ -0,0 +1,404 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"#define _AFX_NO_SPLITTER_RESOURCES\r\n"
"#define _AFX_NO_OLE_RESOURCES\r\n"
"#define _AFX_NO_TRACKER_RESOURCES\r\n"
"#define _AFX_NO_PROPERTY_RESOURCES\r\n"
"\r\n"
"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
"#ifdef _WIN32\r\n"
"LANGUAGE 9, 1\r\n"
"#pragma code_page(1252)\r\n"
"#endif //_WIN32\r\n"
"#include ""res\\commtest.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
"#include ""afxres.rc"" // Standard components\r\n"
"#include ""afxprint.rc"" // printing/print preview resources\r\n"
"#endif\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDR_MAINFRAME ICON DISCARDABLE "res\\commtest.ico"
IDR_COMMTETYPE ICON DISCARDABLE "res\\commtestDoc.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
IDR_MAINFRAME BITMAP MOVEABLE PURE "res\\Toolbar.bmp"
/////////////////////////////////////////////////////////////////////////////
//
// Toolbar
//
IDR_MAINFRAME TOOLBAR DISCARDABLE 16, 15
BEGIN
BUTTON ID_FILE_NEW
BUTTON ID_FILE_OPEN
BUTTON ID_FILE_SAVE
SEPARATOR
BUTTON ID_EDIT_CUT
BUTTON ID_EDIT_COPY
BUTTON ID_EDIT_PASTE
SEPARATOR
BUTTON ID_FILE_PRINT
SEPARATOR
BUTTON ID_APP_ABOUT
END
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_MAINFRAME MENU PRELOAD DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&New\tCtrl+N", ID_FILE_NEW
MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
MENUITEM "&Save\tCtrl+S", ID_FILE_SAVE
MENUITEM "Save &As...", ID_MODEL_SAVE_AS
MENUITEM SEPARATOR
MENUITEM "&Print...\tCtrl+P", ID_FILE_PRINT
MENUITEM "Print Pre&view", ID_FILE_PRINT_PREVIEW
MENUITEM "P&rint Setup...", ID_FILE_PRINT_SETUP
MENUITEM SEPARATOR
MENUITEM "Recent File", ID_FILE_MRU_FILE1, GRAYED
MENUITEM SEPARATOR
MENUITEM "E&xit", ID_APP_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Undo\tCtrl+Z", ID_EDIT_UNDO
MENUITEM SEPARATOR
MENUITEM "Load model garbagename", ID_EDIT_CUT
MENUITEM "Load model conetree4", ID_EDIT_COPY
MENUITEM "Load model jake", ID_EDIT_PASTE
MENUITEM "Load Model M4", ID_EDIT_M4
MENUITEM "ErrorBoxes OFF", ID_ERRORBOX_OFF
MENUITEM "ErrorBoxes ON", ID_ERRORBOX_ON
MENUITEM SEPARATOR
MENUITEM "Start Animation", ID_STARTANIM
MENUITEM "Start Animation (with wrap)", ID_STARTANIMWRAP
MENUITEM "Stop Animation", ID_STOPANIM
MENUITEM SEPARATOR
MENUITEM "Lock Sequence (primary model), + auto-inc seq #",
ID_LOCK_SEQUENCES
MENUITEM "Unlock All Sequences (primary model)", ID_UNLOCKALLSEQS
END
POPUP "&View"
BEGIN
MENUITEM "&Toolbar", ID_VIEW_TOOLBAR
MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR
END
POPUP "&Help"
BEGIN
MENUITEM "&About commtest...", ID_APP_ABOUT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE
BEGIN
"N", ID_FILE_NEW, VIRTKEY, CONTROL
"O", ID_FILE_OPEN, VIRTKEY, CONTROL
"S", ID_FILE_SAVE, VIRTKEY, CONTROL
"P", ID_FILE_PRINT, VIRTKEY, CONTROL
"Z", ID_EDIT_UNDO, VIRTKEY, CONTROL
"X", ID_EDIT_CUT, VIRTKEY, CONTROL
"C", ID_EDIT_COPY, VIRTKEY, CONTROL
"V", ID_EDIT_PASTE, VIRTKEY, CONTROL
VK_BACK, ID_EDIT_UNDO, VIRTKEY, ALT
VK_DELETE, ID_EDIT_CUT, VIRTKEY, SHIFT
VK_INSERT, ID_EDIT_COPY, VIRTKEY, CONTROL
VK_INSERT, ID_EDIT_PASTE, VIRTKEY, SHIFT
VK_F6, ID_NEXT_PANE, VIRTKEY
VK_F6, ID_PREV_PANE, VIRTKEY, SHIFT
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 235, 55
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About commtest"
FONT 8, "MS Sans Serif"
BEGIN
ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20
LTEXT "commtest Version 1.0",IDC_STATIC,40,10,119,8,
SS_NOPREFIX
LTEXT "Copyright (C) 2000",IDC_STATIC,40,25,119,8
DEFPUSHBUTTON "OK",IDOK,178,7,50,14,WS_GROUP
END
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "commtest MFC Application\0"
VALUE "FileVersion", "1, 0, 0, 1\0"
VALUE "InternalName", "commtest\0"
VALUE "LegalCopyright", "Copyright (C) 2000\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "commtest.EXE\0"
VALUE "ProductName", "commtest Application\0"
VALUE "ProductVersion", "1, 0, 0, 1\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // !_MAC
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_ABOUTBOX, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 228
TOPMARGIN, 7
BOTTOMMARGIN, 48
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
IDR_MAINFRAME "commtest\n\nCommte\n\n\nCommtest.Document\nCommte Document"
END
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
AFX_IDS_APP_TITLE "commtest"
AFX_IDS_IDLEMESSAGE "Ready"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_INDICATOR_EXT "EXT"
ID_INDICATOR_CAPS "CAP"
ID_INDICATOR_NUM "NUM"
ID_INDICATOR_SCRL "SCRL"
ID_INDICATOR_OVR "OVR"
ID_INDICATOR_REC "REC"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_FILE_NEW "Create a new document\nNew"
ID_FILE_OPEN "Open an existing document\nOpen"
ID_FILE_CLOSE "Close the active document\nClose"
ID_FILE_SAVE "Save the active document\nSave"
ID_MODEL_SAVE_AS "Save the active document with a new name\nSave As"
ID_FILE_PAGE_SETUP "Change the printing options\nPage Setup"
ID_FILE_PRINT_SETUP "Change the printer and printing options\nPrint Setup"
ID_FILE_PRINT "Print the active document\nPrint"
ID_FILE_PRINT_PREVIEW "Display full pages\nPrint Preview"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_APP_ABOUT "Display program information, version number and copyright\nAbout"
ID_APP_EXIT "Quit the application; prompts to save documents\nExit"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_FILE_MRU_FILE1 "Open this document"
ID_FILE_MRU_FILE2 "Open this document"
ID_FILE_MRU_FILE3 "Open this document"
ID_FILE_MRU_FILE4 "Open this document"
ID_FILE_MRU_FILE5 "Open this document"
ID_FILE_MRU_FILE6 "Open this document"
ID_FILE_MRU_FILE7 "Open this document"
ID_FILE_MRU_FILE8 "Open this document"
ID_FILE_MRU_FILE9 "Open this document"
ID_FILE_MRU_FILE10 "Open this document"
ID_FILE_MRU_FILE11 "Open this document"
ID_FILE_MRU_FILE12 "Open this document"
ID_FILE_MRU_FILE13 "Open this document"
ID_FILE_MRU_FILE14 "Open this document"
ID_FILE_MRU_FILE15 "Open this document"
ID_FILE_MRU_FILE16 "Open this document"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_NEXT_PANE "Switch to the next window pane\nNext Pane"
ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_WINDOW_SPLIT "Split the active window into panes\nSplit"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_EDIT_CLEAR "Erase the selection\nErase"
ID_EDIT_CLEAR_ALL "Erase everything\nErase All"
ID_EDIT_COPY "Copy the selection and put it on the Clipboard\nCopy"
ID_EDIT_CUT "Cut the selection and put it on the Clipboard\nCut"
ID_EDIT_FIND "Find the specified text\nFind"
ID_EDIT_PASTE "Insert Clipboard contents\nPaste"
ID_EDIT_REPEAT "Repeat the last action\nRepeat"
ID_EDIT_REPLACE "Replace specific text with different text\nReplace"
ID_EDIT_SELECT_ALL "Select the entire document\nSelect All"
ID_EDIT_UNDO "Undo the last action\nUndo"
ID_EDIT_REDO "Redo the previously undone action\nRedo"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_VIEW_TOOLBAR "Show or hide the toolbar\nToggle ToolBar"
ID_VIEW_STATUS_BAR "Show or hide the status bar\nToggle StatusBar"
END
STRINGTABLE DISCARDABLE
BEGIN
AFX_IDS_SCSIZE "Change the window size"
AFX_IDS_SCMOVE "Change the window position"
AFX_IDS_SCMINIMIZE "Reduce the window to an icon"
AFX_IDS_SCMAXIMIZE "Enlarge the window to full size"
AFX_IDS_SCNEXTWINDOW "Switch to the next document window"
AFX_IDS_SCPREVWINDOW "Switch to the previous document window"
AFX_IDS_SCCLOSE "Close the active window and prompts to save the documents"
END
STRINGTABLE DISCARDABLE
BEGIN
AFX_IDS_SCRESTORE "Restore the window to normal size"
AFX_IDS_SCTASKLIST "Activate Task List"
END
STRINGTABLE DISCARDABLE
BEGIN
AFX_IDS_PREVIEW_CLOSE "Close print preview mode\nCancel Preview"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#define _AFX_NO_SPLITTER_RESOURCES
#define _AFX_NO_OLE_RESOURCES
#define _AFX_NO_TRACKER_RESOURCES
#define _AFX_NO_PROPERTY_RESOURCES
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE 9, 1
#pragma code_page(1252)
#endif //_WIN32
#include "res\commtest.rc2" // non-Microsoft Visual C++ edited resources
#include "afxres.rc" // Standard components
#include "afxprint.rc" // printing/print preview resources
#endif
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,84 @@
// commtestDoc.cpp : implementation of the CCommtestDoc class
//
#include "stdafx.h"
#include "commtest.h"
#include "commtestDoc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CCommtestDoc
IMPLEMENT_DYNCREATE(CCommtestDoc, CDocument)
BEGIN_MESSAGE_MAP(CCommtestDoc, CDocument)
//{{AFX_MSG_MAP(CCommtestDoc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCommtestDoc construction/destruction
CCommtestDoc::CCommtestDoc()
{
// TODO: add one-time construction code here
}
CCommtestDoc::~CCommtestDoc()
{
}
BOOL CCommtestDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CCommtestDoc serialization
void CCommtestDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
/////////////////////////////////////////////////////////////////////////////
// CCommtestDoc diagnostics
#ifdef _DEBUG
void CCommtestDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CCommtestDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CCommtestDoc commands

View File

@@ -0,0 +1,57 @@
// commtestDoc.h : interface of the CCommtestDoc class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_COMMTESTDOC_H__6150488A_AF87_11D4_8A97_00500424438B__INCLUDED_)
#define AFX_COMMTESTDOC_H__6150488A_AF87_11D4_8A97_00500424438B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CCommtestDoc : public CDocument
{
protected: // create from serialization only
CCommtestDoc();
DECLARE_DYNCREATE(CCommtestDoc)
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCommtestDoc)
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CCommtestDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CCommtestDoc)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_COMMTESTDOC_H__6150488A_AF87_11D4_8A97_00500424438B__INCLUDED_)

View File

@@ -0,0 +1,471 @@
// commtestView.cpp : implementation of the CCommtestView class
//
#include "stdafx.h"
#include "commtest.h"
#include <assert.h>
#include "commtestDoc.h"
#include "commtestView.h"
#include "../tools/modview/wintalk.h"
#include "bits.h"
#include "mainfrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CCommtestView
IMPLEMENT_DYNCREATE(CCommtestView, CTreeView)
BEGIN_MESSAGE_MAP(CCommtestView, CTreeView)
//{{AFX_MSG_MAP(CCommtestView)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_TIMER()
ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CTreeView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CTreeView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CTreeView::OnFilePrintPreview)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCommtestView construction/destruction
CCommtestView* gpCommTestView = NULL;
CCommtestView::CCommtestView()
{
}
CCommtestView::~CCommtestView()
{
}
BOOL CCommtestView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
if (!CTreeView::PreCreateWindow(cs))
{
return FALSE;
}
cs.style |= TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS/* | TVS_EDITLABELS*/;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CCommtestView drawing
/////////////////////////////////////////////////////////////////////////////
// CCommtestView printing
BOOL CCommtestView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CCommtestView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CCommtestView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
/////////////////////////////////////////////////////////////////////////////
// CCommtestView diagnostics
#ifdef _DEBUG
void CCommtestView::AssertValid() const
{
CTreeView::AssertValid();
}
void CCommtestView::Dump(CDumpContext& dc) const
{
CTreeView::Dump(dc);
}
CCommtestDoc* CCommtestView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCommtestDoc)));
return (CCommtestDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CCommtestView message handlers
enum eTimerHandles
{
th_DO_NOT_USE = 0, // system reserved for NULL timer
th_100FPS = 1,
};
int CCommtestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CTreeView::OnCreate(lpCreateStruct) == -1)
return -1;
m_TimerHandle_Update100FPS = SetTimer( th_100FPS, // UINT nIDEvent,
200, // UINT nElapse, (in milliseconds)
NULL // void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD)
);
return 0;
}
BOOL CCommtestView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
m_TimerHandle_Update100FPS = 0;
BOOL b = CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
gpCommTestView = this;
HTREEITEM h = GetTreeCtrl().InsertItem("test_root_item", NULL);
GetTreeCtrl().InsertItem("child", h);
return b;
}
void CCommtestView::OnDestroy()
{
if (m_TimerHandle_Update100FPS)
{
bool bOk = !!KillTimer(m_TimerHandle_Update100FPS); // NZ return if good
if (bOk)
{
m_TimerHandle_Update100FPS = NULL;
}
else
{
// ErrorBox("Error killing timer!"); // should never happen
}
}
CTreeView::OnDestroy();
}
void CCommtestView::OnTimer(UINT nIDEvent)
{
if (nIDEvent != th_100FPS)
{
CTreeView::OnTimer(nIDEvent);
return;
}
// WinTalk_HandleMessages();
}
//DEL void CCommtestView::OnDraw(CDC* pDC)
//DEL {
//DEL CCommtestDoc* pDoc = GetDocument();
//DEL ASSERT_VALID(pDoc);
//DEL // TODO: add draw code for native data here
//DEL }
extern char *va(char *format, ...);
extern bool gbCommInitialised;
extern bool R_IsDescendantOf(HTREEITEM hTreeItem_This, HTREEITEM hTreeItem_Ancestor);
extern bool gbInhibit;
// search tree for an item whose userdata matches what's been passed...
//
// hTreeItem = tree item to start from, pass NULL to start from root
//
HTREEITEM R_ModelTree_FindItemWithThisData(HTREEITEM hTreeItem, UINT32 uiData2Match)
{
if (!hTreeItem)
hTreeItem = gpCommTestView->GetTreeCtrl().GetRootItem();
if (hTreeItem)
{
CString str(gpCommTestView->GetTreeCtrl().GetItemText(hTreeItem));
OutputDebugString(va("Scanning item %X (%s)\n",hTreeItem,(LPCSTR)str));
if (str=="BoltOns")
{
int x=1;
}
// check this tree item...
//
TreeItemData_t TreeItemData;
TreeItemData.uiData = gpCommTestView->GetTreeCtrl().GetItemData(hTreeItem);
// match?...
//
if (TreeItemData.uiData == uiData2Match)
return hTreeItem;
// check child...
//
HTREEITEM hTreeItem_Child = gpCommTestView->GetTreeCtrl().GetChildItem(hTreeItem);
if (hTreeItem_Child)
{
HTREEITEM hTreeItemFound = R_ModelTree_FindItemWithThisData(hTreeItem_Child, uiData2Match);
if (hTreeItemFound)
return hTreeItemFound;
}
// process siblings...
//
HTREEITEM hTreeItem_Sibling = gpCommTestView->GetTreeCtrl().GetNextSiblingItem(hTreeItem);
if (hTreeItem_Sibling)
{
HTREEITEM hTreeItemFound = R_ModelTree_FindItemWithThisData(hTreeItem_Sibling, uiData2Match);
if (hTreeItemFound)
return hTreeItemFound;
}
// this treeitem isnt a match, and neither are its siblings or children, so...
//
return NULL;
}
// we must have called this when the treeview was uninitialised... (duh!)
//
ASSERT(0);
return NULL;
}
void CCommtestView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
if (gbCommInitialised && GetTreeCtrl().GetCount() > 3 /*?*/ && !gbInhibit)
{
HTREEITEM hTreeItem = GetTreeCtrl().GetSelectedItem();
CString Text = GetTreeCtrl().GetItemText(hTreeItem);
TreeItemData_t TreeItemData;
TreeItemData.uiData = GetTreeCtrl().GetItemData(hTreeItem);
LPCSTR psArg = Text;
if (Text == "Bones")
psArg = "#all";
if (Text == "Surfaces")
psArg = "#all";
// LPCSTR psAnswer;
bool bOk = false;
/* if (R_IsDescendantOf(hTreeItem, ghTreeItem_Surfaces))
{
WinTalk_IssueCommand( "model_highlightbone #none");
bOk = WinTalk_IssueCommand(va("model_highlightsurface %s",psArg),NULL,0,&psAnswer);
}
else
if (R_IsDescendantOf(hTreeItem, ghTreeItem_Bones))
{
WinTalk_IssueCommand( "model_highlightsurface #none");
bOk = WinTalk_IssueCommand(va("model_highlightbone %s",psArg),NULL,0,&psAnswer);
}
else
{
WinTalk_IssueCommand( "model_highlightbone #none");
WinTalk_IssueCommand( "model_highlightsurface #none");
}
*/
WinTalk_IssueCommand(va("model_highlightbone %d #none",TreeItemData.iModelHandle));
WinTalk_IssueCommand(va("model_highlightsurface %d #none",TreeItemData.iModelHandle));
switch (TreeItemData.iItemType)
{
case TREEITEMTYPE_SURFACEHEADER: // "surfaces"
{
bOk = WinTalk_IssueCommand(va("model_highlightsurface %d #all",TreeItemData.iModelHandle));
}
break;
case TREEITEMTYPE_BONEHEADER: // "bones"
{
bOk = WinTalk_IssueCommand(va("model_highlightbone %d #all",TreeItemData.iModelHandle));
}
break;
case TREEITEMTYPE_GLM_SURFACE: // a surface
{
bOk = WinTalk_IssueCommand(va("model_highlightsurface %d %s",TreeItemData.iModelHandle, psArg));
}
break;
case TREEITEMTYPE_BONEALIASHEADER: // alias header
{
bOk = WinTalk_IssueCommand(va("model_highlightbone %d #aliased",TreeItemData.iModelHandle));
}
break;
case TREEITEMTYPE_GLM_BONEALIAS: // a bone alias
case TREEITEMTYPE_GLM_BONE: // a bone
{
// WinTalk_IssueCommand(va("model_highlightsurface %d #none",TreeItemData.iModelHandle));
bOk = WinTalk_IssueCommand(va("model_highlightbone %d %s",TreeItemData.iModelHandle, psArg));
}
break;
}
if (bOk)
{
//
}
else
{
// assert(0);
}
}
*pResult = 0;
}
// "psInitialLoadName" param can be "" if not bothered, "psInitialDir" can be NULL to open to last browse-dir
//
// psFilter example: TEXT("Model files (*.glm)|*.glm|All Files(*.*)|*.*||") // LPCSTR psFilter
//
char *InputLoadFileName(LPCSTR psInitialLoadName, LPCSTR psCaption, LPCSTR psInitialDir, LPCSTR psFilter)
{
CFileStatus Filestatus;
CFile File;
static char name[MAX_PATH];
CFileDialog FileDlg(TRUE, NULL, NULL,
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
//TEXT("Map Project Files (*.mpj)|*.lit|Other Map Files (*.smd/*.sc2)|*.sc2;*.smd|FastMap Files (*.fmf)|*.fmf|All Files(*.*)|*.*||"), //Map Object Files|*.sms||"),
psFilter, //Map Object Files|*.sms||"),
AfxGetMainWnd());
static CString strInitialDir;
if (psInitialDir)
strInitialDir = psInitialDir;
FileDlg.m_ofn.lpstrInitialDir = (LPCSTR) strInitialDir;
FileDlg.m_ofn.lpstrTitle=psCaption; // Load Editor Model";
strcpy(name,psInitialLoadName);
FileDlg.m_ofn.lpstrFile=name;
if (FileDlg.DoModal() == IDOK)
{
return name;
}
return NULL;
}
LPCSTR Model_GetSupportedTypesFilter(void)
{
return "Model files (*.glm)|*.glm|All Files(*.*)|*.*||";
}
void CCommtestView::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
if (gbCommInitialised && GetTreeCtrl().GetCount() > 3 /*?*/ && !gbInhibit)
{
HTREEITEM hTreeItem = GetTreeCtrl().GetSelectedItem();
CString Text = GetTreeCtrl().GetItemText(hTreeItem);
TreeItemData_t TreeItemData;
TreeItemData.uiData = GetTreeCtrl().GetItemData(hTreeItem);
bool bOk = false;
/* if (R_IsDescendantOf(hTreeItem, ghTreeItem_Surfaces))
{
WinTalk_IssueCommand( "model_highlightbone #none");
bOk = WinTalk_IssueCommand(va("model_highlightsurface %s",psArg),NULL,0,&psAnswer);
}
else
if (R_IsDescendantOf(hTreeItem, ghTreeItem_Bones))
{
WinTalk_IssueCommand( "model_highlightsurface #none");
bOk = WinTalk_IssueCommand(va("model_highlightbone %s",psArg),NULL,0,&psAnswer);
}
else
{
WinTalk_IssueCommand( "model_highlightbone #none");
WinTalk_IssueCommand( "model_highlightsurface #none");
}
*/
switch (TreeItemData.iItemType)
{
case TREEITEMTYPE_MODELNAME:
{
// is this a bolted model or the root (find out by seeing if its parent is a "BoltOns" treeitem)...
//
HTREEITEM hTreeItemParent = GetTreeCtrl().GetParentItem(hTreeItem);
if (hTreeItemParent)
{
TreeItemData_t TreeItemData_Parent;
TreeItemData_Parent.uiData = GetTreeCtrl().GetItemData(hTreeItemParent);
if (TreeItemData_Parent.iItemType == TREEITEMTYPE_BOLTONSHEADER)
{
//if (GetYesNo("Unbolt/discard this model?"))
{
//<modelhandle of bolted thing to delete>
WinTalk_IssueCommand(va("model_deletebolton %d",TreeItemData.iModelHandle));
GetTreeCtrl().DeleteItem(hTreeItem);
}
}
}
}
break;
case TREEITEMTYPE_GLM_BONE: // a bone
{
extern CMainFrame* gCMainFrame;
if (gCMainFrame)
{
char *psFullPathedFilename = InputLoadFileName( "", // LPCSTR psInitialLoadName,
"Load Model", // LPCSTR psCaption,
"S:\\base\\models\\test\\conetree4", // LPCSTR psInitialDir,
Model_GetSupportedTypesFilter() // LPCSTR psFilter
);
if (psFullPathedFilename)
{
gCMainFrame->BoltModel(TreeItemData.iModelHandle, Text, psFullPathedFilename);
}
}
}
break;
}
if (bOk)
{
//
}
else
{
// assert(0);
}
}
*pResult = 0;
}

View File

@@ -0,0 +1,74 @@
// commtestView.h : interface of the CCommtestView class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_COMMTESTVIEW_H__6150488C_AF87_11D4_8A97_00500424438B__INCLUDED_)
#define AFX_COMMTESTVIEW_H__6150488C_AF87_11D4_8A97_00500424438B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CCommtestView : public CTreeView
{
protected: // create from serialization only
CCommtestView();
DECLARE_DYNCREATE(CCommtestView)
// Attributes
public:
CCommtestDoc* GetDocument();
UINT m_TimerHandle_Update100FPS;
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCommtestView)
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CCommtestView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CCommtestView)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDblclk(NMHDR* pNMHDR, LRESULT* pResult);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#ifndef _DEBUG // debug version in commtestView.cpp
inline CCommtestDoc* CCommtestView::GetDocument()
{ return (CCommtestDoc*)m_pDocument; }
#endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
extern CCommtestView* gpCommTestView;
#endif // !defined(AFX_COMMTESTVIEW_H__6150488C_AF87_11D4_8A97_00500424438B__INCLUDED_)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,13 @@
//
// COMMTEST.RC2 - resources Microsoft Visual C++ does not edit directly
//
#ifdef APSTUDIO_INVOKED
#error this file is not editable by Microsoft Visual C++
#endif //APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
// Add manually edited resources here...
/////////////////////////////////////////////////////////////////////////////

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,27 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by commtest.rc
//
#define IDD_ABOUTBOX 100
#define IDR_MAINFRAME 128
#define IDR_COMMTETYPE 129
#define ID_ERRORBOX_OFF 32771
#define ID_ERRORBOX_ON 32772
#define ID_EDIT_M4 32773
#define ID_STARTANIM 32775
#define ID_STOPANIM 32776
#define ID_STARTANIMWRAP 32777
#define ID_LOCK_SEQUENCES 32778
#define ID_UNLOCKALLSEQS 32779
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 130
#define _APS_NEXT_COMMAND_VALUE 32780
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,308 @@
// Filename:- wintalk.cpp
//
// a module containing code for talking to other windows apps via a shared memory space...
//
#include "stdafx.h"
#include <assert.h>
#include "commtestDoc.h"
#include "commtestview.h"
//#include <winbase.h>
#include "../tools/modview/CommArea.h"
//
#include "../tools/modview/wintalk.h"
#ifndef ZEROMEM
#define ZEROMEM(blah) memset(&blah,0,sizeof(blah))
#endif
void ErrorBox(const char *sString)
{
MessageBox( NULL, sString, "Error", MB_OK|MB_ICONERROR|MB_TASKMODAL );
}
void InfoBox(const char *sString)
{
MessageBox( NULL, sString, "Info", MB_OK|MB_ICONINFORMATION|MB_TASKMODAL );
}
void WarningBox(const char *sString)
{
MessageBox( NULL, sString, "Warning", MB_OK|MB_ICONWARNING|MB_TASKMODAL );
}
char *va(char *format, ...)
{
va_list argptr;
static char string[16][1024];
static index = 0;
index = (++index)&15;
va_start (argptr, format);
vsprintf (string[index], format,argptr);
va_end (argptr);
return string[index];
}
// this'll return a string of up to the first 4095 chars of a system error message...
//
LPCSTR SystemErrorString(DWORD dwError)
{
static char sString[4096];
LPVOID lpMsgBuf=0;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
ZEROMEM(sString);
strncpy(sString,(LPCSTR) lpMsgBuf,sizeof(sString)-1);
LocalFree( lpMsgBuf );
return sString;
}
//void SystemErrorBox(DWORD dwError)
extern HWND g_hWnd;
#define GetYesNo(psQuery) (!!(MessageBox(g_hWnd,psQuery,"Query",MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES))
//////////////////////////////////////////////////////////////////////////////
static LPCSTR FindWhitespace(LPCSTR psString)
{
while (*psString && !isspace(*psString)) psString++;
return psString;
}
static LPCSTR SkipWhitespace(LPCSTR psString)
{
while (isspace(*psString)) psString++;
return psString;
}
// every case here must either do CommArea_CommandAck(...) or CommArea_CommandError(...),
// failure to do this is amazingly bad!!!
//
static void HandleCommands(LPCSTR psString, byte *pbCommandData, int iCommandDataSize)
{
/*
#define IF_ARG(string) if (!strncmp(psArg,string,strlen(string)))
#define NEXT_ARG SkipWhitespace(FindWhitespace(psArg))
LPCSTR psArg = psString;
IF_ARG("model_loadprimary")
{
psArg = NEXT_ARG;
if (Document_ModelLoadPrimary( psArg ))
{
CommArea_CommandAck();
}
else
{
CommArea_CommandError(va("ModView: Failed command: \"model_loadprimary %s\"\"", psArg));
}
}
else
IF_ARG("modeltree_getrootsurface")
{
// for this command, just send back whatever the answer is without validating...
//
HTREEITEM hTreeItem = ModelTree_GetRootSurface(Model_GetPrimaryHandle());
CommArea_CommandAck(va("%d",hTreeItem));
}
else
IF_ARG("modeltree_getrootbone")
{
// for this command, just send back whatever the answer is without validating...
//
HTREEITEM hTreeItem = ModelTree_GetRootBone(Model_GetPrimaryHandle());
CommArea_CommandAck(va("%d",hTreeItem));
}
else
// this version MUST be the first of the two, or the shorter one will early-match even a long command
IF_ARG("modeltree_getitemtextpure") // "...pure" will skip stuff like "////" for disabled surfaces
{
psArg = NEXT_ARG;
HTREEITEM hTreeItem = (HTREEITEM) atoi(psArg);
LPCSTR psText = ModelTree_GetItemText(hTreeItem,true);
CommArea_CommandAck(psText);
}
else
IF_ARG("modeltree_getitemtext")
{
psArg = NEXT_ARG;
HTREEITEM hTreeItem = (HTREEITEM) atoi(psArg);
LPCSTR psText = ModelTree_GetItemText(hTreeItem);
CommArea_CommandAck(psText);
}
else
IF_ARG("modeltree_getchilditem")
{
psArg = NEXT_ARG;
HTREEITEM hTreeItem = (HTREEITEM) atoi(psArg);
hTreeItem = ModelTree_GetChildItem(hTreeItem);
CommArea_CommandAck(va("%d",hTreeItem));
}
else
IF_ARG("modeltree_getnextsiblingitem")
{
psArg = NEXT_ARG;
HTREEITEM hTreeItem = (HTREEITEM) atoi(psArg);
hTreeItem = ModelTree_GetNextSiblingItem(hTreeItem);
CommArea_CommandAck(va("%d",hTreeItem));
}
else
{
// unknown command...
//
CommArea_CommandError(va("ModView: Unknown command \"%s\"", psString));
}
*/
InfoBox(va("CommsTest: Command recieved: \"%s\"",psString));
if (GetYesNo("CommsTest: Report as error? ('NO' will report success)"))
{
CommArea_CommandError(va("CommsTest: Failed to complete task '%s'", psString));
}
else
{
CommArea_CommandAck();
}
}
static bool bDoNotEnterHandler = false; // Modal dialogue boxes can cause problems with re-entrance
void WinTalk_HandleMessages(void)
{
if (!bDoNotEnterHandler)
{
bDoNotEnterHandler = true;
if (!CommArea_IsIdle())
{
CWaitCursor wait;
byte *pbCommandData = NULL;
int iCommandDataSize;
LPCSTR psString;
if ((psString = CommArea_IsCommandWaiting( &pbCommandData, &iCommandDataSize )) != NULL)
{
HandleCommands(psString, pbCommandData, iCommandDataSize);
}
else
if ((psString = CommArea_IsErrorWaiting()) != NULL)
{
assert(0); // I don't think we should ever get here, but just in case...
ErrorBox(va("CommTest: Other program reported an error:\n\n\"%s\"",psString));
CommArea_CommandClear();
}
}
bDoNotEnterHandler = false;
}
}
// return is success / fail
//
bool WinTalk_IssueCommand( LPCSTR psCommand,
byte *pbData, // optional extra command data (current max = 64k)
int iDataSize, // sizeof above
LPCSTR *ppsResultPassback, // optional result passback if expecting an answer string
byte **ppbDataPassback, // optional data passback if expecting a data result
int *piDataSizePassback // optional size of above if you need it supplying
)
{
bool bError = false;
while (!CommArea_IsIdle())
{
WinTalk_HandleMessages();
}
bDoNotEnterHandler = true;
{
CommArea_IssueCommand(psCommand, pbData, iDataSize);
// wait until command is acknowledged or has failed... (you may want a sanity check timeout?)
//
CWaitCursor wait;
while (1)
{
LPCSTR psReply;
if ((psReply = CommArea_IsAckWaiting(ppbDataPassback,piDataSizePassback)) != NULL)
{
if ( ppsResultPassback)
*ppsResultPassback = psReply;
bError = false;
break;
}
if ((psReply = CommArea_IsErrorWaiting()) != NULL)
{
ErrorBox(va("Other program reported an error:\n\n\"%s\"",psReply));
bError = true;
break;
}
Sleep(0); // needed to avoid hogging all CPU time :-)
}
// you MUST do this...
//
CommArea_CommandClear();
/* {
gpCommTestView->GetTreeCtrl().DeleteAllItems();
gpCommTestView->GetTreeCtrl().InsertItem("hello");
}
*/
}
bDoNotEnterHandler = false;
return !bError;
}
////////////////////// eof ////////////////

View File

@@ -0,0 +1,33 @@
// hide these nasty warnings
#ifdef _WIN32
#pragma warning(disable : 4018) // signed/unsigned mismatch
#pragma warning(disable : 4032)
#pragma warning(disable : 4051)
#pragma warning(disable : 4057) // slightly different base types
#pragma warning(disable : 4100) // unreferenced formal parameter
#pragma warning(disable : 4115)
#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence
#pragma warning(disable : 4127) // conditional expression is constant
#pragma warning(disable : 4136)
#pragma warning(disable : 4152) // nonstandard extension, function/data pointer conversion in expression
#pragma warning(disable : 4201)
#pragma warning(disable : 4214)
#pragma warning(disable : 4244) // conversion from double to float
#pragma warning(disable : 4284) // return type not UDT
#pragma warning(disable : 4305) // truncation from const double to float
#pragma warning(disable : 4310) // cast truncates constant value
#pragma warning(disable : 4503) // decorated name length truncated
#pragma warning(disable: 4505) // unreferenced local function has been removed
#pragma warning(disable : 4511) //copy ctor could not be genned
#pragma warning(disable : 4512) //assignment op could not be genned
#pragma warning(disable : 4514) // unreffed inline removed
#pragma warning(disable : 4663) // c++ lang change
//#pragma warning(disable : 4702) // unreachable code
#pragma warning(disable : 4710) // not inlined
#pragma warning(disable : 4711) // selected for automatic inline expansion
#pragma warning(disable : 4220) // varargs matches remaining parameters
#pragma warning(disable : 4786) //identifier was truncated
#endif

146
tools/ModView/drag.cpp Normal file
View File

@@ -0,0 +1,146 @@
// Filename:- drag.cpp
//
#include "stdafx.h"
#include "includes.h"
#include "model.h"
//
#include "drag.h"
const float MOUSE_ROT_SCALE = 0.5f;
const float MOUSE_ZPOS_SCALE = 0.1f;
const float MOUSE_XPOS_SCALE = 0.1f;
const float MOUSE_YPOS_SCALE = 0.1f;
int m_x, m_y;
/*! commands to handle mouse dragging, uses key_flags defines above */
void start_drag( mkey_enum keyFlags, int x, int y )
{
m_x = x;
m_y = y;
}
static bool drag_actual( mkey_enum keyFlags, int x, int y )
{
bool bRepaintAndSetCursor = false;
if ( keyFlags != 0 )
{
if ( keyFlags & KEY_LBUTTON )
{
if ((x != m_x) || (y != m_y))
{
short s = GetAsyncKeyState(VK_MENU);
if (s & 0x8000)
{
AppVars.xPos += ((float)(x - m_x)/10.f) * MOUSE_XPOS_SCALE;
AppVars.yPos -= ((float)(y - m_y)/10.f) * MOUSE_YPOS_SCALE;
}
else
{
s = GetAsyncKeyState(0x5A); // Z key
if ( s&0x8000)
{
AppVars.rotAngleZ += (float)(x - m_x) * MOUSE_ROT_SCALE;
// AppVars.rotAngleZ += (float)(y - m_y) * MOUSE_ROT_SCALE;
if (AppVars.rotAngleZ> 360.0f) AppVars.rotAngleZ=AppVars.rotAngleZ-360.0f;
if (AppVars.rotAngleZ<-360.0f) AppVars.rotAngleZ=AppVars.rotAngleZ+360.0f;
}
else
{
AppVars.rotAngleY += (float)(x - m_x) * MOUSE_ROT_SCALE;
AppVars.rotAngleX += (float)(y - m_y) * MOUSE_ROT_SCALE;
if (AppVars.rotAngleY> 360.0f) AppVars.rotAngleY=AppVars.rotAngleY-360.0f;
if (AppVars.rotAngleY<-360.0f) AppVars.rotAngleY=AppVars.rotAngleY+360.0f;
if (AppVars.rotAngleX> 360.0f) AppVars.rotAngleX=AppVars.rotAngleX-360.0f;
if (AppVars.rotAngleX<-360.0f) AppVars.rotAngleX=AppVars.rotAngleX+360.0f;
}
}
bRepaintAndSetCursor = true;
}
} else
if ( keyFlags & KEY_RBUTTON )
{
if ( y != m_y )
{
AppVars.zPos += ((float)(y - m_y)/10.f) * MOUSE_ZPOS_SCALE;
if (AppVars.zPos<-1000.f) AppVars.zPos=-1000.f;
if (AppVars.zPos> 1000.f) AppVars.zPos= 1000.f;
bRepaintAndSetCursor = true;
}
}
}
return bRepaintAndSetCursor;
}
bool gbScrollLockActive = false;
bool drag( mkey_enum keyFlags, int x, int y )
{
bool bRepaintAndSetCursor = false;
float xPos = AppVars.xPos;
float yPos = AppVars.yPos;
float zPos = AppVars.zPos;
float rotAngleX = AppVars.rotAngleX;
float rotAngleY = AppVars.rotAngleY;
float rotAngleZ = AppVars.rotAngleZ;
SHORT s = GetKeyState(VK_SCROLL);
if (s&1)
{
// OutputDebugString("scroll lock ON\n");
if (!gbScrollLockActive)
{
// reset vars when first activating...
AppVars.xPos_SCROLL = AppVars.yPos_SCROLL = AppVars.zPos_SCROLL = 0.0f;
AppVars.rotAngleX_SCROLL = AppVars.rotAngleY_SCROLL = AppVars.rotAngleZ_SCROLL = 0.0f;
AppVars.xPos_SCROLL = AppVars.xPos;
AppVars.yPos_SCROLL = AppVars.yPos;
AppVars.zPos_SCROLL = AppVars.zPos;
//gbScrollLockActive = true;
}
}
else
{
// OutputDebugString("scroll lock OFF\n");
gbScrollLockActive = false;
}
bool b = drag_actual( keyFlags, x, y );
if (gbScrollLockActive)
{
#define BLAHBLAH(arg) AppVars.arg ## _SCROLL += (AppVars.arg - arg); AppVars.arg = arg;
BLAHBLAH(xPos);
BLAHBLAH(yPos);
BLAHBLAH(zPos);
// BLAHBLAH(rotAngleX);
// BLAHBLAH(rotAngleY);
// BLAHBLAH(rotAngleZ);
}
return b;
}
void end_drag( mkey_enum keyFlags, int x, int y )
{
}
///////////////////// eof /////////////////////

25
tools/ModView/drag.h Normal file
View File

@@ -0,0 +1,25 @@
// Filename:- drag.h
//
#ifndef DRAG_H
#define DRAG_H
enum mkey_enum {
KEY_LBUTTON = MK_LBUTTON,
KEY_RBUTTON = MK_RBUTTON,
KEY_MBUTTON = MK_MBUTTON
};
void start_drag( mkey_enum keyFlags, int x, int y );
bool drag( mkey_enum keyFlags, int x, int y );
void end_drag( mkey_enum keyFlags, int x, int y );
#endif // #ifndef DRAG_H
///////////// eof ///////////

335
tools/ModView/files.cpp Normal file
View File

@@ -0,0 +1,335 @@
// Filename:- files.h
//
#include "stdafx.h"
#include "includes.h"
#include <io.h>
#include "R_Common.h"
//#include "R_Image.h"
//
#include "files.h"
/*
============
Com_StringContains
============
*/
char *Com_StringContains(char *str1, char *str2, int casesensitive) {
int len, i, j;
len = strlen(str1) - strlen(str2);
for (i = 0; i <= len; i++, str1++) {
for (j = 0; str2[j]; j++) {
if (casesensitive) {
if (str1[j] != str2[j]) {
break;
}
}
else {
if (toupper(str1[j]) != toupper(str2[j])) {
break;
}
}
}
if (!str2[j]) {
return str1;
}
}
return NULL;
}
/*
============
Com_Filter
============
*/
int Com_Filter(char *filter, char *name, int casesensitive)
{
char buf[MAX_TOKEN_CHARS];
char *ptr;
int i, found;
while(*filter) {
if (*filter == '*') {
filter++;
for (i = 0; *filter; i++) {
if (*filter == '*' || *filter == '?') break;
buf[i] = *filter;
filter++;
}
buf[i] = '\0';
if (strlen(buf)) {
ptr = Com_StringContains(name, buf, casesensitive);
if (!ptr) return qfalse;
name = ptr + strlen(buf);
}
}
else if (*filter == '?') {
filter++;
name++;
}
else if (*filter == '[' && *(filter+1) == '[') {
filter++;
}
else if (*filter == '[') {
filter++;
found = qfalse;
while(*filter && !found) {
if (*filter == ']' && *(filter+1) != ']') break;
if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
if (casesensitive) {
if (*name >= *filter && *name <= *(filter+2)) found = qtrue;
}
else {
if (toupper(*name) >= toupper(*filter) &&
toupper(*name) <= toupper(*(filter+2))) found = qtrue;
}
filter += 3;
}
else {
if (casesensitive) {
if (*filter == *name) found = qtrue;
}
else {
if (toupper(*filter) == toupper(*name)) found = qtrue;
}
filter++;
}
}
if (!found) return qfalse;
while(*filter) {
if (*filter == ']' && *(filter+1) != ']') break;
filter++;
}
filter++;
name++;
}
else {
if (casesensitive) {
if (*filter != *name) return qfalse;
}
else {
if (toupper(*filter) != toupper(*name)) return qfalse;
}
filter++;
name++;
}
}
return qtrue;
}
/*
============
Com_FilterPath
============
*/
int Com_FilterPath(char *filter, char *name, int casesensitive)
{
int i;
char new_filter[MAX_QPATH];
char new_name[MAX_QPATH];
for (i = 0; i < MAX_QPATH-1 && filter[i]; i++) {
if ( filter[i] == '\\' || filter[i] == ':' ) {
new_filter[i] = '/';
}
else {
new_filter[i] = filter[i];
}
}
new_filter[i] = '\0';
for (i = 0; i < MAX_QPATH-1 && name[i]; i++) {
if ( name[i] == '\\' || name[i] == ':' ) {
new_name[i] = '/';
}
else {
new_name[i] = name[i];
}
}
new_name[i] = '\0';
return Com_Filter(new_filter, new_name, casesensitive);
}
void *Z_Malloc(int size)
{
return malloc(size);
}
void Z_Free(void *mem)
{
free(mem);
}
void *S_Malloc(int size)
{
return Z_Malloc(size);
}
/*
=================================================================================
DIRECTORY SCANNING FUNCTIONS
=================================================================================
*/
#define MAX_FOUND_FILES 0x1000
char *CopyString( const char *in ) {
char *out;
out = (char *)S_Malloc (strlen(in)+1);
strcpy (out, in);
return out;
}
void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **flist, int *numfiles ) {
char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
char filename[MAX_OSPATH];
int findhandle;
struct _finddata_t findinfo;
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
return;
}
if (strlen(subdirs)) {
Com_sprintf( search, sizeof(search), "%s\\%s\\*", basedir, subdirs );
}
else {
Com_sprintf( search, sizeof(search), "%s\\*", basedir );
}
findhandle = _findfirst (search, &findinfo);
if (findhandle == -1) {
return;
}
do {
if (findinfo.attrib & _A_SUBDIR) {
if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) {
if (strlen(subdirs)) {
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name);
}
else {
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", findinfo.name);
}
Sys_ListFilteredFiles( basedir, newsubdirs, filter, flist, numfiles );
}
}
if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
break;
}
Com_sprintf( filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name );
if (!Com_FilterPath( filter, filename, qfalse ))
continue;
flist[ *numfiles ] = CopyString( filename );
(*numfiles)++;
} while ( _findnext (findhandle, &findinfo) != -1 );
_findclose (findhandle);
}
char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) {
char search[MAX_OSPATH];
int nfiles;
char **listCopy;
char *list[MAX_FOUND_FILES];
struct _finddata_t findinfo;
int findhandle;
int flag;
int i;
if (filter) {
nfiles = 0;
Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
list[ nfiles ] = 0;
*numfiles = nfiles;
if (!nfiles)
return NULL;
listCopy = (char **)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
for ( i = 0 ; i < nfiles ; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
return listCopy;
}
if ( !extension) {
extension = "";
}
// passing a slash as extension will find directories
if ( extension[0] == '/' && extension[1] == 0 ) {
extension = "";
flag = 0;
} else {
flag = _A_SUBDIR;
}
Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension );
// search
nfiles = 0;
findhandle = _findfirst (search, &findinfo);
if (findhandle == -1) {
*numfiles = 0;
return NULL;
}
do {
if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {
if ( nfiles == MAX_FOUND_FILES - 1 ) {
break;
}
list[ nfiles ] = CopyString( findinfo.name );
nfiles++;
}
} while ( _findnext (findhandle, &findinfo) != -1 );
list[ nfiles ] = 0;
_findclose (findhandle);
// return a copy of the list
*numfiles = nfiles;
if ( !nfiles ) {
return NULL;
}
listCopy = (char **)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
for ( i = 0 ; i < nfiles ; i++ ) {
listCopy[i] = list[i];
}
listCopy[i] = NULL;
return listCopy;
}
void Sys_FreeFileList( char **flist ) {
int i;
if ( !flist ) {
return;
}
for ( i = 0 ; flist[i] ; i++ ) {
Z_Free( flist[i] );
}
Z_Free( flist );
}

26
tools/ModView/files.h Normal file
View File

@@ -0,0 +1,26 @@
// Filename:- files.h
//
#ifndef FILES_H
#define FILES_H
char* Com_StringContains(char *str1, char *str2, int casesensitive);
int Com_Filter(char *filter, char *name, int casesensitive);
int Com_FilterPath(char *filter, char *name, int casesensitive);
void* Z_Malloc(int size);
void Z_Free(void *mem);
void* S_Malloc(int size);
char *CopyString( const char *in );
void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **flist, int *numfiles );
char** Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs );
void Sys_FreeFileList( char **flist );
#endif // #ifndef FILES_H
/////////////////////// eof ////////////////////////

View File

@@ -0,0 +1,808 @@
// Filename: generic_stuff.cpp
//
#include "stdafx.h"
#include "includes.h"
#include "MainFrm.h"
//
#include "generic_stuff.h"
#define BASEDIRNAME "base"
#define BASEDIRNAME_XMEN "development"
// kept as non-hungarian labels purely because these 2 are so common in our projects...
//
char qdir[1024]={0}; // "S:\"
char gamedir[1024]={0}; // "S:\\baseq3\\"
// unlike "normal" SetQdirFromPath() functions, I need to see if qdir has changed
// (ie by loading an EF model over an SOF model) which could mean that we're in a different dir, and so
// should lose all cached textures etc...
//
bool bXMenPathHack = false;
bool bQ3RulesApply = true;
static bool SetQdirFromPath2( const char *path, const char *psBaseDir );
void SetQdirFromPath( const char *path )
{
char prevQdir[1024];
strcpy(prevQdir,qdir);
bXMenPathHack = false; // MUST be here
if (SetQdirFromPath2(path,BASEDIRNAME))
{
bQ3RulesApply = true;
}
else
{
if (SetQdirFromPath2(path,BASEDIRNAME_XMEN))
{
bQ3RulesApply = false;
bXMenPathHack = true;
}
}
if (stricmp(prevQdir,qdir))
{
extern void Media_Delete(void);
Media_Delete();
}
}
static bool SetQdirFromPath2( const char *path, const char *psBaseDir )
{
// static bool bDone = false;
// if (!bDone)
{
// bDone = true;
char temp[1024];
strcpy(temp,path);
path = temp;
const char *c;
const char *sep;
int len, count;
// if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
// { // path is partial
// Q_getwd (temp);
// strcat (temp, path);
// path = temp;
// }
_strlwr((char*)path);
// search for "base" in path from the RIGHT hand side (and must have a [back]slash just before it)
len = strlen(psBaseDir);
for (c=path+strlen(path)-1 ; c != path ; c--)
{
int i;
if (!strnicmp (c, psBaseDir, len)
&&
(*(c-1) == '/' || *(c-1) == '\\') // would be more efficient to do this first, but only checking after a strncasecmp ok ensures no invalid pointer-1 access
)
{
sep = c + len;
count = 1;
while (*sep && *sep != '/' && *sep != '\\')
{
sep++;
count++;
}
strncpy (gamedir, path, c+len+count-path);
gamedir[c+len+count-path]='\0';
for ( i = 0; i < (int)strlen( gamedir ); i++ )
{
if ( gamedir[i] == '\\' )
gamedir[i] = '/';
}
// qprintf ("gamedir: %s\n", gamedir);
strncpy (qdir, path, c-path);
qdir[c-path] = 0;
for ( i = 0; i < (int)strlen( qdir ); i++ )
{
if ( qdir[i] == '\\' )
qdir[i] = '/';
}
// qprintf ("qdir: %s\n", qdir);
return true;
}
}
// Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path);
}
return false;
}
// takes (eg) "q:\quake\baseq3\textures\borg\name.tga"
//
// and produces "textures/borg/name.tga"
//
void Filename_RemoveQUAKEBASE(CString &string)
{
string.Replace("\\","/");
string.MakeLower();
/*
int loc = string.Find("/quake");
if (loc >=0 )
{
loc = string.Find("/",loc+1);
if (loc >=0)
{
// now pointing at "baseq3", "demoq3", whatever...
loc = string.Find("/", loc+1);
if (loc >= 0)
{
// now pointing at local filename...
//
string = string.Mid(loc+1);
}
}
}
*/
// SetQdirFromPath( string );
string.Replace( gamedir, "" );
}
bool FileExists (LPCSTR psFilename)
{
FILE *handle = fopen(psFilename, "r");
if (!handle)
{
return false;
}
fclose (handle);
return true;
}
long FileLen( LPCSTR psFilename)
{
FILE *handle = fopen(psFilename, "r");
if (!handle)
{
return -1;
}
long l = filesize(handle);
fclose (handle);
return l;
}
// returns actual filename only, no path
//
char *Filename_WithoutPath(LPCSTR psFilename)
{
static char sString[MAX_PATH];
/*
LPCSTR p = strrchr(psFilename,'\\');
if (!p++)
{
p = strrchr(psFilename,'/');
if (!p++)
p=psFilename;
}
strcpy(sString,p);
*/
LPCSTR psCopyPos = psFilename;
while (*psFilename)
{
if (*psFilename == '/' || *psFilename == '\\')
psCopyPos = psFilename+1;
psFilename++;
}
strcpy(sString,psCopyPos);
return sString;
}
// returns (eg) "\dir\name" for "\dir\name.bmp"
//
char *Filename_WithoutExt(LPCSTR psFilename)
{
static char sString[MAX_PATH];
strcpy(sString,psFilename);
char *p = strrchr(sString,'.');
char *p2= strrchr(sString,'\\');
char *p3= strrchr(sString,'/');
// special check, make sure the first suffix we found from the end wasn't just a directory suffix (eg on a path'd filename with no extension anyway)
//
if (p &&
(p2==0 || (p2 && p>p2)) &&
(p3==0 || (p3 && p>p3))
)
*p=0;
return sString;
}
// loses anything after the path (if any), (eg) "\dir\name.bmp" becomes "\dir"
//
char *Filename_PathOnly(LPCSTR psFilename)
{
static char sString[MAX_PATH];
strcpy(sString,psFilename);
// for (int i=0; i<strlen(sString); i++)
// {
// if (sString[i] == '/')
// sString[i] = '\\';
// }
char *p1= strrchr(sString,'\\');
char *p2= strrchr(sString,'/');
char *p = (p1>p2)?p1:p2;
if (p)
*p=0;
return sString;
}
// returns filename's extension only (including '.'), else returns original string if no '.' in it...
//
char *Filename_ExtOnly(LPCSTR psFilename)
{
static char sString[MAX_PATH];
LPCSTR p = strrchr(psFilename,'.');
if (!p)
p=psFilename;
strcpy(sString,p);
return sString;
}
// used when sending output to a text file etc, keeps columns nice and neat...
//
char *String_EnsureMinLength(LPCSTR psString, int iMinLength)
{
static char sString[8][1024];
static int i=0;
i=(i+1)&7;
strcpy(sString[i],psString);
// a bit slow and lazy, but who cares?...
//
while (strlen(sString[i])<(UINT)iMinLength)
strcat(sString[i]," ");
return sString[i];
}
// similar to strlwr, but (crucially) doesn't touch original...
//
char *String_ToLower(LPCSTR psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
return strlwr(sString);
}
// similar to strupr, but (crucially) doesn't touch original...
//
char *String_ToUpper(LPCSTR psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
return strupr(sString);
}
char *String_ForwardSlash(LPCSTR psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
char *p;
while ( (p=strchr(sString,'\\')) != NULL)
{
*p = '/';
}
return strlwr(sString);
}
char *String_RemoveOccurences(LPCSTR psString, LPCSTR psSubStr)
{
static CString str;
str = psString;
str.Replace(psSubStr,"");
return const_cast < char * > ((LPCSTR) str); // :-)
}
char *va(char *format, ...)
{
va_list argptr;
static char string[16][16384]; // important to have a good depth to this. 16 is nice
static index = 0;
index = (++index)&15;
va_start (argptr, format);
// vsprintf (string[index], format,argptr);
_vsnprintf(string[index], sizeof(string[0]), format, argptr);
va_end (argptr);
string[index][sizeof(string[0])-1] = '\0';
return string[index];
}
// returns a path to somewhere writeable, without trailing backslash...
//
// (for extra speed now, only evaluates it on the first call, change this if you like)
//
char *scGetTempPath(void)
{
static char sBuffer[MAX_PATH];
DWORD dwReturnedSize;
static int i=0;
if (!i++)
{
dwReturnedSize = GetTempPath(sizeof(sBuffer),sBuffer);
if (dwReturnedSize>sizeof(sBuffer))
{
// temp path too long to return, so forget it...
//
strcpy(sBuffer,"c:"); // "c:\\"); // should be writeable
}
// strip any trailing backslash...
//
if (sBuffer[strlen(sBuffer)-1]=='\\')
sBuffer[strlen(sBuffer)-1]='\0';
}// if (!i++)
return sBuffer;
}
// psInitialSaveName can be "" if not bothered
LPCSTR InputSaveFileName(LPCSTR psInitialSaveName, LPCSTR psCaption, LPCSTR psInitialPath, LPCSTR psFilter, LPCSTR psExtension)
{
CFileStatus Filestatus;
CFile File;
static char name[MAX_PATH];
CString strInitialSaveName(psInitialSaveName);
strInitialSaveName.Replace("/","\\"); // or windows immediately cancels the dialog
CFileDialog FileDlg(FALSE, psExtension,
strInitialSaveName,
OFN_OVERWRITEPROMPT|OFN_CREATEPROMPT,
psFilter, //TEXT("Map Project Files (*.mpj)|*.lit|Other Map Files (*.smd/*.sc2)|*.sc2;*.smd|FastMap Files (*.fmf)|*.fmf|All Files(*.*)|*.*||"), //Map Object Files|*.sms||"),
AfxGetMainWnd()
);
// FileDlg.m_ofn.lpstrInitialDir=psInitialPath;
// FileDlg.m_ofn.lpstrTitle=psCaption;
// strcpy(name,psInitialSaveName);
// FileDlg.m_ofn.lpstrFile=name;
if (FileDlg.DoModal() == IDOK)
{
static CString strName;
strName = FileDlg.GetPathName();
return strName;
}
return NULL;
}
// "psInitialLoadName" param can be "" if not bothered, "psInitialDir" can be NULL to open to last browse-dir
//
// psFilter example: TEXT("Model files (*.glm)|*.glm|All Files(*.*)|*.*||") // LPCSTR psFilter
//
// there is too much crap in here, and some needless code, fix it sometime... (yeah, right)
//
LPCSTR InputLoadFileName(LPCSTR psInitialLoadName, LPCSTR psCaption, LPCSTR psInitialDir, LPCSTR psFilter)
{
CFileStatus Filestatus;
CFile File;
static char name[MAX_PATH];
CFileDialog FileDlg(TRUE, NULL, NULL,
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
//TEXT("Map Project Files (*.mpj)|*.lit|Other Map Files (*.smd/*.sc2)|*.sc2;*.smd|FastMap Files (*.fmf)|*.fmf|All Files(*.*)|*.*||"), //Map Object Files|*.sms||"),
psFilter, //Map Object Files|*.sms||"),
AfxGetMainWnd());
static CString strInitialDir;
if (psInitialDir)
strInitialDir = psInitialDir;
strInitialDir.Replace("/","\\");
FileDlg.m_ofn.lpstrInitialDir = (LPCSTR) strInitialDir;
FileDlg.m_ofn.lpstrTitle=psCaption; // Load Editor Model";
CString strInitialLoadName(psInitialLoadName);
strInitialLoadName.Replace("/","\\");
strcpy(name,(LPCSTR)strInitialLoadName);
FileDlg.m_ofn.lpstrFile=name;
if (FileDlg.DoModal() == IDOK)
{
return name;
}
return NULL;
}
// these MUST all be MB_TASKMODAL boxes now!!
//
bool gbErrorBox_Inhibit = false; // Keith wanted to be able to remote-deactivate these...
string strLastError;
LPCSTR ModView_GetLastError() // function for him to be able to interrogate if he's disabled the error boxes
{
return strLastError.c_str();
}
extern bool Gallery_Active();
extern void Gallery_AddError (LPCSTR psText);
extern void Gallery_AddInfo (LPCSTR psText);
extern void Gallery_AddWarning (LPCSTR psText);
void ErrorBox(const char *sString)
{
if (Gallery_Active())
{
Gallery_AddError(sString);
Gallery_AddError("\n");
return;
}
if (!gbErrorBox_Inhibit)
{
MessageBox( NULL, sString, "Error", MB_OK|MB_ICONERROR|MB_TASKMODAL );
}
strLastError = sString;
}
void InfoBox(const char *sString)
{
if (Gallery_Active())
{
Gallery_AddInfo(sString);
Gallery_AddInfo("\n");
return;
}
MessageBox( NULL, sString, "Info", MB_OK|MB_ICONINFORMATION|MB_TASKMODAL );
}
void WarningBox(const char *sString)
{
if (Gallery_Active())
{
Gallery_AddWarning(sString);
Gallery_AddWarning("\n");
return;
}
MessageBox( NULL, sString, "Warning", MB_OK|MB_ICONWARNING|MB_TASKMODAL );
}
bool GetYesNo(const char *psQuery)
{
if (Gallery_Active())
{
Gallery_AddWarning("GetYesNo call (... to which I guessed 'NO' ) using this query...\n\n");
Gallery_AddWarning(psQuery);
Gallery_AddWarning("\n");
return false;
}
//#define GetYesNo(psQuery) (!!(MessageBox(AppVars.hWnd,psQuery,"Query",MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES))
#define _GetYesNo(psQuery) (!!(AfxMessageBox(psQuery, MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES))
return _GetYesNo(psQuery);
}
void StatusMessage(LPCSTR psString) // param can be NULL to indicate fallback to "ready" or whatever you want
{
CMainFrame* pMainFrame = (CMainFrame*) AfxGetMainWnd();
if (pMainFrame)
{
pMainFrame->StatusMessage(psString);
}
}
/* this piece copied out of on-line examples, it basically works as a
similar function to Ffilelength(int handle), but it works with streams */
long filesize(FILE *handle)
{
long curpos, length;
curpos = ftell(handle);
fseek(handle, 0L, SEEK_END);
length = ftell(handle);
fseek(handle, curpos, SEEK_SET);
return length;
}
// returns -1 for error
int LoadFile (LPCSTR psPathedFilename, void **bufferptr, int bReportErrors)
{
FILE *f;
int length;
void *buffer;
f = fopen(psPathedFilename,"rb");
if (f)
{
length = filesize(f);
buffer = malloc (length+1);
((char *)buffer)[length] = 0;
int lread = fread (buffer,1,length, f);
fclose (f);
if (lread==length)
{
*bufferptr = buffer;
return length;
}
free(buffer);
}
extern bool gbInImageLoader; // tacky, but keeps quieter errors
if (bReportErrors && !gbInImageLoader)
{
ErrorBox(va("Error reading file %s!",psPathedFilename));
}
return -1;
}
// returns -1 for error
int SaveFile (LPCSTR psPathedFilename, const void *pBuffer, int iSize)
{
extern void CreatePath (const char *path);
CreatePath(psPathedFilename);
FILE *f = fopen(psPathedFilename,"wb");
if (f)
{
int iLength = fwrite(pBuffer, 1, iSize, f);
fclose (f);
if (iLength == iSize)
{
return iLength;
}
ErrorBox(va("Error writing file \"%s\" (length %d), only %d bytes written!",psPathedFilename,iSize,iLength));
return -1;
}
ErrorBox(va("Error opening file \"%s\" for writing!",psPathedFilename));
return -1;
}
// this'll return a string of up to the first 4095 chars of a system error message...
//
LPCSTR SystemErrorString(DWORD dwError)
{
static char sString[4096];
LPVOID lpMsgBuf=0;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
ZEROMEM(sString);
strncpy(sString,(LPCSTR) lpMsgBuf,sizeof(sString)-1);
LocalFree( lpMsgBuf );
return sString;
}
void SystemErrorBox(DWORD dwError)
{
ErrorBox( SystemErrorString(dwError) );
}
LPCSTR scGetComputerName(void)
{
static char cTempBuffer[128]; // well ott for laziness
DWORD dwTempBufferSize;
static int i=0;
if (!i++)
{
dwTempBufferSize = (sizeof (cTempBuffer))-1;
strcpy(cTempBuffer,"");
if (!GetComputerName(cTempBuffer, &dwTempBufferSize))
strcpy(cTempBuffer,"Unknown"); // error retrieving host computer name
}
return &cTempBuffer[0];
}
LPCSTR scGetUserName(void)
{
static char cTempBuffer[128];
DWORD dwTempBufferSize;
static int i=0;
if (!i++)
{
dwTempBufferSize = (sizeof (cTempBuffer))-1;
strcpy(cTempBuffer,"");
if (!GetUserName(cTempBuffer, &dwTempBufferSize))
strcpy(cTempBuffer,"Unknown"); // error retrieving host computer name
}
return &cTempBuffer[0];
}
bool TextFile_Read(CString &strFile, LPCSTR psFullPathedFilename, bool bLoseSlashSlashREMs /* = true */, bool bLoseBlankLines /* = true */)
{
FILE *fhTextFile = fopen(psFullPathedFilename,"rt");
if (fhTextFile)
{
char sLine[32768]; // sod it, should be enough for one line.
char *psLine;
strFile.Empty();
while ((psLine = fgets( sLine, sizeof(sLine), fhTextFile ))!=NULL)
{
if (bLoseSlashSlashREMs && !strncmp(psLine,"//",2))
{
// do nothing
}
else
{
// lose any whitespace to either side
CString strTemp(psLine);
strTemp.TrimLeft();
strTemp.TrimRight();
strTemp+="\n"; // restore the CR that got trimmed off by TrimRight()
if (bLoseBlankLines && (strTemp.IsEmpty() || strTemp.GetAt(0)=='\n'))
{
// do nothing
}
else
{
strFile += strTemp;
}
}
}
fclose(fhTextFile);
}
return !!fhTextFile;
}
bool SendFileToNotepad(LPCSTR psFilename)
{
bool bReturn = false;
char sExecString[MAX_PATH];
sprintf(sExecString,"notepad %s",psFilename);
if (WinExec(sExecString, // LPCSTR lpCmdLine, // address of command line
SW_SHOWNORMAL // UINT uCmdShow // window style for new application
)
>31 // don't ask me, Windoze just uses >31 as OK in this call.
)
{
// ok...
//
bReturn = true;
}
else
{
ErrorBox("Unable to locate/run NOTEPAD on this machine!\n\n(let me know about this -Ste)");
}
return bReturn;
}
// creates as temp file, then spawns notepad with it...
//
bool SendStringToNotepad(LPCSTR psWhatever, LPCSTR psLocalFileName)
{
bool bReturn = false;
LPCSTR psOutputFileName = va("%s\\%s",scGetTempPath(),psLocalFileName);
FILE *handle = fopen(psOutputFileName,"wt");
if (handle)
{
fprintf(handle,psWhatever);
fclose(handle);
bReturn = SendFileToNotepad(psOutputFileName);
}
else
{
ErrorBox(va("Unable to create file \"%s\" for notepad to use!",psOutputFileName));
}
return bReturn;
}
////////////////////////// eof ///////////////////////////

View File

@@ -0,0 +1,59 @@
// Filename:- generic_stuff.h
//
#ifndef GENERIC_STUFF_H
#define GENERIC_STUFF_H
extern char qdir[];
extern char gamedir[];
void SetQdirFromPath( const char *path );
void Filename_RemoveQUAKEBASE(CString &string);
bool FileExists (LPCSTR psFilename);
long FileLen( LPCSTR psFilename);
char *Filename_WithoutPath(LPCSTR psFilename);
char *Filename_WithoutExt(LPCSTR psFilename);
char *Filename_PathOnly(LPCSTR psFilename);
char *Filename_ExtOnly(LPCSTR psFilename);
char *String_EnsureMinLength(LPCSTR psString, int iMinLength);
char *String_ToLower(LPCSTR psString);
char *String_ToUpper(LPCSTR psString);
char *String_ForwardSlash(LPCSTR psString);
char *String_RemoveOccurences(LPCSTR psString, LPCSTR psSubStr);
char *va(char *format, ...);
char *scGetTempPath(void);
LPCSTR InputSaveFileName(LPCSTR psInitialSaveName, LPCSTR psCaption, LPCSTR psInitialPath, LPCSTR psFilter, LPCSTR psExtension);
LPCSTR InputLoadFileName(LPCSTR psInitialLoadName, LPCSTR psCaption, LPCSTR psInitialDir, LPCSTR psFilter);
LPCSTR scGetComputerName(void);
LPCSTR scGetUserName(void);
extern bool gbErrorBox_Inhibit;
LPCSTR ModView_GetLastError();
void ErrorBox(const char *sString);
void InfoBox(const char *sString);
void WarningBox(const char *sString);
void StatusMessage(LPCSTR psString);
void SystemErrorBox(DWORD dwError = GetLastError());
LPCSTR SystemErrorString(DWORD dwError = GetLastError());
//#define GetYesNo(psQuery) (!!(MessageBox(AppVars.hWnd,psQuery,"Query",MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES))
bool GetYesNo(const char *psQuery);
long filesize(FILE *handle);
int LoadFile (LPCSTR psPathedFilename, void **bufferptr, int bReportErrors = true);
int SaveFile (LPCSTR psPathedFilename, const void *pBuffer, int iSize);
bool TextFile_Read(CString &strFile, LPCSTR psFullPathedFilename, bool bLoseSlashSlashREMs = true, bool bLoseBlankLines = true);
bool SendFileToNotepad(LPCSTR psFilename);
bool SendStringToNotepad(LPCSTR psWhatever, LPCSTR psLocalFileName);
#endif // #ifndef GENERIC_STUFF_H
////////////// eof /////////////

View File

@@ -0,0 +1,831 @@
// Main Parsing Class
//
#if !defined(GENERICPARSER_H_INC)
#include "GenericParser.h"
#endif
#if 0
//
//
// CParseGroup
//
//
/************************************************************************************************
* CParseGroup
* copy constructor. recursively copies all subgroups and pairs.
*
* Input
* an existing parse group
*
* Output
* none
*
************************************************************************************************/
CParseGroup::CParseGroup(CParseGroup *orig)
{
CParseGroup *newGroup = 0;
if (orig == 0)
{
return;
}
mWriteable = orig->mWriteable;
mName = orig->mName;
mParent = orig->mParent;
for (TParsePairIter itp = orig->PairsBegin(); itp != orig->PairsEnd(); itp++)
{
AddPair((*itp).first, (*itp).second);
}
for (TParseGroupIter itg = orig->GroupsBegin(); itg != orig->GroupsEnd(); itg++)
{
newGroup = new CParseGroup((*itg).second);
AddSubGroup(newGroup);
}
}
/************************************************************************************************
* ~CParseGroup
* basic destructor. deallocate any sub groups before going away
*
* inputs:
* none
*
* return:
* nothing
************************************************************************************************/
CParseGroup::~CParseGroup()
{
Clean();
}
/************************************************************************************************
* FindPairValue
* Return the value assigned to the provided key. If said key doesn't exist for this
* ParseGroup, the provided default value is returned.
*
* inputs:
* a key string to be used as an element in CParseGroup::mPairs
* a default value string to be returned in the event that the provided key isn't found
*
* return:
* either the string value stored at CParseGroup::mPairs[key] or, failing that, the provided
* default value
*
************************************************************************************************/
string CParseGroup::FindPairValue(string key, string defaultVal)
{
map<string, string>::iterator it;
it = mPairs.find(key);
if (it != mPairs.end())
{
return (*it).second;
}
return defaultVal;
}
/************************************************************************************************
* FindSubGroup
* search for a subgroup with a particular name
*
* Input
* name of subgroup, boolean indicating whether or not to search recursively
*
* Output
* pointer to the desired subgroup, NULL if not found
*
************************************************************************************************/
CParseGroup *CParseGroup::FindSubGroup(string name, bool recurse/*false*/)
{
TParseGroupIter it = mSubGroups.find(name);
CParseGroup *subGroup = 0, *findGroup = 0;
if (it != mSubGroups.end())
{
return (*it).second;
}
// didn't find it in the top level of groups. if we're supposed to recurse, search
//our top level's subgroups, else return NULL
if (recurse)
{
for (it = mSubGroups.begin(); it != mSubGroups.end(); it++)
{
subGroup = (*it).second;
if (subGroup)
{
findGroup = subGroup->FindSubGroup(name, recurse);
if (findGroup)
{
return findGroup;
}
}
}
}
return NULL;
}
/************************************************************************************************
* FindSubGroupWithPair
* finds a subgroup that contains the provided key/value pair
*
* inputs:
* strings key and value for locating the subgroup
*
* return:
* pointer to the ParseGroup representing the subgroup we're after or NULL if we didn't find it
************************************************************************************************/
CParseGroup *CParseGroup::FindSubGroupWithPair(string key, string value)
{
TParseGroupIter it;
TParsePairIter itp;
for (it = mSubGroups.begin(); it != mSubGroups.end(); it++)
{
itp = ((CParseGroup*)(*it).second)->mPairs.find(key);
if (itp != ((CParseGroup*)(*it).second)->mPairs.end())
{
if (value.compare((*itp).second) == 0)
{
// found a subgroup with a key/value pair matching the one we're looking for
return ((CParseGroup*)(*it).second);
}
}
}
// none of our subgroups contains the key/value pair
return NULL;
}
/************************************************************************************************
* DeleteSubGroup
* find the given subgroup in our multimap of subgroups and remove it. also, try to find
* it in our vector of ordered subgroups and remove it from there.
*
* Input
* parse group to be deleted
*
* Output
* true if it was found and deleted, false otherwise
*
************************************************************************************************/
bool CParseGroup::DeleteSubGroup(CParseGroup *delGroup)
{
TParseGroupIter itg;
if (delGroup == 0)
{
return false;
}
itg = mSubGroups.find(delGroup->GetName());
if (itg != mSubGroups.end())
{
// this is a multimap, so make sure our pointers match
while ( ((*itg).second != delGroup) && (itg != mSubGroups.end()) )
{
itg++;
}
if ((*itg).second == delGroup)
{
// try to find it in mInOrderSubGroups
if (mInOrderSubGroups.size())
{
vector<pair<string, CParseGroup*> >::iterator itv = mInOrderSubGroups.begin();
for (int i = 0; i < mInOrderSubGroups.size(); i++, itv++)
{
if (mInOrderSubGroups[i].second == delGroup)
{
mInOrderSubGroups.erase(itv);
break;
}
}
}
delete delGroup;
delGroup = 0;
mSubGroups.erase(itg);
return true;
}
}
return false;
}
/************************************************************************************************
* Clean
* cleans up our sub group list
*
* inputs:
* none
*
* return:
* nothing
************************************************************************************************/
void CParseGroup::Clean()
{
TParseGroupIter it;
for (it = mSubGroups.begin(); it != mSubGroups.end(); it++)
{
delete (CParseGroup*)(*it).second;
}
mSubGroups.clear();
mInOrderPairs.clear();
mInOrderSubGroups.clear();
}
/************************************************************************************************
* WriteLine
* writes a line of data to the provided output string
*
* inputs:
* a brace depth, allowing pretty formatted text, a line of text to be written, and an output string
*
* return:
* true if data is written successfully, false otherwise
************************************************************************************************/
bool CParseGroup::WriteLine(int depth, const string line, string &output)
{
for (int i = 0; i < depth; i++)
{
output += "\t";
}
output += line;
output += "\n";
return true;
}
/************************************************************************************************
* WriteGroup
* write this group's pairs and then its subgroups
*
* inputs:
* name of the object, indentation depth, the destination string
*
* return:
* true if data is written successfully, false otherwise
************************************************************************************************/
bool CParseGroup::WriteGroup(string name, int depth, string &output)
{
string curLine;
CParseGroup *subGroup = 0;
vector< pair<string, string> > &inOrderPairs = GetInOrderPairs();
vector< pair<string, CParseGroup*> > &inOrderGroups = GetInOrderGroups();
// first, write out the name (e.g. "hook") of the object
WriteLine(depth, name, output);
// now write out an open brace to begin the innards of our object
WriteLine(depth, "{", output);
// write out the key/value pairs
for (int p = 0; p < inOrderPairs.size(); p++)
{
curLine = "\"";
curLine += inOrderPairs[p].first;
curLine += "\"\t\"";
curLine += inOrderPairs[p].second;
curLine += "\"";
WriteLine(depth+1, curLine, output);
}
// recursively write out the subgroups
for (int g = 0; g < inOrderGroups.size(); g++)
{
WriteLine(depth+1, "", output);
subGroup = inOrderGroups[g].second;
if (subGroup)
{
subGroup->WriteGroup(inOrderGroups[g].first, depth+1, output);
}
}
// now write out a close brace
WriteLine(depth, "}", output);
return true;
}
//
//
// CGenericParser
//
//
/************************************************************************************************
* CGenericParser
* constructor. inits the max token length.
*
* input:
* none
*
* return:
* nothing
************************************************************************************************/
CGenericParser::CGenericParser():
mMaxTokenLength(1024)
{
mLineCount = 0;
mBraceDepth = 0;
mCurGroup = NULL;
}
/************************************************************************************************
* ~CGenericParser
* deallocates any CParseGroups we created, general clean up
*
* inputs:
* none
*
* return:
* nothing
************************************************************************************************/
CGenericParser::~CGenericParser()
{
mGroups.Clean();
}
/************************************************************************************************
* SkipWhiteSpace
* loops through the char's in data and points data to the next non-whitespace character. sets
* newLine variable to true if one of the whitespace char's is a new line.
*
* input:
* pointer to text data, pointer to a boolean which states whether or not a newline is encountered
*
* return:
* the altered data pointer if it's pointing to a valid char. returns NULL if we reached the
* end of the data.
************************************************************************************************/
char *CGenericParser::SkipWhiteSpace( char *data, bool *newLine )
{
char ch;
while(isspace(ch = *data))
{
if( '\n' == ch )
{
*newLine = true;
mLineCount++;
}
data++;
}
if (0 == ch)
{
// reached the end of our data
return NULL;
}
return data;
}
/************************************************************************************************
* EatCurrentLine
* increments the data pointer until it hits a new line or we run out of char data
*
* input:
* pointer to text data
*
* return:
* nothing
************************************************************************************************/
void CGenericParser::EatCurrentLine( char **data )
{
while (**data && **data != '\n')
{
if ('{' == **data)
{
mBraceDepth++;
}
else if ('}' == **data)
{
if (0 == mBraceDepth)
{
// too many closing braces
}
else
{
mBraceDepth--;
}
}
(*data)++;
}
}
/************************************************************************************************
* GetToken
* parses a text string to procure the next viable (non-whitespace, non-comment) token.
* said token will be stored in CGenericParser::mToken
*
* input:
* pointer to character data to be parsed, boolean stating whether or not new lines are
* acceptable characters for the upcoming token
*
* return:
* reference to the string containing the text value of the new token
*
************************************************************************************************/
string &CGenericParser::GetToken( char **dataPtr, const bool allowNewLines )
{
char ch = 0;
int len = 0;
bool newLine = false;
char *data = *dataPtr;
// reset our current token
mToken = "";
// return an empty string if text data is NULL
if ( !data )
{
*dataPtr = NULL;
return mToken;
}
// loop through the text data, skip whitespace, skip comments, get to the
//beginning of the next token
while ( data = SkipWhiteSpace( data, &newLine ) )
{
if ( newLine && !allowNewLines )
{
*dataPtr = data;
return mToken;
}
ch = *data;
// skip // comments
if ( ('/' == ch) && ('/' == data[1]) )
{
EatCurrentLine(&data);
}
// skip /* */ comments
else if ( ('/' == ch) && ('*' == data[1]) )
{
while ( *data && ((*data != '*') || (data[1] != '/')) )
{
data++;
}
if ( *data )
{
data += 2;
}
}
else
{
break;
}
}
// if SkipWhiteSpace returned NULL, we got to the end of our data without finding
//another valid token
if ( !data )
{
*dataPtr = NULL;
return mToken;
}
//
// at this point we're pointing at the next valid char in our data stream
//
// handle quoted strings
if ('\"' == ch)
{
data++;
while (1)
{
ch = *data++;
if (('\"' == ch) || !ch)
{
*dataPtr = (char*)data;
return mToken;
}
if (len < mMaxTokenLength)
{
mToken.append(1,ch);
len++;
}
}
}
// ok, these next characters are a token
do
{
if ('{' == *data)
{
mBraceDepth++;
}
else if ('}' == *data)
{
if (0 == mBraceDepth)
{
// too many closing braces
}
else
{
mBraceDepth--;
}
}
if (len < mMaxTokenLength)
{
mToken.append(1,ch);
len++;
}
data++;
ch = *data;
if ( '\n' == ch )
{
mLineCount++;
}
} while (!isspace(ch));
if (len == mMaxTokenLength)
{
// token is too long...excess characters discarded
len = 0;
}
*dataPtr = ( char * ) data;
return mToken;
}
/************************************************************************************************
* ReturnToBraceDepthZero
* this function is called when a parse error is encountered. its goal is to eat any and all
* text until it returns to brace depth zero, where the parser can hopefully start over
*
* inputs:
* pointer to character data to be parsed
*
* return:
* nothing
************************************************************************************************/
void CGenericParser::ReturnToBraceDepthZero(char **dataPtr)
{
// we already parsed a mismatched '}' so discount it in terms of subtracting from brace depth
mBraceDepth++;
// commence the eating of tokens
while (1)
{
GetToken(dataPtr);
if ( (0 == mBraceDepth) || (mToken.empty()) )
{
return;
}
}
}
/************************************************************************************************
* ParseGroup
* recursively parses a text string using a nested-block format. basically parses a pair of
* tokens at once, if possible.
*
* inputs:
* pointer to character data to be parsed
*
* return:
* true if a group is parsed, false if end-of-file
************************************************************************************************/
bool CGenericParser::ParseGroup(char **dataPtr)
{
string tok1;
string tok2;
while (1)
{
tok1 = GetToken(dataPtr);
if (tok1.empty())
{
// reached end of data
return false;
}
if ('}' == tok1[0])
{
// ending a ParseGroup
mCurGroup = mCurGroup->GetParent();
return true;
}
tok2 = GetToken(dataPtr);
if (tok2.empty())
{
// empty group or a key-value pair with no value, just a key
}
else if ('{' == tok2[0])
{
// we're starting a new CParseGroup and its name is currently in tok1
CParseGroup *newGroup = new CParseGroup(tok1, mCurGroup, mWriteable);
if (NULL == mCurGroup)
{
// this is a top level group so add it to the parser's list
mGroups.AddSubGroup(newGroup);
mCurGroup = newGroup;
}
else
{
// this is somebody's subgroup
mCurGroup->AddSubGroup(newGroup);
// time for some ol' fashioned, down-home recursion. yeehaw!
mCurGroup = newGroup;
ParseGroup(dataPtr);
}
}
else if ('}' == tok2[0])
{
// error. try to recover.
ReturnToBraceDepthZero(dataPtr);
}
else
{
if (mCurGroup == 0)
{
// assume we're adding a key/value pair at the file level
mGroups.AddPair(tok1, tok2);
}
else
{
// we're considering tok1 as a key and tok2 as a value
mCurGroup->AddPair(tok1, tok2);
}
}
}
}
/************************************************************************************************
* Parse
* parses text data for CParseGroup's until end-of-file is reached
*
* inputs:
* pointer to character data to be parsed, boolean indicating if we should wipe our
* stored data before parsing more, boolean indicating if we should make this data
* writeable
*
* return:
* nothing
************************************************************************************************/
bool CGenericParser::Parse(char **dataPtr, bool cleanFirst/*true*/, bool writeable /*false*/)
{
// a quick test to find hand-edit errors that always seem to manifest as perplexing bugs before we find them...
{
string strBraceTest(*dataPtr);
int iOpeningBraces = 0;
int iClosingBraces = 0;
char *p;
while ((p=strchr(strBraceTest.c_str(),'{'))!=NULL)
{
*p = '#'; // anything that's not a '{'
iOpeningBraces++;
}
while ((p=strchr(strBraceTest.c_str(),'}'))!=NULL)
{
*p = '#'; // anything that's not a '}'
iClosingBraces++;
}
if (iOpeningBraces != iClosingBraces)
{
// maybe print something here, but in any case...
//
return false;
}
}
if (cleanFirst)
{
// if this is a new stream of data, init some stuff
mGroups.Clean();
}
mWriteable = writeable;
mGroups.SetWriteable(mWriteable);
while (ParseGroup(dataPtr))
{
;
}
return true;
}
/************************************************************************************************
* Write
* take all of the stuff we have stored as ParseGroups and write it in an aesthetically
* pleasing form to an output string
*
* Input
* output string
*
* Output
* true if every parsegroup wrote without incident, false otherwise
*
************************************************************************************************/
bool CGenericParser::Write(string &output)
{
string curLine;
CParseGroup *subGroup = 0;
vector< pair<string, string> > &inOrderPairs = mGroups.GetInOrderPairs();
vector< pair<string, CParseGroup*> > &inOrderGroups = mGroups.GetInOrderGroups();
if (!mWriteable)
{
return false;
}
// write out the key/value pairs
for (int p = 0; p < inOrderPairs.size(); p++)
{
curLine = "\"";
curLine += inOrderPairs[p].first;
curLine += "\"\t\"";
curLine += inOrderPairs[p].second;
curLine += "\"";
mGroups.WriteLine(0, curLine, output);
}
// recursively write out the subgroups
for (int g = 0; g < inOrderGroups.size(); g++)
{
mGroups.WriteLine(0, "", output);
subGroup = inOrderGroups[g].second;
if (subGroup)
{
subGroup->WriteGroup(inOrderGroups[g].first, 0, output);
}
}
return true;
}
/************************************************************************************************
* AddParseGroup
* if you want to be able to write out a parsegroup hierarchy, you may want to create
* some of it yourself rather than just rely on what you've read in. that's what this
* fn is for. this is returning a pointer to an object allocate on the heap, so make sure
* it gets deallocated (if you add it into the existing hierarchy of a CGenericParser that
* will take care of it for you)
*
* Input
* name of the new parse group, parent of your new parse group (can't be NULL), whether
* or not your new parse group will be writeable (defaults to true)
*
* Output
* pointer to new parse group
*
************************************************************************************************/
CParseGroup *CGenericParser::AddParseGroup(string groupName, CParseGroup &groupParent, bool writeable /*true*/)
{
CParseGroup *newGroup = new CParseGroup(groupName, &groupParent, writeable);
groupParent.AddSubGroup(newGroup);
return newGroup;
}
/************************************************************************************************
* DeleteParseGroup
* recursively deletes a parse group
*
* Input
* parent of group to be deleted, pointer to parse group to be deleted
*
* Output
* true if it was found and deleted
*
************************************************************************************************/
bool CGenericParser::DeleteParseGroup(CParseGroup *parentGroup, CParseGroup *delGroup)
{
return parentGroup->DeleteSubGroup(delGroup);
}
/************************************************************************************************
* <function>
*
* inputs:
*
* return:
*
************************************************************************************************/
#endif

View File

@@ -0,0 +1,208 @@
#pragma once
#if 0
#if !defined(GENERICPARSER_H_INC)
#define GENERICPARSER_H_INC
#ifdef DEBUG_LINKING
#pragma message("...including GenericParser.h")
#endif
#include "disablewarnings.h"
//
// CConfusedParser is a class designed to contain all of the functionality necessary for
//reading the text files containing CConfusedEntity information generated by ConfusED.
//
#pragma warning( push, 3 )
#if !defined(MAP_INC)
#define MAP_INC
#include <map>
#endif
#if !defined(STRING_INC)
#define STRING_INC
#include <string>
#endif
#if !defined(LIST_INC)
#define LIST_INC
#include <list>
#endif
#if !defined(VECTOR_INC)
#define VECTOR_INC
#include <vector>
#endif
#pragma warning( pop ) // stl sets warnings back on, so get mine back
using namespace std;
#include "disablewarnings.h"
class CParseGroup;
class CParseGroup
{
public:
typedef multimap<string, CParseGroup*>::iterator TParseGroupIter;
typedef map<string, string>::iterator TParsePairIter;
private:
string mName;
map<string, string> mPairs;
multimap<string, CParseGroup*> mSubGroups;
CParseGroup* mParent;
vector<pair<string, string> > mInOrderPairs;
vector<pair<string, CParseGroup*> > mInOrderSubGroups;
bool mWriteable;
public:
CParseGroup(bool writeable = false):
mParent(NULL),
mWriteable(writeable)
{}
CParseGroup(const string name, CParseGroup *parent, bool writeable = false):
mName(name),
mParent(parent),
mWriteable(writeable)
{}
CParseGroup(CParseGroup *orig);
~CParseGroup();
CParseGroup *GetParent()
{
return mParent;
}
string GetName()
{
return mName;
}
int GetNumPairs() { return mPairs.size(); }
int GetNumSubGroups() { return mSubGroups.size(); }
void AddSubGroup(CParseGroup *grp)
{
if (grp)
{
mSubGroups.insert(pair<string, CParseGroup*>(grp->GetName(),grp));
if (mWriteable)
{
mInOrderSubGroups.push_back(pair<string, CParseGroup*>(grp->GetName(),grp));
}
}
}
void AddPair(string key, string value)
{
mPairs[key] = value;
if (mWriteable)
{
mInOrderPairs.push_back(pair<string, string>(key, value));
}
}
void AddPair(const char *key, const char *value)
{
mPairs[key] = value;
if (mWriteable)
{
mInOrderPairs.push_back(pair<string, string>(key, value));
}
}
void SetPair(string key, string value)
{
mPairs[key] = value;
if (mWriteable)
{
// try to find this pair in mInOrderPairs
for (int i = 0; i < mInOrderPairs.size(); i++)
{
if (key.compare(mInOrderPairs[i].first) == 0)
{
mInOrderPairs[i].second = value;
return;
}
}
// doesn't exist yet so add a new pair
mInOrderPairs.push_back(pair<string, string>(key, value));
}
}
void DeletePair(string key)
{
if (mWriteable)
{
map<string, string>::iterator it = mPairs.find(key);
if (it != mPairs.end())
{
mPairs.erase(it);
}
// try to find this pair in mInOrderPairs
for (vector<pair<string, string> >::iterator itInOrder = mInOrderPairs.begin(); itInOrder != mInOrderPairs.end(); ++itInOrder)
{
if (key.compare( (*itInOrder).first) == 0)
{
mInOrderPairs.erase(itInOrder);
break;
}
}
}
}
string FindPairValue(string key, string defaultVal);
CParseGroup *FindSubGroup(string name, bool recurse = false);
CParseGroup *FindSubGroupWithPair(string key, string value);
bool DeleteSubGroup(CParseGroup *delGroup);
bool WriteLine(int depth, const string line, string &output);
bool WriteGroup(string name, int depth, string &output);
void Clean();
TParseGroupIter GroupsBegin() { return mSubGroups.begin(); }
TParseGroupIter GroupsEnd() { return mSubGroups.end(); }
TParsePairIter PairsBegin() { return mPairs.begin(); }
TParsePairIter PairsEnd() { return mPairs.end(); }
// use these for writing (maintain the order in which the data was read)
vector< pair<string, string> > &GetInOrderPairs() { return mInOrderPairs; }
vector< pair<string, CParseGroup*> > &GetInOrderGroups() { return mInOrderSubGroups; }
void SetWriteable(bool writeable) { mWriteable = writeable; }
};
class CGenericParser
{
private:
string mToken;
int mLineCount;
const int mMaxTokenLength;
int mBraceDepth;
CParseGroup *mCurGroup;
CParseGroup mGroups;
bool mWriteable;
protected:
// really low level utility functions
char *SkipWhiteSpace( char *data, bool *newLine );
string &GetToken( char **dataPtr, const bool allowNewLines = true);
void EatCurrentLine( char **data );
void ReturnToBraceDepthZero(char **dataPtr);
// higher level utility
bool ParseGroup(char **dataPtr);
public:
CGenericParser();
~CGenericParser();
bool Parse(char **dataPtr, bool cleanFirst = true, bool writeable = false);
bool Write(string &output);
void SetWriteable(bool writeable) { mWriteable = writeable; GetBaseParseGroup()->SetWriteable(writeable);}
void Clean() { mGroups.Clean(); }
CParseGroup *GetBaseParseGroup()
{
return &mGroups;
}
CParseGroup *AddParseGroup(string groupName, CParseGroup &groupParent, bool writeable = true);
bool DeleteParseGroup(CParseGroup *parentGroup, CParseGroup *delGroup);
};
#endif // GENERICPARSER_H_INC
#endif

View File

@@ -0,0 +1,66 @@
// GetString.cpp : implementation file
//
#include "stdafx.h"
#include "modview.h"
#include "GetString.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CGetString dialog
CGetString::CGetString(LPCSTR psPrompt, CString *pFeedback, LPCSTR psDefault /* = NULL */, CWnd* pParent /*=NULL*/)
: CDialog(CGetString::IDD, pParent)
{
//{{AFX_DATA_INIT(CGetString)
m_strEditBox = _T("");
//}}AFX_DATA_INIT
m_pFeedback = pFeedback;
m_pPrompt = psPrompt;
m_pDefault = psDefault;
}
void CGetString::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CGetString)
DDX_Text(pDX, IDC_EDIT1, m_strEditBox);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CGetString, CDialog)
//{{AFX_MSG_MAP(CGetString)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CGetString message handlers
BOOL CGetString::OnInitDialog()
{
CDialog::OnInitDialog();
GetDlgItem(IDC_GETSTRING_PROMPT)->SetWindowText(m_pPrompt);
GetDlgItem(IDC_EDIT1)->SetWindowText(m_pDefault?m_pDefault:"");
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CGetString::OnOK()
{
UpdateData(DIALOG_TO_DATA);
*m_pFeedback = m_strEditBox;
CDialog::OnOK();
}

51
tools/ModView/getstring.h Normal file
View File

@@ -0,0 +1,51 @@
#if !defined(AFX_GETSTRING_H__E76C376A_6584_419C_A9E7_A49BF2A18494__INCLUDED_)
#define AFX_GETSTRING_H__E76C376A_6584_419C_A9E7_A49BF2A18494__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// GetString.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CGetString dialog
class CGetString : public CDialog
{
// Construction
public:
CGetString(LPCSTR pPrompt, CString *pFeedback, LPCSTR psDefault = NULL, CWnd* pParent = NULL);
// Dialog Data
//{{AFX_DATA(CGetString)
enum { IDD = IDD_DIALOG_GETSTRING };
CString m_strEditBox;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CGetString)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
CString *m_pFeedback;
LPCSTR m_pPrompt;
LPCSTR m_pDefault;
// Generated message map functions
//{{AFX_MSG(CGetString)
virtual BOOL OnInitDialog();
virtual void OnOK();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_GETSTRING_H__E76C376A_6584_419C_A9E7_A49BF2A18494__INCLUDED_)

521
tools/ModView/gl_bits.cpp Normal file
View File

@@ -0,0 +1,521 @@
// Filename:- gl_bits.cpp
//
#include "stdafx.h"
#include "includes.h"
//
#include "gl_bits.h"
int g_iAssertCounter = 0; // just used for debug-outs
// Global handle to main client window GL rendering context, used for other DC/RC pairs to share lists with.
//
HGLRC g_hRC = NULL;
HDC g_hDC = NULL;
CString csGLVendor;
CString csGLRenderer;
CString csGLVersion;
CString csGLExtensions;
LPCSTR GL_GetInfo(void)
{
static CString string;
string = va("\nGL_VENDOR: %s\n", csGLVendor);
string+= va("GL_RENDERER: %s\n", csGLRenderer);
string+= va("GL_VERSION: %s\n", csGLVersion);
string+= va("GL_EXTENSIONS: %s\n", csGLExtensions);
/* CString strExtensionList(csGLExtensions);
strExtensionList.Replace(" ","\t");
string+= va("GL_EXTENSIONS:\n%s\n", strExtensionList);//csGLExtensions);
*/
return string;
}
// ChoosePFD
//
// Helper function that replaces ChoosePixelFormat.
//
static int GLW_ChoosePFD( HDC hDC, PIXELFORMATDESCRIPTOR *pPFD )
{
#define MAX_PFDS 256
PIXELFORMATDESCRIPTOR pfds[MAX_PFDS+1];
int maxPFD = 0;
int i;
int bestMatch = 0;
OutputDebugString( va("...GLW_ChoosePFD( %d, %d, %d )\n", ( int ) pPFD->cColorBits, ( int ) pPFD->cDepthBits, ( int ) pPFD->cStencilBits) );
// count number of PFDs
//
maxPFD = DescribePixelFormat( hDC, 1, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[0] );
if ( maxPFD > MAX_PFDS )
{
OutputDebugString( va( "...numPFDs > MAX_PFDS (%d > %d)\n", maxPFD, MAX_PFDS) );
maxPFD = MAX_PFDS;
}
OutputDebugString( va("...%d PFDs found\n", maxPFD - 1) );
FILE *handle = fopen("c:\\ModView_GL_report.txt","wt");
fprintf(handle,"Total PFDs: %d\n\n",maxPFD);
// grab information
for ( i = 1; i <= maxPFD; i++ )
{
DescribePixelFormat( hDC, i, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[i] );
fprintf(handle,"PFD %d/%d\n",i,maxPFD);
fprintf(handle,"=========\n");
#define FLAGDUMP(flag) if ( (pfds[i].dwFlags & flag ) != 0 ) fprintf(handle,"(flag: %s)\n",#flag);
FLAGDUMP( PFD_DOUBLEBUFFER );
FLAGDUMP( PFD_STEREO );
FLAGDUMP( PFD_DRAW_TO_WINDOW );
FLAGDUMP( PFD_DRAW_TO_BITMAP );
FLAGDUMP( PFD_SUPPORT_GDI );
FLAGDUMP( PFD_SUPPORT_OPENGL );
FLAGDUMP( PFD_GENERIC_FORMAT );
FLAGDUMP( PFD_NEED_PALETTE );
FLAGDUMP( PFD_NEED_SYSTEM_PALETTE );
FLAGDUMP( PFD_SWAP_EXCHANGE );
FLAGDUMP( PFD_SWAP_COPY );
FLAGDUMP( PFD_SWAP_LAYER_BUFFERS );
FLAGDUMP( PFD_GENERIC_ACCELERATED );
FLAGDUMP( PFD_SUPPORT_DIRECTDRAW );
if ( pfds[i].iPixelType == PFD_TYPE_RGBA )
{
// fprintf(handle,"RGBA mode\n");
}
else
{
fprintf(handle,"NOT RGBA mode!!!!!!!!!!!!\n");
}
fprintf(handle, "Colour bits: %d\n",pfds[i].cColorBits);
fprintf(handle, "Depth bits: %d\n",pfds[i].cDepthBits);
fprintf(handle,"\n");
}
// look for a best match
for ( i = 1; i <= maxPFD; i++ )
{
fprintf(handle,"(bestMatch: %d)\n",bestMatch );
//
// make sure this has hardware acceleration
//
if ( ( pfds[i].dwFlags & PFD_GENERIC_FORMAT ) != 0 )
{
// if ( !r_allowSoftwareGL->integer )
{
// if ( r_verbose->integer )
{
fprintf(handle,//OutputDebugString(
va ("...PFD %d rejected, software acceleration\n", i ));
}
continue;
}
}
// verify pixel type
if ( pfds[i].iPixelType != PFD_TYPE_RGBA )
{
// if ( r_verbose->integer )
{
fprintf(handle,//OutputDebugString(
va("...PFD %d rejected, not RGBA\n", i) );
}
continue;
}
// verify proper flags
if ( ( ( pfds[i].dwFlags & pPFD->dwFlags ) & pPFD->dwFlags ) != pPFD->dwFlags )
{
// if ( r_verbose->integer )
{
fprintf(handle,//OutputDebugString(
va("...PFD %d rejected, improper flags (0x%x instead of 0x%x)\n", i, pfds[i].dwFlags, pPFD->dwFlags) );
}
continue;
}
// verify enough bits
if ( pfds[i].cDepthBits < 15 )
{
fprintf(handle,va("...PFD %d rejected, depth bits only %d (<15)\n", i, pfds[i].cDepthBits) );
continue;
}
/* if ( ( pfds[i].cStencilBits < 4 ) && ( pPFD->cStencilBits > 0 ) )
{
continue;
}
*/
//
// selection criteria (in order of priority):
//
// PFD_STEREO
// colorBits
// depthBits
// stencilBits
//
if ( bestMatch )
{
/*
// check stereo
if ( ( pfds[i].dwFlags & PFD_STEREO ) && ( !( pfds[bestMatch].dwFlags & PFD_STEREO ) ) && ( pPFD->dwFlags & PFD_STEREO ) )
{
bestMatch = i;
continue;
}
if ( !( pfds[i].dwFlags & PFD_STEREO ) && ( pfds[bestMatch].dwFlags & PFD_STEREO ) && ( pPFD->dwFlags & PFD_STEREO ) )
{
bestMatch = i;
continue;
}
*/
// check color
if ( pfds[bestMatch].cColorBits != pPFD->cColorBits )
{
// prefer perfect match
if ( pfds[i].cColorBits == pPFD->cColorBits )
{
bestMatch = i;
continue;
}
// otherwise if this PFD has more bits than our best, use it
else if ( pfds[i].cColorBits > pfds[bestMatch].cColorBits )
{
bestMatch = i;
continue;
}
}
// check depth
if ( pfds[bestMatch].cDepthBits != pPFD->cDepthBits )
{
// prefer perfect match
if ( pfds[i].cDepthBits == pPFD->cDepthBits )
{
bestMatch = i;
continue;
}
// otherwise if this PFD has more bits than our best, use it
else if ( pfds[i].cDepthBits > pfds[bestMatch].cDepthBits )
{
bestMatch = i;
continue;
}
}
/*
// check stencil
if ( pfds[bestMatch].cStencilBits != pPFD->cStencilBits )
{
// prefer perfect match
if ( pfds[i].cStencilBits == pPFD->cStencilBits )
{
bestMatch = i;
continue;
}
// otherwise if this PFD has more bits than our best, use it
else if ( ( pfds[i].cStencilBits > pfds[bestMatch].cStencilBits ) &&
( pPFD->cStencilBits > 0 ) )
{
bestMatch = i;
continue;
}
}
*/
}
else
{
bestMatch = i;
}
}
fprintf(handle,"Bestmode: %d\n",bestMatch);
if ( !bestMatch )
{
fprintf(handle,"No decent mode found!\n");
fclose(handle);
return 0;
}
if ( ( pfds[bestMatch].dwFlags & PFD_GENERIC_FORMAT ) != 0 )
{
// if ( !r_allowSoftwareGL->integer )
// {
// ri.Printf( PRINT_ALL, "...no hardware acceleration found\n" );
// return 0;
// }
// else
{
fprintf(handle,//OutputDebugString(
"...using software emulation\n" );
}
}
else if ( pfds[bestMatch].dwFlags & PFD_GENERIC_ACCELERATED )
{
fprintf(handle,//OutputDebugString(
"...MCD acceleration found\n" );
}
else
{
fprintf(handle,//OutputDebugString(
"...hardware acceleration found\n" );
}
*pPFD = pfds[bestMatch];
fclose(handle);
return bestMatch;
}
HGLRC GL_GenerateRC(HDC hDC, bool bDoubleBuffer/* = true*/)
{
HGLRC hRC = NULL;
if (1/*RunningNT() || bCalledFromMainCellView*/)
{
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this struct
1, // struct version
PFD_DRAW_TO_WINDOW | // draw to window (not bitmap)
// PFD_DOUBLEBUFFER | // double buffered mode
PFD_SUPPORT_OPENGL, // support opengl in window
PFD_TYPE_RGBA, // RGBA colour mode
24, // want 24bit colour
0,0,0,0,0,0, // not used to select mode
0,0, // not used to select mode
0,0,0,0,0, // not used to select mode
32, // size of depth buffer
0, // not used to select mode
0, // not used to select mode
PFD_MAIN_PLANE, // draw in main plane
0, // not used to select mode
0,0,0 // not used to select mode
};
if (bDoubleBuffer)
{
pfd.dwFlags |= PFD_DOUBLEBUFFER;
}
// choose a pixel format that best matches the one we want...
//
int iPixelFormat = GLW_ChoosePFD(hDC,&pfd); // try and choose best hardware mode
if (iPixelFormat == 0)
{
// nothing decent found, fall bac to whatever crap the system recommends...
//
iPixelFormat = ChoosePixelFormat(hDC,&pfd);
}
//
// set the pixel format for this device context...
//
VERIFY(SetPixelFormat(hDC, iPixelFormat, &pfd));
//
// create the rendering context...
//
hRC = wglCreateContext(hDC);
if (hRC)
{
//
// make the rendering context current, init, then deselect...
//
VERIFY(wglMakeCurrent(hDC,hRC));
// first one in creates the global RC, everyone else shares lists with it...
//
if (g_hRC)
{
ASSERT_GL;
VERIFY(wglShareLists(g_hRC,hRC));
ASSERT_GL;
}
else
{
g_hRC = hRC;
g_hDC = hDC;
// record vendor strings for later display...
//
csGLVendor = glGetString (GL_VENDOR);
csGLRenderer = glGetString (GL_RENDERER);
csGLVersion = glGetString (GL_VERSION);
csGLExtensions = glGetString (GL_EXTENSIONS);
//
// for the moment I'll insist on 24 bits and up (texture loading reasons, plus GL issues)
//
{
HDC _hDC = GetDC( GetDesktopWindow() );
int iDesktopBitDepth = GetDeviceCaps( _hDC, BITSPIXEL );
if (iDesktopBitDepth == 8)
{
WarningBox(va("Your desktop is only %d bit!,\n\nChange the bitdepth to 16 or more (65536 colours or over) and re-run.",iDesktopBitDepth));
}
ReleaseDC( GetDesktopWindow(), _hDC );
}
}
// VERIFY(wglMakeCurrent(NULL,NULL)); // leave context running!
}
}
return hRC;
}
//////////// ?????
#define NEAR_GL_PLANE 0.1
#define FAR_GL_PLANE 512
void GL_Enter3D( double dFOV, int iWindowWidth, int iWindowDepth, bool bWireFrame, bool bCLS/* = true */)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (iWindowDepth > 0)
gluPerspective( dFOV, (double)iWindowWidth/(double)iWindowDepth, NEAR_GL_PLANE, FAR_GL_PLANE );
glViewport( 0, 0, iWindowWidth, iWindowDepth );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_DEPTH_TEST);
if (bCLS)
{
// glClearColor (0,0,0,0);
glClearColor((float)1/((float)256/(float)AppVars._R), (float)1/((float)256/(float)AppVars._G), (float)1/((float)256/(float)AppVars._B), 0.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
if (AppVars.bShowPolysAsDoubleSided && !AppVars.bForceWhite)
{
glDisable(GL_CULL_FACE);
}
else
{
glEnable(GL_CULL_FACE);
}
if (bWireFrame)
{
// glDisable(GL_CULL_FACE);
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_LIGHTING);
}
else
{
// glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// hitech: not this
if (AppVars.bBilinear)
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); // ?
}
else
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
}
}
glColor3f (1,1,1);
}
void GL_Enter2D(int iWindowWidth, int iWindowDepth, bool bCLS/* = true */)
{
glViewport (0,0, iWindowWidth, iWindowDepth);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho (0, iWindowWidth, iWindowDepth, 0, -99999, 99999);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glDisable (GL_DEPTH_TEST);
glDisable (GL_CULL_FACE);
glDisable (GL_BLEND);
if (bCLS)
{
// glClearColor (0,1,0,0);
glClearColor((float)1/((float)256/(float)AppVars._R), (float)1/((float)256/(float)AppVars._G), (float)1/((float)256/(float)AppVars._B), 0.0f);
glClear (GL_COLOR_BUFFER_BIT);
}
glEnable (GL_TEXTURE_2D);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor3f (1,1,1);
}
void GL_Exit2D(void)
{
glDisable (GL_TEXTURE_2D);
glColor3f (1,1,1);
}
#ifdef _DEBUG
void AssertGL(const char *sFile, int iLine)
{
GLenum glError;
if ((glError = glGetError())!=GL_NO_ERROR)
{
int iReportCount=0; /* stop crashes via only 32 errors max */
OutputDebugString(va("*** GL_ERROR! *** (File:%s Line:%d\n",sFile, iLine));
do
{
OutputDebugString(va("(%d) %s\n",g_iAssertCounter,(char *)gluErrorString(glError)));
g_iAssertCounter++;
}
while (iReportCount++<32 && (glError = glGetError())!=GL_NO_ERROR);
// ASSERT(0);
}
}
#endif
////////////////////// eof ///////////////////////

39
tools/ModView/gl_bits.h Normal file
View File

@@ -0,0 +1,39 @@
// Filename:- gl_bits.h
//
#ifndef GL_BITS_H
#define GL_BITS_H
HGLRC GL_GenerateRC (HDC hDC, bool bDoubleBuffer = true);
//GLuint GL_BindImage (CImage *image);
void GL_Enter3D( double dFOV, int iWindowWidth, int iWindowDepth, bool bWireFrame, bool bCLS = true );
void GL_Enter2D (int iWindowWidth, int iWindowDepth, bool bCLS = true);
void GL_Exit2D (void);
int GL_GetCorrectedDim (int iDim);
char* GL_GetCorrectedDimString(int iDim);
LPCSTR GL_GetInfo(void);
#ifdef _DEBUG
#define ASSERT_GL AssertGL(__FILE__,__LINE__)
void AssertGL(const char *sFile, int iLine);
#else
#define ASSERT_GL
#endif
typedef struct tagFRECT
{
float left;
float top;
float right;
float bottom;
} FRECT, FAR *LPFRECT;
#endif // #ifndef GL_BITS_H
/////////////////// eof //////////////////

1708
tools/ModView/glm_code.cpp Normal file

File diff suppressed because it is too large Load Diff

101
tools/ModView/glm_code.h Normal file
View File

@@ -0,0 +1,101 @@
// Filename:- glm_code.h
//
#ifndef GLM_CODE_H
#define GLM_CODE_H
#include "mdx_format.h"
////////////////////////////////////////////////
//
// Jake's stuff...
#define MAX_G2_SURFACES 1000 // this is the max surfaces any model can have. IMPORTANT - used everywhere
#define MAX_G2_LODS 10 // this restriction mainly a MODVIEW thing, but carcass will only build 10 LODs as well because of surfacename rules (ie "xxxx_n" names)
#define MAX_BONE_OVERRIDES 32
#define MAX_POSSIBLE_BONES 512
#define BONE_ANGLES_ABSOLUTE 0x0001
#define BONE_ANGLES_ADDITIVE 0x0002
#define BONE_ANGLES_RELATIVE 0x0004
#define BONE_ANIM_OVERRIDE 0x0008
#define BONE_ANIM_OVERRIDE_LOOP 0x0010
#define BONE_ANIM_NEW_ANIM 0x0020
typedef struct {
int boneNumber;
vec3_t angles;
int flags;
int startFrame;
int endFrame;
float currentFrame;
float newFrame;
float animSpeed;
} boneInfo_t;
typedef enum
{
SURF_ERROR, // needed to replace where Jake just did "return 0", which couldn't be distinguished from SURF_ON
SURF_ON,// = SURF_ERROR,
SURF_OFF,
SURF_NO_DESCENDANTS,
SURF_INHERENTLYOFF // can never be set, but may be returned on query
} SurfaceOnOff_t; // enumerations for offFlags used in surfaceInfo_t
typedef struct {
int ident; // ident of this surface - required so the materials renderer knows what sort of surface this refers to
SurfaceOnOff_t offFlags; // what the flags are for this model
int surface; // index into array held inside the model definition of pointers to the actual surface data loaded in - used by both client and game
void *boneList; // pointer to transformed bone list for this surface - required client side for rendering DONOT USE IN GAME SIDE
void *surfaceData; // pointer to surface data loaded into file - only used by client renderer DO NOT USE IN GAME SIDE - if there is a vid restart this will be out of wack on the game
} surfaceInfo_t;
/*
typedef struct {
float matrix[3][4];
} mdxBone_t;
*/
typedef struct
{
float m[4][4];
}mdxBone4_t;
//
////////////////////////////////////////////////
bool GLMModel_Parse(struct ModelContainer *pContainer, LPCSTR psLocalFilename, HTREEITEM hTreeItem_Parent = NULL);
SurfaceOnOff_t GLMModel_Surface_GetStatus( ModelHandle_t hModel, int iSurfaceIndex );
void GLMModel_DeleteExtra(void);
bool GLMModel_SurfaceContainsBoneReference(ModelHandle_t hModel, int iLODNumber, int iSurfaceNumber, int iBoneNumber);
LPCSTR GLMModel_BoneInfo( ModelHandle_t hModel, int iBoneIndex );
LPCSTR GLMModel_SurfaceVertInfo( ModelHandle_t hModel, int iSurfaceIndex );
LPCSTR GLMModel_SurfaceInfo( ModelHandle_t hModel, int iSurfaceIndex, bool bShortVersionForTag );
bool GLMModel_SurfaceIsTag(ModelHandle_t hModel, int iSurfaceindex );
bool GLMModel_SurfaceIsON(ModelHandle_t hModel, int iSurfaceIndex );
LPCSTR GLMModel_GetSurfaceName( ModelHandle_t hModel, int iSurfaceIndex );
LPCSTR GLMModel_GetSurfaceShaderName( ModelHandle_t hModel, int iSurfaceIndex );
LPCSTR GLMModel_GetBoneName( ModelHandle_t hModel, int iBoneIndex );
bool R_GLMModel_Tree_ReEvalSurfaceText(ModelHandle_t hModel, HTREEITEM hTreeItem = NULL, bool bDeadFromHereOn = false);
bool GLMModel_Surface_Off( ModelHandle_t hModel, int iSurfaceIndex );
bool GLMModel_Surface_On( ModelHandle_t hModel, int iSurfaceIndex );
bool GLMModel_Surface_NoDescendants(ModelHandle_t hModel, int iSurfaceIndex );
bool GLMModel_Surface_SetStatus( ModelHandle_t hModel, int iSurfaceIndex, SurfaceOnOff_t eStatus );
void GLMModel_Surfaces_DefaultAll(ModelHandle_t hModel);
mdxaBone_t *GLMModel_GetBasePoseMatrix(ModelHandle_t hModel, int iBoneIndex);
bool GLMModel_GetBounds(ModelHandle_t hModel, int iLODNumber, int iFrameNumber, vec3_t &v3Mins, vec3_t &v3Maxs);
int GLMModel_EnsureGenerated_VertEdgeInfo(ModelHandle_t hModel, int iLOD, SurfaceEdgeInfoPerLOD_t &SurfaceEdgeInfoPerLOD);
void *GLMModel_GetDefaultGLA(void);
#endif // #ifndef GLM_CODE_H
////////////// eof ////////////

985
tools/ModView/image.cpp Normal file
View File

@@ -0,0 +1,985 @@
// Filename:- image.cpp
//
#include "stdafx.h"
#include "includes.h"
#include "modview.h"
#include "textures.h"
//
#include "image.h"
#ifndef DWORD
#define DWORD unsigned long
#endif
#define iDSTAMP_CELL_PIXDIM 16 // adjust this, higher = more secure but less stamps on picture
#define iDSTAMP_CELL_PIXELS (iDSTAMP_CELL_PIXDIM * iDSTAMP_CELL_PIXDIM)
#define iDSTAMP_INSTANCE_CELLDIM 8 // leave this alone at all times!
#define iDSTAMP_INSTANCE_PIXDIM (iDSTAMP_INSTANCE_CELLDIM * iDSTAMP_CELL_PIXDIM)
#define iDSTAMP_CHAR_BITS 7
#define iHIDDENBIT 1//32 // 1,2,4,8,16,32,64, or 128
#define iHIDDENBITSHIFT 0//5 // 0,1,2,3, 4 5 6 7
#pragma pack(push,1)
typedef struct
{
char sHDR[3]; // "HDR", no trailing zero
char sDDMMYY[6]; // date/month/year, no trailing zero
char sText[14]; // text, no end trailing zero, but maybe early one
} WatermarkData_t;
typedef struct
{
WatermarkData_t Data;
DWORD dwCRC;
} Watermark_t;
typedef struct
{
byte R,G,B,A;
}Pixel_t;
#pragma pack(pop)
typedef struct
{
byte *pPixels;
int iWidth;
int iHeight;
int iPlanes;
} DStampImage_t;
typedef struct
{
DStampImage_t *pImage;
Watermark_t *pWatermark;
} DStampData_t;
Watermark_t TheWatermark;
#define PixelSetR(p,r) p.R=r
#define PixelSetG(p,g) p.G=g
#define PixelSetB(p,b) p.B=b
#define PixelSetA(p,a) p.A=a
#define PixelGetR(p) p.R
#define PixelGetG(p) p.G
#define PixelGetB(p) p.B
#define PixelGetA(p) p.A
#define PixelInit(p) memset(&p,0,sizeof(p)); // later on I'll adapt this for initing default alpha etc, but for now
#define PROGRESS_INIT \
CProgressCtrl *pProgress = NULL; \
if (((CModViewApp*)AfxGetApp())->m_pMainWnd) \
{ \
pProgress = new CProgressCtrl; \
bool bOK = !!pProgress->Create( WS_CHILD|WS_VISIBLE|PBS_SMOOTH, \
CRect(100,100,200,200), \
((CModViewApp*)AfxGetApp())->m_pMainWnd, \
1 \
); \
if (!bOK) \
{ \
delete pProgress; \
pProgress = NULL; \
} \
}
#define PROGRESS_SETRANGE(range) \
if (pProgress) \
{ \
pProgress->SetRange(0,range); \
}
#define PROGRESS_SETPOS(position) \
if (pProgress) \
{ \
pProgress->SetPos(position);\
}
#define PROGRESS_CLOSE \
if (pProgress) \
{ \
delete pProgress; \
pProgress = 0; \
}
// return NULL = legal, else string saying why not...
//
static LPCSTR DStamp_TextIsLegal(LPCSTR psText)
{
int iLen = strlen(psText);
if (iLen > sizeof(TheWatermark.Data.sText))
{
return va("\"%s\" is too long by %d chars",psText, sizeof(TheWatermark.Data.sText) - iLen);
}
for (int i=0; i<iLen; i++)
{
if (psText[i] > 127)
{
return va("\"%s\" contains hi-ascii char '%c', only 7-bit ascii allowed",psText, psText[i]);
}
}
return NULL;
}
static void DStamp_EncryptData(void *pvData, int iByteLength)
{
/* don't use this method since we need to keep as 7-bit ascii
byte *pData = (byte*) pvData;
for (int i=0; i<iByteLength; i++)
{
*pData = *pData ^ ('#'+i);
pData++;
}
*/
}
// same as encrypt at the moment, because of XOR, but may change...
//
static void DStamp_DecryptData(void *pvData, int iByteLength)
{
DStamp_EncryptData(pvData,iByteLength);
}
static DWORD DStamp_UpdateCRC(DWORD dwCRC, byte b)
{
dwCRC += (DWORD) b;
if (dwCRC & (1<<31))
{
dwCRC<<=1;
dwCRC+=2; // add 1, plus carry
}
else
{
dwCRC<<=1;
dwCRC++; // add 1, no carry
}
return dwCRC;
}
static DWORD DStamp_CalcBlockCRC(void *pvData, int iByteLength)
{
byte *pData = (byte*) pvData;
DWORD dwCRC = 0;
for (int i=0; i<iByteLength; i++)
{
dwCRC = DStamp_UpdateCRC(dwCRC, pData[i]);
}
dwCRC &= 0x7F7F7F7F; // lose 7th bit from each byte
return dwCRC;
}
static LPCSTR DStamp_GetYear(void)
{
static char sTemp[20];
time_t ltime;
time( &ltime );
struct tm *today = localtime( &ltime );
strftime( sTemp, sizeof(sTemp), "%d%m%y", today );
return &sTemp[0];
}
static Watermark_t *DStamp_InitWatermark(LPCSTR psText)
{
Watermark_t *pWatermark = &TheWatermark;
strncpy(pWatermark->Data.sHDR, "HDR", sizeof(pWatermark->Data.sHDR));
strncpy(pWatermark->Data.sText, psText, sizeof(pWatermark->Data.sText));
strncpy(pWatermark->Data.sDDMMYY, DStamp_GetYear(), sizeof(pWatermark->Data.sDDMMYY));
DStamp_EncryptData(&pWatermark->Data, sizeof(pWatermark->Data));
pWatermark->dwCRC = DStamp_CalcBlockCRC(&pWatermark->Data, sizeof(pWatermark->Data));
return pWatermark;
}
static Pixel_t *DStamp_GetImagePixel(DStampImage_t *pImage, int iXpos, int iYpos)
{
int iBPP = (pImage->iPlanes == 24)?3:4;
byte *pPixels = pImage->pPixels + (iYpos * pImage->iWidth * iBPP) + (iXpos * iBPP);
static Pixel_t Pixel;
memcpy(&Pixel, pPixels, iBPP);
if (iBPP == 3)
{
Pixel.A = 255; // actually, this can be ignored
}
return &Pixel;
}
static void DStamp_SetImagePixel(DStampImage_t *pImage, int iXpos, int iYpos, Pixel_t *pPixel)
{
int iBPP = (pImage->iPlanes == 24)?3:4;
byte *pPixels = pImage->pPixels + (iYpos * pImage->iWidth * iBPP) + (iXpos * iBPP);
memcpy(pPixels, pPixel, iBPP);
}
// returns either 0 or 1 for bits, or 2 for "finished"
//
static int DStamp_GetWaterMarkBit(int *piSourceIndex_Byte, int *piSourceIndex_Bit, void *pvBytes, int iBytesLen)
{
byte *pBytes = (byte *) pvBytes;
// if (*piSourceIndex_Byte==(int)strlen(psWatermarkString)+1) // trying to get bits from beyond trailing zero?
// return 2;
if (*piSourceIndex_Byte==iBytesLen) // trying to get bits from beyond trailing zero?
return 2;
char c = pBytes[*piSourceIndex_Byte];
int iBitReturn = (c>>*piSourceIndex_Bit)&1;
*piSourceIndex_Bit+=1; // *not* ++!
if (*piSourceIndex_Bit == iDSTAMP_CHAR_BITS)
{
*piSourceIndex_Bit = 0;
*piSourceIndex_Byte+=1; // *not* ++!
}
return iBitReturn;
}
static void DStamp_ReadCell(DStampData_t *pData, int iCellXpos, int iCellYpos, byte *b1, byte *b2, byte *b3)
{
int iWBitR = 0,
iWBitG = 0,
iWBitB = 0;
for (int iPixelY=0; iPixelY<iDSTAMP_CELL_PIXDIM; iPixelY++)
{
for (int iPixelX=0; iPixelX<iDSTAMP_CELL_PIXDIM; iPixelX++)
{
Pixel_t Pixel = *DStamp_GetImagePixel(pData->pImage, iPixelX + iCellXpos, iPixelY + iCellYpos);
iWBitR += (PixelGetR(Pixel)&iHIDDENBIT)?1:0;
iWBitG += (PixelGetG(Pixel)&iHIDDENBIT)?1:0;
iWBitB += (PixelGetB(Pixel)&iHIDDENBIT)?1:0;
}
}
// work out pixel consensuses... (consensi?)
//
// if > half the pixels are true, accept that as true...
//
*b1 = (iWBitR > iDSTAMP_CELL_PIXELS/2)?1:0;
*b2 = (iWBitG > iDSTAMP_CELL_PIXELS/2)?1:0;
*b3 = (iWBitB > iDSTAMP_CELL_PIXELS/2)?1:0;
}
static void DStamp_MarkCell(DStampData_t *pData, int iCellXpos, int iCellYpos, int *piTxtByte, int *piTxtBit)
{
byte R = DStamp_GetWaterMarkBit(piTxtByte, piTxtBit, pData->pWatermark, sizeof(*pData->pWatermark));
byte G = DStamp_GetWaterMarkBit(piTxtByte, piTxtBit, pData->pWatermark, sizeof(*pData->pWatermark));
byte B = DStamp_GetWaterMarkBit(piTxtByte, piTxtBit, pData->pWatermark, sizeof(*pData->pWatermark));
for (int iPixelY=0; iPixelY<iDSTAMP_CELL_PIXDIM; iPixelY++)
{
for (int iPixelX=0; iPixelX<iDSTAMP_CELL_PIXDIM; iPixelX++)
{
Pixel_t Pixel = *DStamp_GetImagePixel(pData->pImage, iPixelX + iCellXpos, iPixelY + iCellYpos);
PixelSetR(Pixel,( (PixelGetR(Pixel)&~iHIDDENBIT) | (((R==2)?0:R)<<iHIDDENBITSHIFT) ));
PixelSetG(Pixel,( (PixelGetG(Pixel)&~iHIDDENBIT) | (((G==2)?0:G)<<iHIDDENBITSHIFT) ));
PixelSetB(Pixel,( (PixelGetB(Pixel)&~iHIDDENBIT) | (((B==2)?0:B)<<iHIDDENBITSHIFT) ));
DStamp_SetImagePixel(pData->pImage, iPixelX + iCellXpos, iPixelY + iCellYpos, &Pixel);
}
}
/* byte R2,G2,B2;
DStamp_ReadCell(pData, iCellXpos, iCellYpos, &R2,&G2,&B2);
assert( (R2==((R==2)?0:R)) &&
(G2==((G==2)?0:G)) &&
(B2==((B==2)?0:B))
);
*/
}
// apply one watermark-instance to the image...
//
static void DStamp_MarkInstance(DStampData_t *pData, int iInstancePixelX, int iInstancePixelY)
{
int iTxtByte = 0;
int iTxtBit = 0;
for (int iYCell = 0; iYCell < iDSTAMP_INSTANCE_CELLDIM; iYCell++)
{
for (int iXCell = 0; iXCell < iDSTAMP_INSTANCE_CELLDIM; iXCell++)
{
int iCellXpos = iInstancePixelX + (iXCell * iDSTAMP_CELL_PIXDIM);
int iCellYpos = iInstancePixelY + (iYCell * iDSTAMP_CELL_PIXDIM);
DStamp_MarkCell(pData, iCellXpos, iCellYpos, &iTxtByte, &iTxtBit);
}
}
}
// see if we can read some watermark data, else return NULL...
//
static LPCSTR DStamp_ReadInstance(DStampData_t *pData, int iInstancePixelX, int iInstancePixelY)
{
LPCSTR psMessage = NULL;
int iTxtByte = 0;
int iTxtBit = 0;
byte *pbOut = (byte*) pData->pWatermark;
memset(pbOut,0,sizeof(*pData->pWatermark));
for (int iYCell = 0; iYCell < iDSTAMP_INSTANCE_CELLDIM; iYCell++)
{
for (int iXCell = 0; iXCell < iDSTAMP_INSTANCE_CELLDIM; iXCell++)
{
int iCellXpos = iInstancePixelX + (iXCell * iDSTAMP_CELL_PIXDIM);
int iCellYpos = iInstancePixelY + (iYCell * iDSTAMP_CELL_PIXDIM);
byte b1,b2,b3;
DStamp_ReadCell(pData, iCellXpos, iCellYpos, &b1,&b2,&b3);
#define DECODEBIT(DestString,bit) \
DestString[iTxtByte] |= bit<<iTxtBit++; \
if (iTxtBit==iDSTAMP_CHAR_BITS) \
{ \
iTxtBit=0; \
iTxtByte++; \
}
DECODEBIT(pbOut,b1);
DECODEBIT(pbOut,b2);
DECODEBIT(pbOut,b3);
if (iTxtByte>=3) // huge speed opt, check for header, if not found, give up on this cell...
{
if (strncmp((char*)pbOut,"HDR",3))
{
return NULL;
}
}
}
}
if (!strncmp(pData->pWatermark->Data.sHDR,"HDR",3))
{
DWORD dwCRC = DStamp_CalcBlockCRC(&pData->pWatermark->Data, sizeof(pData->pWatermark->Data));
char sString[100];
char sDate[100];
strncpy(sString,pData->pWatermark->Data.sText,sizeof(pData->pWatermark->Data.sText));
sString[sizeof(pData->pWatermark->Data.sText)] = '\0';
strncpy(sDate,pData->pWatermark->Data.sDDMMYY,sizeof(pData->pWatermark->Data.sDDMMYY));
sDate[sizeof(pData->pWatermark->Data.sDDMMYY)] = '\0';
static char sOutput[1024];
sprintf(sOutput,"SentTo: \"%s\", Date(DD/MM/YY) = %s",sString,sDate);
if (dwCRC == pData->pWatermark->dwCRC)
{
OutputDebugString(sOutput);
psMessage = &sOutput[0];
}
else
{
OutputDebugString(va("Skipping non-CRC HDR-match: %s\n",sOutput));
}
}
return psMessage;
}
// return is NULL for ok, else error string...
//
LPCSTR DStamp_MarkImage(byte *pPixels, int iWidth, int iHeight, int iPlanes, LPCSTR psText)
{
LPCSTR psError = NULL;
if (iPlanes == 24 || iPlanes == 32)
{
psError = DStamp_TextIsLegal(psText);
if (!psError)
{
DStampImage_t Image;
Image.pPixels = pPixels;
Image.iWidth = iWidth;
Image.iHeight = iHeight;
Image.iPlanes = iPlanes;
DStampData_t Data;
Data.pImage = &Image;
Data.pWatermark = DStamp_InitWatermark(psText);
int iInstances_Across = Data.pImage->iWidth / iDSTAMP_INSTANCE_PIXDIM;
int iInstances_Down = Data.pImage->iHeight / iDSTAMP_INSTANCE_PIXDIM;
int iInstancesTotal = iInstances_Across * iInstances_Down;
#ifdef _DEBUG
int iDebug_WaterMarkSize = sizeof(Watermark_t);
OutputDebugString(va("%d stamp instances on screen\n",iInstancesTotal));
#endif
if (iInstancesTotal)
{
// center the stamp grid within the image...
//
int iYStart = (Data.pImage->iHeight - (iInstances_Down * iDSTAMP_INSTANCE_PIXDIM))/2;
int iXStart = (Data.pImage->iWidth - (iInstances_Across * iDSTAMP_INSTANCE_PIXDIM))/2;
for (int iInstanceY = 0; iInstanceY < iInstances_Down; iInstanceY++)
{
for (int iInstanceX = 0; iInstanceX < iInstances_Across; iInstanceX++)
{
int iInstancePixelX = (iInstanceX * iDSTAMP_INSTANCE_PIXDIM) + iXStart;
int iInstancePixelY = (iInstanceY * iDSTAMP_INSTANCE_PIXDIM) + iYStart;
DStamp_MarkInstance(&Data, iInstancePixelX, iInstancePixelY);
// LPCSTR psMessage = DStamp_ReadInstance(&Data, iInstancePixelX, iInstancePixelY);
// if (psMessage)
// {
// OutputDebugString(va("Marked Instance with message \"%s\"\n",psMessage));
// }
// else
// {
// int z=1;
// }
}
}
}
else
{
psError = va("DStamp_MarkImage(): Unable to fit watermark on screen using iDSTAMP_CELL_PIXDIM of %d!",iDSTAMP_CELL_PIXDIM);
}
}
}
else
{
psError = "DStamp_MarkImage(): Supplied image must be 24 or 32 bit";
}
return psError;
}
bool DStamp_MarkImage(Texture_t *pTexture, LPCSTR psText)
{
LPCSTR psError = DStamp_MarkImage(pTexture->pPixels, pTexture->iWidth, pTexture->iHeight, 32, psText);
if (!psError)
return true;
ErrorBox(psError);
return false;
}
void DStamp_AnalyseImage(byte *pPixels, int iWidth, int iHeight, int iPlanes)
{
CWaitCursor wait;
const int iBlockSampleSize = 8;
PROGRESS_INIT;
PROGRESS_SETRANGE((iHeight/iBlockSampleSize));
DStampImage_t Image;
Image.pPixels = pPixels;
Image.iWidth = iWidth;
Image.iHeight = iHeight;
Image.iPlanes = iPlanes;
DStampImage_t ImageOut;
ImageOut.pPixels = (byte *) malloc (iWidth * iHeight * ((iPlanes == 24)?3:4));
ImageOut.iWidth = iWidth;
ImageOut.iHeight = iHeight;
ImageOut.iPlanes = iPlanes;
/*
// new line dup code...
//
for (int y=0; y<iHeight-3; y+=30)
{
for (int x=0; x<iWidth; x++)
{
Pixel_t *pPixel = DStamp_GetImagePixel(&Image, x, y);
DStamp_SetImagePixel(&Image, x, y+1, pPixel);
DStamp_SetImagePixel(&Image, x, y+2, pPixel);
DStamp_SetImagePixel(&Image, x, y+3, pPixel);
}
}
*/
#if 1
for (int y = 0; y+iBlockSampleSize < iHeight; y += iBlockSampleSize)
{
PROGRESS_SETPOS(y);
for (int x = 0; x+iBlockSampleSize < iWidth; x += iBlockSampleSize)
{
unsigned int r=0,g=0,b=0;
unsigned int rh=0,gh=0,bh=0;
unsigned int rl=INT_MAX,gl=INT_MAX,bl=INT_MAX;
if (x==120 && y==232)
{
int z=1;
}
int iNoisyPixels = 0;
int iMassivelyDeviantPixels = 0;
for (int iBlockPass=0; iBlockPass<3; iBlockPass++)
{
// pass 0 = read pixels, average out channels
// pass 1 = count noisy pixels
// pass 2 = colour in block as 0 or 255 to show noise if > half blocks noisy
//
for (int by=0; by < iBlockSampleSize; by++)
{
for (int bx=0; bx < iBlockSampleSize; bx++)
{
int px = x+bx;
int py = y+by;
Pixel_t *pPixel = DStamp_GetImagePixel(&Image, px, py);
switch (iBlockPass)
{
case 0: // read/accumulate pixel values...
{
r += pPixel->R;
g += pPixel->G;
b += pPixel->B;
rh = max(rh,pPixel->R);
gh = max(gh,pPixel->G);
bh = max(bh,pPixel->B);
rl = min(rl,pPixel->R);
gl = min(gl,pPixel->G);
bl = min(bl,pPixel->B);
}
break;
case 1: // analyse...
{
if (rh-rl>90 ||
gh-gl>90 ||
bh-bl>90
)
{
iMassivelyDeviantPixels++;
}
if (px>0 && px<iWidth-1 && py>0 && py<iHeight-1)
{
int this_r = pPixel->R;
int this_g = pPixel->G;
int this_b = pPixel->B;
bool bPixelIsNoisy = false;
if (px==123 && py==235)
{
int z=1;
}
for (int y2=py-1; y2<py+2 && !bPixelIsNoisy; y2++)
{
for (int x2=px-1; x2<px+2 && !bPixelIsNoisy; x2++)
{
if (x2!=px&&y2!=py)
{
pPixel = DStamp_GetImagePixel(&Image, x2, y2);
int rdiff = abs(pPixel->R - this_r);
int gdiff = abs(pPixel->G - this_g);
int bdiff = abs(pPixel->B - this_b);
const int iMinTolerance = 7;
const int iMaxTolerance = 50;
if ((rdiff > iMaxTolerance) ||
(gdiff > iMaxTolerance) ||
(bdiff > iMaxTolerance) ||
abs(pPixel->R - r) > iMaxTolerance ||
abs(pPixel->G - g) > iMaxTolerance ||
abs(pPixel->B - b) > iMaxTolerance
)
{
//iMassivelyDeviantPixels++;
iNoisyPixels-=5000; // force not to be noisy for blocks with sharp contrasts
}
else
if ((rdiff > iMinTolerance && rdiff < iMaxTolerance) ||
(gdiff > iMinTolerance && gdiff < iMaxTolerance) ||
(bdiff > iMinTolerance && bdiff < iMaxTolerance)
)
{
bPixelIsNoisy = true;
}
}
}
}
if (bPixelIsNoisy)
{
iNoisyPixels++;
}
}
}
break;
case 2: // paint...
{
pPixel->R = pPixel->G = pPixel->B = (iNoisyPixels>((iBlockSampleSize*iBlockSampleSize)/2))?255:0;
DStamp_SetImagePixel(&ImageOut, x+bx, y+by, pPixel);
}
break;
}
}
}
switch (iBlockPass)
{
case 0:
r /= iBlockSampleSize*iBlockSampleSize;
g /= iBlockSampleSize*iBlockSampleSize;
b /= iBlockSampleSize*iBlockSampleSize;
break;
case 1:
if (iMassivelyDeviantPixels > (iBlockSampleSize*iBlockSampleSize)/8)
{
// if > 1/8th of the pixels are massively deviant, then set this block so we can't use it.
iNoisyPixels-=5000; // force not to be noisy for blocks with sharp contrasts
}
break;
}
}
}
}
#endif
#if 1
// copy analysis results over input picture for saving on return...
//
DStampImage_t ImageTmp;
ImageTmp.pPixels = (byte *) malloc (iWidth * iHeight * ((iPlanes == 24)?3:4));
ImageTmp.iWidth = iWidth;
ImageTmp.iHeight = iHeight;
ImageTmp.iPlanes = iPlanes;
memcpy(ImageTmp.pPixels,ImageOut.pPixels, iWidth * iHeight * ((iPlanes == 24)?3:4));
// now eliminate any single white or black sampleblocks...
//
// for (int iEliminate = 0; iEliminate<2; iEliminate++)
{
// start one-in from all edges, so we can check 8 surrounding squares safely...
//
for (y = 0+iBlockSampleSize; y + (2*iBlockSampleSize) < iHeight; y += iBlockSampleSize)
{
for (int x = 0+iBlockSampleSize; x + (2*iBlockSampleSize) < iWidth; x+= iBlockSampleSize)
{
unsigned int r=0,g=0,b=0;
Pixel_t *pPixel = DStamp_GetImagePixel(&ImageTmp, x, y);
bool bThisPixelWasBlack = !(pPixel->R); // all channels same, so just checking R is fine
//if (bThisPixelWasBlack)
{
// now check neighbours, all 8 surrounding blocks must be same colour, or bye-bye...
//
bool bSurroundedByOpposite = true;
for (int y2=y-iBlockSampleSize; y2<y+(2*iBlockSampleSize) && bSurroundedByOpposite; y2+=iBlockSampleSize)
{
for (int x2=x-iBlockSampleSize; x2<x+(2*iBlockSampleSize) && bSurroundedByOpposite; x2+=iBlockSampleSize)
{
if (x2!=x && y2!=y)
{
Pixel_t *pPixel = DStamp_GetImagePixel(&ImageTmp, x2, y2);
bool bScanPixelWasBlack = !(pPixel->R);
if (bScanPixelWasBlack == bThisPixelWasBlack)
{
bSurroundedByOpposite = false;
}
}
}
}
if (bSurroundedByOpposite)
{
// blot this pixel out by toggling it to the other colour...
//
pPixel->R = pPixel->G = pPixel->B = bThisPixelWasBlack?255:0;
for (int py=y; py<y+iBlockSampleSize; py++)
{
for (int px=x; px<x+iBlockSampleSize; px++)
{
DStamp_SetImagePixel(&ImageOut, px, py, pPixel);
}
}
}
}
}
}
}
memcpy(ImageTmp.pPixels,ImageOut.pPixels, iWidth * iHeight * ((iPlanes == 24)?3:4));
#endif
// now highlight original pic with differences...
//
for (y=0; y+iBlockSampleSize < iHeight; y+=iBlockSampleSize)
{
for (int x=0; x+iBlockSampleSize < iWidth; x+=iBlockSampleSize)
{
Pixel_t *pPixel = DStamp_GetImagePixel(&ImageTmp, x, y);
bool bThisPixelWasBlack = !(pPixel->R); // all channels same, so just checking R is fine
// bool bPrevPixelWasBlack = true;
// if (x>=iBlockSampleSize)
// {
// pPixel = DStamp_GetImagePixel(&ImageTmp, x-iBlockSampleSize, y);
// bPrevPixelWasBlack = !(pPixel->R); // all channels same, so just checking R is fine
// }
if (!bThisPixelWasBlack )//&& !bPrevPixelWasBlack)
{
unsigned int r=0,g=0,b=0;
for (int iPass=0; iPass<2; iPass++)
{
// highlight this sample square of the original pic...
//
for (int y2=y; y2<y+iBlockSampleSize; y2++)
{
for (int x2=x; x2<x+iBlockSampleSize; x2++)
{
if (!iPass)
{
pPixel = DStamp_GetImagePixel(&Image, x2, y2);
r+= pPixel->R;
g+= pPixel->G;
b+= pPixel->B;
}
else
{
#if 1
// highlight...
//
pPixel = DStamp_GetImagePixel(&Image, x2/*-iBlockSampleSize*/, y2);
pPixel->R |= 128;
pPixel->G &=~128;
pPixel->B &=~128;
#else
pPixel = DStamp_GetImagePixel(&Image, x2, y2);
pPixel->R = (r + pPixel->R)/2;
pPixel->G = (g + pPixel->G)/2;
pPixel->B = (b + pPixel->B)/2;
#endif
DStamp_SetImagePixel(&Image, x2, y2, pPixel);
}
}
}
if (!iPass)
{
pPixel->R = r = r/(iBlockSampleSize*iBlockSampleSize);
pPixel->G = g = g/(iBlockSampleSize*iBlockSampleSize);
pPixel->B = b = b/(iBlockSampleSize*iBlockSampleSize);
}
}
}
}
}
PROGRESS_CLOSE;
free(ImageTmp.pPixels);
free(ImageOut.pPixels);
}
void DStamp_AnalyseImage(Texture_t *pTexture)
{
DStamp_AnalyseImage(pTexture->pPixels, pTexture->iWidth, pTexture->iHeight, 32);
}
LPCSTR DStamp_ReadImage(byte *pPixels, int iWidth, int iHeight, int iPlanes)
{
CWaitCursor wait;
LPCSTR psMessage = NULL;
if (iPlanes == 24 || iPlanes == 32)
{
DStampImage_t Image;
Image.pPixels = pPixels;
Image.iWidth = iWidth;
Image.iHeight = iHeight;
Image.iPlanes = iPlanes;
DStampData_t Data;
Data.pImage = &Image;
Data.pWatermark = &TheWatermark;
if (1)
{
int iInstances_Across = Data.pImage->iWidth / iDSTAMP_INSTANCE_PIXDIM;
int iInstances_Down = Data.pImage->iHeight / iDSTAMP_INSTANCE_PIXDIM;
// #ifdef _DEBUG
// int iDebug_WaterMarkSize = sizeof(Watermark_t);
// int iDebug_InstancesTotal = iInstances_Across * iInstances_Down;
// #endif
/*
#define iDSTAMP_CELL_PIXDIM 16 // adjust this, higher = more secure but less stamps on picture
#define iDSTAMP_CELL_PIXELS (iDSTAMP_CELL_PIXDIM * iDSTAMP_CELL_PIXDIM)
#define iDSTAMP_INSTANCE_CELLDIM 8 // leave this alone at all times!
#define iDSTAMP_INSTANCE_PIXDIM (iDSTAMP_INSTANCE_CELLDIM * iDSTAMP_CELL_PIXDIM)
#define iDSTAMP_CHAR_BITS 7
*/
CProgressCtrl *pProgress = NULL;
if (((CModViewApp*)AfxGetApp())->m_pMainWnd)
{
pProgress = new CProgressCtrl;
bool bOK = !!pProgress->Create( WS_CHILD|WS_VISIBLE|PBS_SMOOTH, // DWORD dwStyle,
CRect(100,100,200,200), // const RECT& rect,
((CModViewApp*)AfxGetApp())->m_pMainWnd, // CWnd* pParentWnd,
1 // UINT nID
);
if (!bOK)
{
delete pProgress;
pProgress = NULL;
}
}
// the image may have been cropped, so we need to hunt for the signature at every pixel position...
//
int iYScans = 0;
for (int iLazy = 0; iLazy<2; iLazy++)
{
for (int iYStart = 0; iYStart < iDSTAMP_INSTANCE_PIXDIM && !psMessage; iYStart++)
{
if (iLazy)
{
if (pProgress)
{
pProgress->SetRange(0,iYScans);
}
OutputDebugString(va("iYStart %%%d\n",(iYStart*100)/iDSTAMP_INSTANCE_PIXDIM));
if (pProgress)
{
pProgress->SetPos(iYStart);
// wait.Restore();
}
for (int iXStart = 0; iXStart < iDSTAMP_INSTANCE_PIXDIM && !psMessage; iXStart++)
{
// look for some stamps here...
//
for (int iInstanceY = 0; iInstanceY < iInstances_Down && !psMessage; iInstanceY++)
{
for (int iInstanceX = 0; iInstanceX < iInstances_Across && !psMessage; iInstanceX++)
{
int iInstancePixelX = (iInstanceX * iDSTAMP_INSTANCE_PIXDIM) + iXStart;
int iInstancePixelY = (iInstanceY * iDSTAMP_INSTANCE_PIXDIM) + iYStart;
if (iInstancePixelX + iDSTAMP_INSTANCE_PIXDIM >= iWidth
||
iInstancePixelY + iDSTAMP_INSTANCE_PIXDIM >= iHeight
)
{
// ... then skip this position while hunting for header start
}
else
{
psMessage = DStamp_ReadInstance(&Data, iInstancePixelX, iInstancePixelY);
}
}
}
}
}
else
{
for (int iInstanceY = 0; iInstanceY < iInstances_Down; iInstanceY++)
{
int iInstancePixelY = (iInstanceY * iDSTAMP_INSTANCE_PIXDIM) + iYStart;
if (iInstancePixelY + iDSTAMP_INSTANCE_PIXDIM >= iHeight)
{
}
else
{
iYScans++;
}
}
}
}
}
if (pProgress)
{
delete pProgress;
pProgress = 0;
}
}
}
else
{
ErrorBox("DStamp_ReadImage(): Supplied image must be 24 or 32 bit");
}
return psMessage;
}
////////////////// eof ////////////////

21
tools/ModView/image.h Normal file
View File

@@ -0,0 +1,21 @@
// Filename:- image.h
//
#ifndef IMAGE_H
#define IMAGE_H
#include "textures.h"
bool DStamp_MarkImage(Texture_t *pTexture, LPCSTR psText); // this-app-specific
LPCSTR DStamp_MarkImage(byte *pPixels, int iWidth, int iHeight, int iPlanes, LPCSTR psText); // generic
LPCSTR DStamp_ReadImage(byte *pPixels, int iWidth, int iHeight, int iPlanes);
void DStamp_AnalyseImage(byte *pPixels, int iWidth, int iHeight, int iPlanes);
void DStamp_AnalyseImage(Texture_t *pTexture);
#endif // #ifndef IMAGE_H
//////////////// eof ////////////

107
tools/ModView/includes.h Normal file
View File

@@ -0,0 +1,107 @@
// Filename:- includes.h
//
#ifndef INCLUDES_H
#define INCLUDES_H
#include <gl\gl.h>
#include <gl\glu.h>
#include <assert.h>
#include <math.h>
typedef int ModelHandle_t; // keep as sequential int, currently I allow 0..255 models
typedef enum {
MOD_BAD,
MOD_BRUSH,
MOD_MESH,
MOD_MD4,
MOD_MDXM,
MOD_MDXA
} modtype_t;
////////////////////////////////////////////////////
//
// unfortunately, there isn't one tiny file I can just get these defines from without importing 10,000 other lines
// of crap I don't want, so for now....
//
#ifndef MAX_QPATH
#define MAX_QPATH 64
#define MAX_OSPATH MAX_PATH
#define MAX_SKIN_FILES 1000 // some high number we'll never reach (probably)
// surface geometry should not exceed these limits to be legal within Q3 engine
#define SHADER_MAX_VERTEXES 1000
#define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES)
//
// ... but in order for ModView to work with Xmen models I need to have a higher limit...
//
#define ACTUAL_SHADER_MAX_VERTEXES (SHADER_MAX_VERTEXES*3) // *3 is arbitrary, if we hit the limit, increase it.
#define ACTUAL_SHADER_MAX_INDEXES (SHADER_MAX_INDEXES*3) // ""
extern bool bQ3RulesApply;
extern bool bXMenPathHack;
#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString
#define MAX_STRING_TOKENS 256 // max tokens resulting from Cmd_TokenizeString
#define MAX_TOKEN_CHARS 1024 // max length of an individual token
#define MAX_INFO_STRING 1024
#define MAX_INFO_KEY 1024
#define MAX_INFO_VALUE 1024
#define BIG_INFO_STRING 8192 // used for system info key only
#define BIG_INFO_KEY 8192
#define BIG_INFO_VALUE 8192
#define LL(x) x // LittleLong(x) // no need to byteswap for now, this is only a Windoze app
#define LF(x) x // LittleFloat(x)
#define LS(x) x // LittleShort(x)
typedef enum {qfalse, qtrue} qboolean;
typedef int qhandle_t;
typedef int TextureHandle_t;
#define QDECL __cdecl
// angle indexes
#define PITCH 0 // up / down
#define YAW 1 // left / right
#define ROLL 2 // fall over
#ifdef DOUBLEVEC_T
typedef double vec_t;
#else
typedef float vec_t;
#endif
typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
#endif // #ifndef MAX_QPATH
//
////////////////////////////////////////////////////
#include "generic_stuff.h"
#include "gl_bits.h"
#include "model.h"
#include "stl.h"
#ifndef SAFEFREE
#define SAFEFREE(blah) if (blah){free(blah);blah=NULL;}
#endif
#define ZEROMEM(blah) memset(&blah,0,sizeof(blah))
#define ZEROMEMPTR(blah) memset(blah,0,sizeof(*blah))
#endif // #ifndef INCLUDES_H
////////////////////// eof /////////////////////

View File

@@ -0,0 +1,94 @@
/*
* jcomapi.c
*
* Copyright (C) 1994, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains application interface routines that are used for both
* compression and decompression.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/*
* Abort processing of a JPEG compression or decompression operation,
* but don't destroy the object itself.
*
* For this, we merely clean up all the nonpermanent memory pools.
* Note that temp files (virtual arrays) are not allowed to belong to
* the permanent pool, so we will be able to close all temp files here.
* Closing a data source or destination, if necessary, is the application's
* responsibility.
*/
GLOBAL void
jpeg_abort (j_common_ptr cinfo)
{
int pool;
/* Releasing pools in reverse order might help avoid fragmentation
* with some (brain-damaged) malloc libraries.
*/
for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) {
(*cinfo->mem->free_pool) (cinfo, pool);
}
/* Reset overall state for possible reuse of object */
cinfo->global_state = (cinfo->is_decompressor ? DSTATE_START : CSTATE_START);
}
/*
* Destruction of a JPEG object.
*
* Everything gets deallocated except the master jpeg_compress_struct itself
* and the error manager struct. Both of these are supplied by the application
* and must be freed, if necessary, by the application. (Often they are on
* the stack and so don't need to be freed anyway.)
* Closing a data source or destination, if necessary, is the application's
* responsibility.
*/
GLOBAL void
jpeg_destroy (j_common_ptr cinfo)
{
/* We need only tell the memory manager to release everything. */
/* NB: mem pointer is NULL if memory mgr failed to initialize. */
if (cinfo->mem != NULL)
(*cinfo->mem->self_destruct) (cinfo);
cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */
cinfo->global_state = 0; /* mark it destroyed */
}
/*
* Convenience routines for allocating quantization and Huffman tables.
* (Would jutils.c be a more reasonable place to put these?)
*/
GLOBAL JQUANT_TBL *
jpeg_alloc_quant_table (j_common_ptr cinfo)
{
JQUANT_TBL *tbl;
tbl = (JQUANT_TBL *)
(*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL));
tbl->sent_table = FALSE; /* make sure this is false in any new table */
return tbl;
}
GLOBAL JHUFF_TBL *
jpeg_alloc_huff_table (j_common_ptr cinfo)
{
JHUFF_TBL *tbl;
tbl = (JHUFF_TBL *)
(*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL));
tbl->sent_table = FALSE; /* make sure this is false in any new table */
return tbl;
}

View File

@@ -0,0 +1,41 @@
/* jconfig.wat --- jconfig.h for Watcom C/C++ on MS-DOS or OS/2. */
/* see jconfig.doc for explanations */
#define HAVE_PROTOTYPES
#define HAVE_UNSIGNED_CHAR
#define HAVE_UNSIGNED_SHORT
/* #define void char */
/* #define const */
#define CHAR_IS_UNSIGNED
#define HAVE_STDDEF_H
#define HAVE_STDLIB_H
#undef NEED_BSD_STRINGS
#undef NEED_SYS_TYPES_H
#undef NEED_FAR_POINTERS /* Watcom uses flat 32-bit addressing */
#undef NEED_SHORT_EXTERNAL_NAMES
#undef INCOMPLETE_TYPES_BROKEN
#define JDCT_DEFAULT JDCT_FLOAT
#define JDCT_FASTEST JDCT_FLOAT
#ifdef JPEG_INTERNALS
#undef RIGHT_SHIFT_IS_UNSIGNED
#endif /* JPEG_INTERNALS */
#ifdef JPEG_CJPEG_DJPEG
#define BMP_SUPPORTED /* BMP image file format */
#define GIF_SUPPORTED /* GIF image file format */
#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
#undef RLE_SUPPORTED /* Utah RLE image file format */
#define TARGA_SUPPORTED /* Targa image file format */
#undef TWO_FILE_COMMANDLINE /* optional */
#define USE_SETMODE /* Needed to make one-file style work in Watcom */
#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */
#undef DONT_USE_B_MODE
#undef PROGRESS_REPORT /* optional */
#endif /* JPEG_CJPEG_DJPEG */

View File

@@ -0,0 +1,398 @@
/*
* jdapimin.c
*
* Copyright (C) 1994-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains application interface code for the decompression half
* of the JPEG library. These are the "minimum" API routines that may be
* needed in either the normal full-decompression case or the
* transcoding-only case.
*
* Most of the routines intended to be called directly by an application
* are in this file or in jdapistd.c. But also see jcomapi.c for routines
* shared by compression and decompression, and jdtrans.c for the transcoding
* case.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/*
* Initialization of a JPEG decompression object.
* The error manager must already be set up (in case memory manager fails).
*/
GLOBAL void
jpeg_create_decompress (j_decompress_ptr cinfo)
{
int i;
/* For debugging purposes, zero the whole master structure.
* But error manager pointer is already there, so save and restore it.
*/
{
struct jpeg_error_mgr * err = cinfo->err;
MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct));
cinfo->err = err;
}
cinfo->is_decompressor = TRUE;
/* Initialize a memory manager instance for this object */
jinit_memory_mgr((j_common_ptr) cinfo);
/* Zero out pointers to permanent structures. */
cinfo->progress = NULL;
cinfo->src = NULL;
for (i = 0; i < NUM_QUANT_TBLS; i++)
cinfo->quant_tbl_ptrs[i] = NULL;
for (i = 0; i < NUM_HUFF_TBLS; i++) {
cinfo->dc_huff_tbl_ptrs[i] = NULL;
cinfo->ac_huff_tbl_ptrs[i] = NULL;
}
/* Initialize marker processor so application can override methods
* for COM, APPn markers before calling jpeg_read_header.
*/
jinit_marker_reader(cinfo);
/* And initialize the overall input controller. */
jinit_input_controller(cinfo);
/* OK, I'm ready */
cinfo->global_state = DSTATE_START;
}
/*
* Destruction of a JPEG decompression object
*/
GLOBAL void
jpeg_destroy_decompress (j_decompress_ptr cinfo)
{
jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
}
/*
* Abort processing of a JPEG decompression operation,
* but don't destroy the object itself.
*/
GLOBAL void
jpeg_abort_decompress (j_decompress_ptr cinfo)
{
jpeg_abort((j_common_ptr) cinfo); /* use common routine */
}
/*
* Install a special processing method for COM or APPn markers.
*/
GLOBAL void
jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code,
jpeg_marker_parser_method routine)
{
if (marker_code == JPEG_COM)
cinfo->marker->process_COM = routine;
else if (marker_code >= JPEG_APP0 && marker_code <= JPEG_APP0+15)
cinfo->marker->process_APPn[marker_code-JPEG_APP0] = routine;
else
ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);
}
/*
* Set default decompression parameters.
*/
LOCAL void
default_decompress_parms (j_decompress_ptr cinfo)
{
/* Guess the input colorspace, and set output colorspace accordingly. */
/* (Wish JPEG committee had provided a real way to specify this...) */
/* Note application may override our guesses. */
switch (cinfo->num_components) {
case 1:
cinfo->jpeg_color_space = JCS_GRAYSCALE;
cinfo->out_color_space = JCS_GRAYSCALE;
break;
case 3:
if (cinfo->saw_JFIF_marker) {
cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */
} else if (cinfo->saw_Adobe_marker) {
switch (cinfo->Adobe_transform) {
case 0:
cinfo->jpeg_color_space = JCS_RGB;
break;
case 1:
cinfo->jpeg_color_space = JCS_YCbCr;
break;
default:
WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
break;
}
} else {
/* Saw no special markers, try to guess from the component IDs */
int cid0 = cinfo->comp_info[0].component_id;
int cid1 = cinfo->comp_info[1].component_id;
int cid2 = cinfo->comp_info[2].component_id;
if (cid0 == 1 && cid1 == 2 && cid2 == 3)
cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
else {
TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
}
}
/* Always guess RGB is proper output colorspace. */
cinfo->out_color_space = JCS_RGB;
break;
case 4:
if (cinfo->saw_Adobe_marker) {
switch (cinfo->Adobe_transform) {
case 0:
cinfo->jpeg_color_space = JCS_CMYK;
break;
case 2:
cinfo->jpeg_color_space = JCS_YCCK;
break;
default:
WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */
break;
}
} else {
/* No special markers, assume straight CMYK. */
cinfo->jpeg_color_space = JCS_CMYK;
}
cinfo->out_color_space = JCS_CMYK;
break;
default:
cinfo->jpeg_color_space = JCS_UNKNOWN;
cinfo->out_color_space = JCS_UNKNOWN;
break;
}
/* Set defaults for other decompression parameters. */
cinfo->scale_num = 1; /* 1:1 scaling */
cinfo->scale_denom = 1;
cinfo->output_gamma = 1.0;
cinfo->buffered_image = FALSE;
cinfo->raw_data_out = FALSE;
cinfo->dct_method = JDCT_DEFAULT;
cinfo->do_fancy_upsampling = TRUE;
cinfo->do_block_smoothing = TRUE;
cinfo->quantize_colors = FALSE;
/* We set these in case application only sets quantize_colors. */
cinfo->dither_mode = JDITHER_FS;
#ifdef QUANT_2PASS_SUPPORTED
cinfo->two_pass_quantize = TRUE;
#else
cinfo->two_pass_quantize = FALSE;
#endif
cinfo->desired_number_of_colors = 256;
cinfo->colormap = NULL;
/* Initialize for no mode change in buffered-image mode. */
cinfo->enable_1pass_quant = FALSE;
cinfo->enable_external_quant = FALSE;
cinfo->enable_2pass_quant = FALSE;
}
/*
* Decompression startup: read start of JPEG datastream to see what's there.
* Need only initialize JPEG object and supply a data source before calling.
*
* This routine will read as far as the first SOS marker (ie, actual start of
* compressed data), and will save all tables and parameters in the JPEG
* object. It will also initialize the decompression parameters to default
* values, and finally return JPEG_HEADER_OK. On return, the application may
* adjust the decompression parameters and then call jpeg_start_decompress.
* (Or, if the application only wanted to determine the image parameters,
* the data need not be decompressed. In that case, call jpeg_abort or
* jpeg_destroy to release any temporary space.)
* If an abbreviated (tables only) datastream is presented, the routine will
* return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then
* re-use the JPEG object to read the abbreviated image datastream(s).
* It is unnecessary (but OK) to call jpeg_abort in this case.
* The JPEG_SUSPENDED return code only occurs if the data source module
* requests suspension of the decompressor. In this case the application
* should load more source data and then re-call jpeg_read_header to resume
* processing.
* If a non-suspending data source is used and require_image is TRUE, then the
* return code need not be inspected since only JPEG_HEADER_OK is possible.
*
* This routine is now just a front end to jpeg_consume_input, with some
* extra error checking.
*/
GLOBAL int
jpeg_read_header (j_decompress_ptr cinfo, boolean require_image)
{
int retcode;
if (cinfo->global_state != DSTATE_START &&
cinfo->global_state != DSTATE_INHEADER)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
retcode = jpeg_consume_input(cinfo);
switch (retcode) {
case JPEG_REACHED_SOS:
retcode = JPEG_HEADER_OK;
break;
case JPEG_REACHED_EOI:
if (require_image) /* Complain if application wanted an image */
ERREXIT(cinfo, JERR_NO_IMAGE);
/* Reset to start state; it would be safer to require the application to
* call jpeg_abort, but we can't change it now for compatibility reasons.
* A side effect is to free any temporary memory (there shouldn't be any).
*/
jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */
retcode = JPEG_HEADER_TABLES_ONLY;
break;
case JPEG_SUSPENDED:
/* no work */
break;
}
return retcode;
}
/*
* Consume data in advance of what the decompressor requires.
* This can be called at any time once the decompressor object has
* been created and a data source has been set up.
*
* This routine is essentially a state machine that handles a couple
* of critical state-transition actions, namely initial setup and
* transition from header scanning to ready-for-start_decompress.
* All the actual input is done via the input controller's consume_input
* method.
*/
GLOBAL int
jpeg_consume_input (j_decompress_ptr cinfo)
{
int retcode = JPEG_SUSPENDED;
/* NB: every possible DSTATE value should be listed in this switch */
switch (cinfo->global_state) {
case DSTATE_START:
/* Start-of-datastream actions: reset appropriate modules */
(*cinfo->inputctl->reset_input_controller) (cinfo);
/* Initialize application's data source module */
(*cinfo->src->init_source) (cinfo);
cinfo->global_state = DSTATE_INHEADER;
/*FALLTHROUGH*/
case DSTATE_INHEADER:
retcode = (*cinfo->inputctl->consume_input) (cinfo);
if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */
/* Set up default parameters based on header data */
default_decompress_parms(cinfo);
/* Set global state: ready for start_decompress */
cinfo->global_state = DSTATE_READY;
}
break;
case DSTATE_READY:
/* Can't advance past first SOS until start_decompress is called */
retcode = JPEG_REACHED_SOS;
break;
case DSTATE_PRELOAD:
case DSTATE_PRESCAN:
case DSTATE_SCANNING:
case DSTATE_RAW_OK:
case DSTATE_BUFIMAGE:
case DSTATE_BUFPOST:
case DSTATE_STOPPING:
retcode = (*cinfo->inputctl->consume_input) (cinfo);
break;
default:
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
}
return retcode;
}
/*
* Have we finished reading the input file?
*/
GLOBAL boolean
jpeg_input_complete (j_decompress_ptr cinfo)
{
/* Check for valid jpeg object */
if (cinfo->global_state < DSTATE_START ||
cinfo->global_state > DSTATE_STOPPING)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
return cinfo->inputctl->eoi_reached;
}
/*
* Is there more than one scan?
*/
GLOBAL boolean
jpeg_has_multiple_scans (j_decompress_ptr cinfo)
{
/* Only valid after jpeg_read_header completes */
if (cinfo->global_state < DSTATE_READY ||
cinfo->global_state > DSTATE_STOPPING)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
return cinfo->inputctl->has_multiple_scans;
}
/*
* Finish JPEG decompression.
*
* This will normally just verify the file trailer and release temp storage.
*
* Returns FALSE if suspended. The return value need be inspected only if
* a suspending data source is used.
*/
GLOBAL boolean
jpeg_finish_decompress (j_decompress_ptr cinfo)
{
if ((cinfo->global_state == DSTATE_SCANNING ||
cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) {
/* Terminate final pass of non-buffered mode */
if (cinfo->output_scanline < cinfo->output_height)
ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
(*cinfo->master->finish_output_pass) (cinfo);
cinfo->global_state = DSTATE_STOPPING;
} else if (cinfo->global_state == DSTATE_BUFIMAGE) {
/* Finishing after a buffered-image operation */
cinfo->global_state = DSTATE_STOPPING;
} else if (cinfo->global_state != DSTATE_STOPPING) {
/* STOPPING = repeat call after a suspension, anything else is error */
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
}
/* Read until EOI */
while (! cinfo->inputctl->eoi_reached) {
if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
return FALSE; /* Suspend, come back later */
}
/* Do final cleanup */
(*cinfo->src->term_source) (cinfo);
/* We can use jpeg_abort to release memory and reset global_state */
jpeg_abort((j_common_ptr) cinfo);
return TRUE;
}

View File

@@ -0,0 +1,275 @@
/*
* jdapistd.c
*
* Copyright (C) 1994-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains application interface code for the decompression half
* of the JPEG library. These are the "standard" API routines that are
* used in the normal full-decompression case. They are not used by a
* transcoding-only application. Note that if an application links in
* jpeg_start_decompress, it will end up linking in the entire decompressor.
* We thus must separate this file from jdapimin.c to avoid linking the
* whole decompression library into a transcoder.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* Forward declarations */
LOCAL boolean output_pass_setup JPP((j_decompress_ptr cinfo));
/*
* Decompression initialization.
* jpeg_read_header must be completed before calling this.
*
* If a multipass operating mode was selected, this will do all but the
* last pass, and thus may take a great deal of time.
*
* Returns FALSE if suspended. The return value need be inspected only if
* a suspending data source is used.
*/
GLOBAL boolean
jpeg_start_decompress (j_decompress_ptr cinfo)
{
if (cinfo->global_state == DSTATE_READY) {
/* First call: initialize master control, select active modules */
jinit_master_decompress(cinfo);
if (cinfo->buffered_image) {
/* No more work here; expecting jpeg_start_output next */
cinfo->global_state = DSTATE_BUFIMAGE;
return TRUE;
}
cinfo->global_state = DSTATE_PRELOAD;
}
if (cinfo->global_state == DSTATE_PRELOAD) {
/* If file has multiple scans, absorb them all into the coef buffer */
if (cinfo->inputctl->has_multiple_scans) {
#ifdef D_MULTISCAN_FILES_SUPPORTED
for (;;) {
int retcode;
/* Call progress monitor hook if present */
if (cinfo->progress != NULL)
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
/* Absorb some more input */
retcode = (*cinfo->inputctl->consume_input) (cinfo);
if (retcode == JPEG_SUSPENDED)
return FALSE;
if (retcode == JPEG_REACHED_EOI)
break;
/* Advance progress counter if appropriate */
if (cinfo->progress != NULL &&
(retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
/* jdmaster underestimated number of scans; ratchet up one scan */
cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
}
}
}
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif /* D_MULTISCAN_FILES_SUPPORTED */
}
cinfo->output_scan_number = cinfo->input_scan_number;
} else if (cinfo->global_state != DSTATE_PRESCAN)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
/* Perform any dummy output passes, and set up for the final pass */
return output_pass_setup(cinfo);
}
/*
* Set up for an output pass, and perform any dummy pass(es) needed.
* Common subroutine for jpeg_start_decompress and jpeg_start_output.
* Entry: global_state = DSTATE_PRESCAN only if previously suspended.
* Exit: If done, returns TRUE and sets global_state for proper output mode.
* If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN.
*/
LOCAL boolean
output_pass_setup (j_decompress_ptr cinfo)
{
if (cinfo->global_state != DSTATE_PRESCAN) {
/* First call: do pass setup */
(*cinfo->master->prepare_for_output_pass) (cinfo);
cinfo->output_scanline = 0;
cinfo->global_state = DSTATE_PRESCAN;
}
/* Loop over any required dummy passes */
while (cinfo->master->is_dummy_pass) {
#ifdef QUANT_2PASS_SUPPORTED
/* Crank through the dummy pass */
while (cinfo->output_scanline < cinfo->output_height) {
JDIMENSION last_scanline;
/* Call progress monitor hook if present */
if (cinfo->progress != NULL) {
cinfo->progress->pass_counter = (long) cinfo->output_scanline;
cinfo->progress->pass_limit = (long) cinfo->output_height;
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
}
/* Process some data */
last_scanline = cinfo->output_scanline;
(*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL,
&cinfo->output_scanline, (JDIMENSION) 0);
if (cinfo->output_scanline == last_scanline)
return FALSE; /* No progress made, must suspend */
}
/* Finish up dummy pass, and set up for another one */
(*cinfo->master->finish_output_pass) (cinfo);
(*cinfo->master->prepare_for_output_pass) (cinfo);
cinfo->output_scanline = 0;
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif /* QUANT_2PASS_SUPPORTED */
}
/* Ready for application to drive output pass through
* jpeg_read_scanlines or jpeg_read_raw_data.
*/
cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
return TRUE;
}
/*
* Read some scanlines of data from the JPEG decompressor.
*
* The return value will be the number of lines actually read.
* This may be less than the number requested in several cases,
* including bottom of image, data source suspension, and operating
* modes that emit multiple scanlines at a time.
*
* Note: we warn about excess calls to jpeg_read_scanlines() since
* this likely signals an application programmer error. However,
* an oversize buffer (max_lines > scanlines remaining) is not an error.
*/
GLOBAL JDIMENSION
jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
JDIMENSION max_lines)
{
JDIMENSION row_ctr;
if (cinfo->global_state != DSTATE_SCANNING)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->output_scanline >= cinfo->output_height) {
WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
return 0;
}
/* Call progress monitor hook if present */
if (cinfo->progress != NULL) {
cinfo->progress->pass_counter = (long) cinfo->output_scanline;
cinfo->progress->pass_limit = (long) cinfo->output_height;
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
}
/* Process some data */
row_ctr = 0;
(*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines);
cinfo->output_scanline += row_ctr;
return row_ctr;
}
/*
* Alternate entry point to read raw data.
* Processes exactly one iMCU row per call, unless suspended.
*/
GLOBAL JDIMENSION
jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
JDIMENSION max_lines)
{
JDIMENSION lines_per_iMCU_row;
if (cinfo->global_state != DSTATE_RAW_OK)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->output_scanline >= cinfo->output_height) {
WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
return 0;
}
/* Call progress monitor hook if present */
if (cinfo->progress != NULL) {
cinfo->progress->pass_counter = (long) cinfo->output_scanline;
cinfo->progress->pass_limit = (long) cinfo->output_height;
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
}
/* Verify that at least one iMCU row can be returned. */
lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size;
if (max_lines < lines_per_iMCU_row)
ERREXIT(cinfo, JERR_BUFFER_SIZE);
/* Decompress directly into user's buffer. */
if (! (*cinfo->coef->decompress_data) (cinfo, data))
return 0; /* suspension forced, can do nothing more */
/* OK, we processed one iMCU row. */
cinfo->output_scanline += lines_per_iMCU_row;
return lines_per_iMCU_row;
}
/* Additional entry points for buffered-image mode. */
#ifdef D_MULTISCAN_FILES_SUPPORTED
/*
* Initialize for an output pass in buffered-image mode.
*/
GLOBAL boolean
jpeg_start_output (j_decompress_ptr cinfo, int scan_number)
{
if (cinfo->global_state != DSTATE_BUFIMAGE &&
cinfo->global_state != DSTATE_PRESCAN)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
/* Limit scan number to valid range */
if (scan_number <= 0)
scan_number = 1;
if (cinfo->inputctl->eoi_reached &&
scan_number > cinfo->input_scan_number)
scan_number = cinfo->input_scan_number;
cinfo->output_scan_number = scan_number;
/* Perform any dummy output passes, and set up for the real pass */
return output_pass_setup(cinfo);
}
/*
* Finish up after an output pass in buffered-image mode.
*
* Returns FALSE if suspended. The return value need be inspected only if
* a suspending data source is used.
*/
GLOBAL boolean
jpeg_finish_output (j_decompress_ptr cinfo)
{
if ((cinfo->global_state == DSTATE_SCANNING ||
cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) {
/* Terminate this pass. */
/* We do not require the whole pass to have been completed. */
(*cinfo->master->finish_output_pass) (cinfo);
cinfo->global_state = DSTATE_BUFPOST;
} else if (cinfo->global_state != DSTATE_BUFPOST) {
/* BUFPOST = repeat call after a suspension, anything else is error */
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
}
/* Read markers looking for SOS or EOI */
while (cinfo->input_scan_number <= cinfo->output_scan_number &&
! cinfo->inputctl->eoi_reached) {
if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
return FALSE; /* Suspend, come back later */
}
cinfo->global_state = DSTATE_BUFIMAGE;
return TRUE;
}
#endif /* D_MULTISCAN_FILES_SUPPORTED */

View File

@@ -0,0 +1,205 @@
/*
* jdatasrc.c
*
* Copyright (C) 1994, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains decompression data source routines for the case of
* reading JPEG data from a file (or any stdio stream). While these routines
* are sufficient for most applications, some will want to use a different
* source manager.
* IMPORTANT: we assume that fread() will correctly transcribe an array of
* JOCTETs from 8-bit-wide elements on external storage. If char is wider
* than 8 bits on your machine, you may need to do some tweaking.
*/
/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
#include "jinclude.h"
#include "jpeglib.h"
#include "jerror.h"
/* Expanded data source object for stdio input */
typedef struct {
struct jpeg_source_mgr pub; /* public fields */
unsigned char *infile; /* source stream */
JOCTET * buffer; /* start of buffer */
boolean start_of_file; /* have we gotten any data yet? */
} my_source_mgr;
typedef my_source_mgr * my_src_ptr;
// do a search on this if you change it, to catch the one in the file load/alloc code(which can't see this H file)
#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
/*
* Initialize source --- called by jpeg_read_header
* before any data is actually read.
*/
METHODDEF void
init_source (j_decompress_ptr cinfo)
{
my_src_ptr src = (my_src_ptr) cinfo->src;
/* We reset the empty-input-file flag for each image,
* but we don't clear the input buffer.
* This is correct behavior for reading a series of images from one source.
*/
src->start_of_file = TRUE;
}
/*
* Fill the input buffer --- called whenever buffer is emptied.
*
* In typical applications, this should read fresh data into the buffer
* (ignoring the current state of next_input_byte & bytes_in_buffer),
* reset the pointer & count to the start of the buffer, and return TRUE
* indicating that the buffer has been reloaded. It is not necessary to
* fill the buffer entirely, only to obtain at least one more byte.
*
* There is no such thing as an EOF return. If the end of the file has been
* reached, the routine has a choice of ERREXIT() or inserting fake data into
* the buffer. In most cases, generating a warning message and inserting a
* fake EOI marker is the best course of action --- this will allow the
* decompressor to output however much of the image is there. However,
* the resulting error message is misleading if the real problem is an empty
* input file, so we handle that case specially.
*
* In applications that need to be able to suspend compression due to input
* not being available yet, a FALSE return indicates that no more data can be
* obtained right now, but more may be forthcoming later. In this situation,
* the decompressor will return to its caller (with an indication of the
* number of scanlines it has read, if any). The application should resume
* decompression after it has loaded more data into the input buffer. Note
* that there are substantial restrictions on the use of suspension --- see
* the documentation.
*
* When suspending, the decompressor will back up to a convenient restart point
* (typically the start of the current MCU). next_input_byte & bytes_in_buffer
* indicate where the restart point will be if the current call returns FALSE.
* Data beyond this point must be rescanned after resumption, so move it to
* the front of the buffer rather than discarding it.
*/
METHODDEF boolean
fill_input_buffer (j_decompress_ptr cinfo)
{
my_src_ptr src = (my_src_ptr) cinfo->src;
memcpy( src->buffer, src->infile, INPUT_BUF_SIZE );
src->infile += INPUT_BUF_SIZE;
src->pub.next_input_byte = src->buffer;
src->pub.bytes_in_buffer = INPUT_BUF_SIZE;
src->start_of_file = FALSE;
return TRUE;
}
/*
* Skip data --- used to skip over a potentially large amount of
* uninteresting data (such as an APPn marker).
*
* Writers of suspendable-input applications must note that skip_input_data
* is not granted the right to give a suspension return. If the skip extends
* beyond the data currently in the buffer, the buffer can be marked empty so
* that the next read will cause a fill_input_buffer call that can suspend.
* Arranging for additional bytes to be discarded before reloading the input
* buffer is the application writer's problem.
*/
METHODDEF void
skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
my_src_ptr src = (my_src_ptr) cinfo->src;
/* Just a dumb implementation for now. Could use fseek() except
* it doesn't work on pipes. Not clear that being smart is worth
* any trouble anyway --- large skips are infrequent.
*/
if (num_bytes > 0) {
while (num_bytes > (long) src->pub.bytes_in_buffer) {
num_bytes -= (long) src->pub.bytes_in_buffer;
(void) fill_input_buffer(cinfo);
/* note we assume that fill_input_buffer will never return FALSE,
* so suspension need not be handled.
*/
}
src->pub.next_input_byte += (size_t) num_bytes;
src->pub.bytes_in_buffer -= (size_t) num_bytes;
}
}
/*
* An additional method that can be provided by data source modules is the
* resync_to_restart method for error recovery in the presence of RST markers.
* For the moment, this source module just uses the default resync method
* provided by the JPEG library. That method assumes that no backtracking
* is possible.
*/
/*
* Terminate source --- called by jpeg_finish_decompress
* after all data has been read. Often a no-op.
*
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
* application must deal with any cleanup that should happen even
* for error exit.
*/
METHODDEF void
term_source (j_decompress_ptr cinfo)
{
/* no work necessary here */
}
/*
* Prepare for input from a stdio stream.
* The caller must have already opened the stream, and is responsible
* for closing it after finishing decompression.
*/
GLOBAL void
jpeg_stdio_src (j_decompress_ptr cinfo, unsigned char *infile)
{
my_src_ptr src;
/* The source object and input buffer are made permanent so that a series
* of JPEG images can be read from the same file by calling jpeg_stdio_src
* only before the first one. (If we discarded the buffer at the end of
* one image, we'd likely lose the start of the next one.)
* This makes it unsafe to use this manager and a different source
* manager serially with the same JPEG object. Caveat programmer.
*/
if (cinfo->src == NULL) { /* first time for this JPEG object? */
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(my_source_mgr));
src = (my_src_ptr) cinfo->src;
src->buffer = (JOCTET *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
INPUT_BUF_SIZE * SIZEOF(JOCTET));
}
src = (my_src_ptr) cinfo->src;
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_input_buffer;
src->pub.skip_input_data = skip_input_data;
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->pub.term_source = term_source;
src->infile = infile;
src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
src->pub.next_input_byte = NULL; /* until buffer loaded */
}

View File

@@ -0,0 +1,725 @@
/*
* jdcoefct.c
*
* Copyright (C) 1994-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains the coefficient buffer controller for decompression.
* This controller is the top level of the JPEG decompressor proper.
* The coefficient buffer lies between entropy decoding and inverse-DCT steps.
*
* In buffered-image mode, this controller is the interface between
* input-oriented processing and output-oriented processing.
* Also, the input side (only) is used when reading a file for transcoding.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* Block smoothing is only applicable for progressive JPEG, so: */
#ifndef D_PROGRESSIVE_SUPPORTED
#undef BLOCK_SMOOTHING_SUPPORTED
#endif
/* Private buffer controller object */
typedef struct {
struct jpeg_d_coef_controller pub; /* public fields */
/* These variables keep track of the current location of the input side. */
/* cinfo->input_iMCU_row is also used for this. */
JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
int MCU_vert_offset; /* counts MCU rows within iMCU row */
int MCU_rows_per_iMCU_row; /* number of such rows needed */
/* The output side's location is represented by cinfo->output_iMCU_row. */
/* In single-pass modes, it's sufficient to buffer just one MCU.
* We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
* and let the entropy decoder write into that workspace each time.
* (On 80x86, the workspace is FAR even though it's not really very big;
* this is to keep the module interfaces unchanged when a large coefficient
* buffer is necessary.)
* In multi-pass modes, this array points to the current MCU's blocks
* within the virtual arrays; it is used only by the input side.
*/
JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
#ifdef D_MULTISCAN_FILES_SUPPORTED
/* In multi-pass modes, we need a virtual block array for each component. */
jvirt_barray_ptr whole_image[MAX_COMPONENTS];
#endif
#ifdef BLOCK_SMOOTHING_SUPPORTED
/* When doing block smoothing, we latch coefficient Al values here */
int * coef_bits_latch;
#define SAVED_COEFS 6 /* we save coef_bits[0..5] */
#endif
} my_coef_controller;
typedef my_coef_controller * my_coef_ptr;
/* Forward declarations */
METHODDEF int decompress_onepass
JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
#ifdef D_MULTISCAN_FILES_SUPPORTED
METHODDEF int decompress_data
JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
#endif
#ifdef BLOCK_SMOOTHING_SUPPORTED
LOCAL boolean smoothing_ok JPP((j_decompress_ptr cinfo));
METHODDEF int decompress_smooth_data
JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
#endif
LOCAL void
start_iMCU_row (j_decompress_ptr cinfo)
/* Reset within-iMCU-row counters for a new row (input side) */
{
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
/* In an interleaved scan, an MCU row is the same as an iMCU row.
* In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
* But at the bottom of the image, process only what's left.
*/
if (cinfo->comps_in_scan > 1) {
coef->MCU_rows_per_iMCU_row = 1;
} else {
if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
else
coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
}
coef->MCU_ctr = 0;
coef->MCU_vert_offset = 0;
}
/*
* Initialize for an input processing pass.
*/
METHODDEF void
start_input_pass (j_decompress_ptr cinfo)
{
cinfo->input_iMCU_row = 0;
start_iMCU_row(cinfo);
}
/*
* Initialize for an output processing pass.
*/
METHODDEF void
start_output_pass (j_decompress_ptr cinfo)
{
#ifdef BLOCK_SMOOTHING_SUPPORTED
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
/* If multipass, check to see whether to use block smoothing on this pass */
if (coef->pub.coef_arrays != NULL) {
if (cinfo->do_block_smoothing && smoothing_ok(cinfo))
coef->pub.decompress_data = decompress_smooth_data;
else
coef->pub.decompress_data = decompress_data;
}
#endif
cinfo->output_iMCU_row = 0;
}
/*
* Decompress and return some data in the single-pass case.
* Always attempts to emit one fully interleaved MCU row ("iMCU" row).
* Input and output must run in lockstep since we have only a one-MCU buffer.
* Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
*
* NB: output_buf contains a plane for each component in image.
* For single pass, this is the same as the components in the scan.
*/
METHODDEF int
decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
{
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
JDIMENSION MCU_col_num; /* index of current MCU within row */
JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
int blkn, ci, xindex, yindex, yoffset, useful_width;
JSAMPARRAY output_ptr;
JDIMENSION start_col, output_col;
jpeg_component_info *compptr;
inverse_DCT_method_ptr inverse_DCT;
/* Loop to process as much as one whole iMCU row */
for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
yoffset++) {
for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col;
MCU_col_num++) {
/* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */
jzero_far((void FAR *) coef->MCU_buffer[0],
(size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK)));
if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
/* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset;
coef->MCU_ctr = MCU_col_num;
return JPEG_SUSPENDED;
}
/* Determine where data should go in output_buf and do the IDCT thing.
* We skip dummy blocks at the right and bottom edges (but blkn gets
* incremented past them!). Note the inner loop relies on having
* allocated the MCU_buffer[] blocks sequentially.
*/
blkn = 0; /* index of current DCT block within MCU */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* Don't bother to IDCT an uninteresting component. */
if (! compptr->component_needed) {
blkn += compptr->MCU_blocks;
continue;
}
inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
: compptr->last_col_width;
output_ptr = output_buf[ci] + yoffset * compptr->DCT_scaled_size;
start_col = MCU_col_num * compptr->MCU_sample_width;
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (cinfo->input_iMCU_row < last_iMCU_row ||
yoffset+yindex < compptr->last_row_height) {
output_col = start_col;
for (xindex = 0; xindex < useful_width; xindex++) {
(*inverse_DCT) (cinfo, compptr,
(JCOEFPTR) coef->MCU_buffer[blkn+xindex],
output_ptr, output_col);
output_col += compptr->DCT_scaled_size;
}
}
blkn += compptr->MCU_width;
output_ptr += compptr->DCT_scaled_size;
}
}
}
/* Completed an MCU row, but perhaps not an iMCU row */
coef->MCU_ctr = 0;
}
/* Completed the iMCU row, advance counters for next one */
cinfo->output_iMCU_row++;
if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
start_iMCU_row(cinfo);
return JPEG_ROW_COMPLETED;
}
/* Completed the scan */
(*cinfo->inputctl->finish_input_pass) (cinfo);
return JPEG_SCAN_COMPLETED;
}
/*
* Dummy consume-input routine for single-pass operation.
*/
METHODDEF int
dummy_consume_data (j_decompress_ptr cinfo)
{
return JPEG_SUSPENDED; /* Always indicate nothing was done */
}
#ifdef D_MULTISCAN_FILES_SUPPORTED
/*
* Consume input data and store it in the full-image coefficient buffer.
* We read as much as one fully interleaved MCU row ("iMCU" row) per call,
* ie, v_samp_factor block rows for each component in the scan.
* Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
*/
METHODDEF int
consume_data (j_decompress_ptr cinfo)
{
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
JDIMENSION MCU_col_num; /* index of current MCU within row */
int blkn, ci, xindex, yindex, yoffset;
JDIMENSION start_col;
JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
JBLOCKROW buffer_ptr;
jpeg_component_info *compptr;
/* Align the virtual buffers for the components used in this scan. */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
buffer[ci] = (*cinfo->mem->access_virt_barray)
((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
cinfo->input_iMCU_row * compptr->v_samp_factor,
(JDIMENSION) compptr->v_samp_factor, TRUE);
/* Note: entropy decoder expects buffer to be zeroed,
* but this is handled automatically by the memory manager
* because we requested a pre-zeroed array.
*/
}
/* Loop to process one whole iMCU row */
for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
yoffset++) {
for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;
MCU_col_num++) {
/* Construct list of pointers to DCT blocks belonging to this MCU */
blkn = 0; /* index of current DCT block within MCU */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
start_col = MCU_col_num * compptr->MCU_width;
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
coef->MCU_buffer[blkn++] = buffer_ptr++;
}
}
}
/* Try to fetch the MCU. */
if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
/* Suspension forced; update state counters and exit */
coef->MCU_vert_offset = yoffset;
coef->MCU_ctr = MCU_col_num;
return JPEG_SUSPENDED;
}
}
/* Completed an MCU row, but perhaps not an iMCU row */
coef->MCU_ctr = 0;
}
/* Completed the iMCU row, advance counters for next one */
if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
start_iMCU_row(cinfo);
return JPEG_ROW_COMPLETED;
}
/* Completed the scan */
(*cinfo->inputctl->finish_input_pass) (cinfo);
return JPEG_SCAN_COMPLETED;
}
/*
* Decompress and return some data in the multi-pass case.
* Always attempts to emit one fully interleaved MCU row ("iMCU" row).
* Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
*
* NB: output_buf contains a plane for each component in image.
*/
METHODDEF int
decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
{
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
JDIMENSION block_num;
int ci, block_row, block_rows;
JBLOCKARRAY buffer;
JBLOCKROW buffer_ptr;
JSAMPARRAY output_ptr;
JDIMENSION output_col;
jpeg_component_info *compptr;
inverse_DCT_method_ptr inverse_DCT;
/* Force some input to be done if we are getting ahead of the input. */
while (cinfo->input_scan_number < cinfo->output_scan_number ||
(cinfo->input_scan_number == cinfo->output_scan_number &&
cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) {
if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
return JPEG_SUSPENDED;
}
/* OK, output from the virtual arrays. */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Don't bother to IDCT an uninteresting component. */
if (! compptr->component_needed)
continue;
/* Align the virtual buffer for this component. */
buffer = (*cinfo->mem->access_virt_barray)
((j_common_ptr) cinfo, coef->whole_image[ci],
cinfo->output_iMCU_row * compptr->v_samp_factor,
(JDIMENSION) compptr->v_samp_factor, FALSE);
/* Count non-dummy DCT block rows in this iMCU row. */
if (cinfo->output_iMCU_row < last_iMCU_row)
block_rows = compptr->v_samp_factor;
else {
/* NB: can't use last_row_height here; it is input-side-dependent! */
block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (block_rows == 0) block_rows = compptr->v_samp_factor;
}
inverse_DCT = cinfo->idct->inverse_DCT[ci];
output_ptr = output_buf[ci];
/* Loop over all DCT blocks to be processed. */
for (block_row = 0; block_row < block_rows; block_row++) {
buffer_ptr = buffer[block_row];
output_col = 0;
for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {
(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
output_ptr, output_col);
buffer_ptr++;
output_col += compptr->DCT_scaled_size;
}
output_ptr += compptr->DCT_scaled_size;
}
}
if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
return JPEG_ROW_COMPLETED;
return JPEG_SCAN_COMPLETED;
}
#endif /* D_MULTISCAN_FILES_SUPPORTED */
#ifdef BLOCK_SMOOTHING_SUPPORTED
/*
* This code applies interblock smoothing as described by section K.8
* of the JPEG standard: the first 5 AC coefficients are estimated from
* the DC values of a DCT block and its 8 neighboring blocks.
* We apply smoothing only for progressive JPEG decoding, and only if
* the coefficients it can estimate are not yet known to full precision.
*/
/*
* Determine whether block smoothing is applicable and safe.
* We also latch the current states of the coef_bits[] entries for the
* AC coefficients; otherwise, if the input side of the decompressor
* advances into a new scan, we might think the coefficients are known
* more accurately than they really are.
*/
LOCAL boolean
smoothing_ok (j_decompress_ptr cinfo)
{
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
boolean smoothing_useful = FALSE;
int ci, coefi;
jpeg_component_info *compptr;
JQUANT_TBL * qtable;
int * coef_bits;
int * coef_bits_latch;
if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)
return FALSE;
/* Allocate latch area if not already done */
if (coef->coef_bits_latch == NULL)
coef->coef_bits_latch = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
cinfo->num_components *
(SAVED_COEFS * SIZEOF(int)));
coef_bits_latch = coef->coef_bits_latch;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* All components' quantization values must already be latched. */
if ((qtable = compptr->quant_table) == NULL)
return FALSE;
/* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */
for (coefi = 0; coefi <= 5; coefi++) {
if (qtable->quantval[coefi] == 0)
return FALSE;
}
/* DC values must be at least partly known for all components. */
coef_bits = cinfo->coef_bits[ci];
if (coef_bits[0] < 0)
return FALSE;
/* Block smoothing is helpful if some AC coefficients remain inaccurate. */
for (coefi = 1; coefi <= 5; coefi++) {
coef_bits_latch[coefi] = coef_bits[coefi];
if (coef_bits[coefi] != 0)
smoothing_useful = TRUE;
}
coef_bits_latch += SAVED_COEFS;
}
return smoothing_useful;
}
/*
* Variant of decompress_data for use when doing block smoothing.
*/
METHODDEF int
decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
{
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
JDIMENSION block_num, last_block_column;
int ci, block_row, block_rows, access_rows;
JBLOCKARRAY buffer;
JBLOCKROW buffer_ptr, prev_block_row, next_block_row;
JSAMPARRAY output_ptr;
JDIMENSION output_col;
jpeg_component_info *compptr;
inverse_DCT_method_ptr inverse_DCT;
boolean first_row, last_row;
JBLOCK workspace;
int *coef_bits;
JQUANT_TBL *quanttbl;
INT32 Q00,Q01,Q02,Q10,Q11,Q20, num;
int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;
int Al, pred;
/* Force some input to be done if we are getting ahead of the input. */
while (cinfo->input_scan_number <= cinfo->output_scan_number &&
! cinfo->inputctl->eoi_reached) {
if (cinfo->input_scan_number == cinfo->output_scan_number) {
/* If input is working on current scan, we ordinarily want it to
* have completed the current row. But if input scan is DC,
* we want it to keep one row ahead so that next block row's DC
* values are up to date.
*/
JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0;
if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta)
break;
}
if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
return JPEG_SUSPENDED;
}
/* OK, output from the virtual arrays. */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Don't bother to IDCT an uninteresting component. */
if (! compptr->component_needed)
continue;
/* Count non-dummy DCT block rows in this iMCU row. */
if (cinfo->output_iMCU_row < last_iMCU_row) {
block_rows = compptr->v_samp_factor;
access_rows = block_rows * 2; /* this and next iMCU row */
last_row = FALSE;
} else {
/* NB: can't use last_row_height here; it is input-side-dependent! */
block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (block_rows == 0) block_rows = compptr->v_samp_factor;
access_rows = block_rows; /* this iMCU row only */
last_row = TRUE;
}
/* Align the virtual buffer for this component. */
if (cinfo->output_iMCU_row > 0) {
access_rows += compptr->v_samp_factor; /* prior iMCU row too */
buffer = (*cinfo->mem->access_virt_barray)
((j_common_ptr) cinfo, coef->whole_image[ci],
(cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,
(JDIMENSION) access_rows, FALSE);
buffer += compptr->v_samp_factor; /* point to current iMCU row */
first_row = FALSE;
} else {
buffer = (*cinfo->mem->access_virt_barray)
((j_common_ptr) cinfo, coef->whole_image[ci],
(JDIMENSION) 0, (JDIMENSION) access_rows, FALSE);
first_row = TRUE;
}
/* Fetch component-dependent info */
coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS);
quanttbl = compptr->quant_table;
Q00 = quanttbl->quantval[0];
Q01 = quanttbl->quantval[1];
Q10 = quanttbl->quantval[2];
Q20 = quanttbl->quantval[3];
Q11 = quanttbl->quantval[4];
Q02 = quanttbl->quantval[5];
inverse_DCT = cinfo->idct->inverse_DCT[ci];
output_ptr = output_buf[ci];
/* Loop over all DCT blocks to be processed. */
for (block_row = 0; block_row < block_rows; block_row++) {
buffer_ptr = buffer[block_row];
if (first_row && block_row == 0)
prev_block_row = buffer_ptr;
else
prev_block_row = buffer[block_row-1];
if (last_row && block_row == block_rows-1)
next_block_row = buffer_ptr;
else
next_block_row = buffer[block_row+1];
/* We fetch the surrounding DC values using a sliding-register approach.
* Initialize all nine here so as to do the right thing on narrow pics.
*/
DC1 = DC2 = DC3 = (int) prev_block_row[0][0];
DC4 = DC5 = DC6 = (int) buffer_ptr[0][0];
DC7 = DC8 = DC9 = (int) next_block_row[0][0];
output_col = 0;
last_block_column = compptr->width_in_blocks - 1;
for (block_num = 0; block_num <= last_block_column; block_num++) {
/* Fetch current DCT block into workspace so we can modify it. */
jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);
/* Update DC values */
if (block_num < last_block_column) {
DC3 = (int) prev_block_row[1][0];
DC6 = (int) buffer_ptr[1][0];
DC9 = (int) next_block_row[1][0];
}
/* Compute coefficient estimates per K.8.
* An estimate is applied only if coefficient is still zero,
* and is not known to be fully accurate.
*/
/* AC01 */
if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) {
num = 36 * Q00 * (DC4 - DC6);
if (num >= 0) {
pred = (int) (((Q01<<7) + num) / (Q01<<8));
if (Al > 0 && pred >= (1<<Al))
pred = (1<<Al)-1;
} else {
pred = (int) (((Q01<<7) - num) / (Q01<<8));
if (Al > 0 && pred >= (1<<Al))
pred = (1<<Al)-1;
pred = -pred;
}
workspace[1] = (JCOEF) pred;
}
/* AC10 */
if ((Al=coef_bits[2]) != 0 && workspace[8] == 0) {
num = 36 * Q00 * (DC2 - DC8);
if (num >= 0) {
pred = (int) (((Q10<<7) + num) / (Q10<<8));
if (Al > 0 && pred >= (1<<Al))
pred = (1<<Al)-1;
} else {
pred = (int) (((Q10<<7) - num) / (Q10<<8));
if (Al > 0 && pred >= (1<<Al))
pred = (1<<Al)-1;
pred = -pred;
}
workspace[8] = (JCOEF) pred;
}
/* AC20 */
if ((Al=coef_bits[3]) != 0 && workspace[16] == 0) {
num = 9 * Q00 * (DC2 + DC8 - 2*DC5);
if (num >= 0) {
pred = (int) (((Q20<<7) + num) / (Q20<<8));
if (Al > 0 && pred >= (1<<Al))
pred = (1<<Al)-1;
} else {
pred = (int) (((Q20<<7) - num) / (Q20<<8));
if (Al > 0 && pred >= (1<<Al))
pred = (1<<Al)-1;
pred = -pred;
}
workspace[16] = (JCOEF) pred;
}
/* AC11 */
if ((Al=coef_bits[4]) != 0 && workspace[9] == 0) {
num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9);
if (num >= 0) {
pred = (int) (((Q11<<7) + num) / (Q11<<8));
if (Al > 0 && pred >= (1<<Al))
pred = (1<<Al)-1;
} else {
pred = (int) (((Q11<<7) - num) / (Q11<<8));
if (Al > 0 && pred >= (1<<Al))
pred = (1<<Al)-1;
pred = -pred;
}
workspace[9] = (JCOEF) pred;
}
/* AC02 */
if ((Al=coef_bits[5]) != 0 && workspace[2] == 0) {
num = 9 * Q00 * (DC4 + DC6 - 2*DC5);
if (num >= 0) {
pred = (int) (((Q02<<7) + num) / (Q02<<8));
if (Al > 0 && pred >= (1<<Al))
pred = (1<<Al)-1;
} else {
pred = (int) (((Q02<<7) - num) / (Q02<<8));
if (Al > 0 && pred >= (1<<Al))
pred = (1<<Al)-1;
pred = -pred;
}
workspace[2] = (JCOEF) pred;
}
/* OK, do the IDCT */
(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) workspace,
output_ptr, output_col);
/* Advance for next column */
DC1 = DC2; DC2 = DC3;
DC4 = DC5; DC5 = DC6;
DC7 = DC8; DC8 = DC9;
buffer_ptr++, prev_block_row++, next_block_row++;
output_col += compptr->DCT_scaled_size;
}
output_ptr += compptr->DCT_scaled_size;
}
}
if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
return JPEG_ROW_COMPLETED;
return JPEG_SCAN_COMPLETED;
}
#endif /* BLOCK_SMOOTHING_SUPPORTED */
/*
* Initialize coefficient buffer controller.
*/
GLOBAL void
jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
{
my_coef_ptr coef;
coef = (my_coef_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_coef_controller));
cinfo->coef = (struct jpeg_d_coef_controller *) coef;
coef->pub.start_input_pass = start_input_pass;
coef->pub.start_output_pass = start_output_pass;
#ifdef BLOCK_SMOOTHING_SUPPORTED
coef->coef_bits_latch = NULL;
#endif
/* Create the coefficient buffer. */
if (need_full_buffer) {
#ifdef D_MULTISCAN_FILES_SUPPORTED
/* Allocate a full-image virtual array for each component, */
/* padded to a multiple of samp_factor DCT blocks in each direction. */
/* Note we ask for a pre-zeroed array. */
int ci, access_rows;
jpeg_component_info *compptr;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
access_rows = compptr->v_samp_factor;
#ifdef BLOCK_SMOOTHING_SUPPORTED
/* If block smoothing could be used, need a bigger window */
if (cinfo->progressive_mode)
access_rows *= 3;
#endif
coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE,
(JDIMENSION) jround_up((long) compptr->width_in_blocks,
(long) compptr->h_samp_factor),
(JDIMENSION) jround_up((long) compptr->height_in_blocks,
(long) compptr->v_samp_factor),
(JDIMENSION) access_rows);
}
coef->pub.consume_data = consume_data;
coef->pub.decompress_data = decompress_data;
coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
/* We only need a single-MCU buffer. */
JBLOCKROW buffer;
int i;
buffer = (JBLOCKROW)
(*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) {
coef->MCU_buffer[i] = buffer + i;
}
coef->pub.consume_data = dummy_consume_data;
coef->pub.decompress_data = decompress_onepass;
coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */
}
}

View File

@@ -0,0 +1,367 @@
/*
* jdcolor.c
*
* Copyright (C) 1991-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains output colorspace conversion routines.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* Private subobject */
typedef struct {
struct jpeg_color_deconverter pub; /* public fields */
/* Private state for YCC->RGB conversion */
int * Cr_r_tab; /* => table for Cr to R conversion */
int * Cb_b_tab; /* => table for Cb to B conversion */
INT32 * Cr_g_tab; /* => table for Cr to G conversion */
INT32 * Cb_g_tab; /* => table for Cb to G conversion */
} my_color_deconverter;
typedef my_color_deconverter * my_cconvert_ptr;
/**************** YCbCr -> RGB conversion: most common case **************/
/*
* YCbCr is defined per CCIR 601-1, except that Cb and Cr are
* normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
* The conversion equations to be implemented are therefore
* R = Y + 1.40200 * Cr
* G = Y - 0.34414 * Cb - 0.71414 * Cr
* B = Y + 1.77200 * Cb
* where Cb and Cr represent the incoming values less CENTERJSAMPLE.
* (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
*
* To avoid floating-point arithmetic, we represent the fractional constants
* as integers scaled up by 2^16 (about 4 digits precision); we have to divide
* the products by 2^16, with appropriate rounding, to get the correct answer.
* Notice that Y, being an integral input, does not contribute any fraction
* so it need not participate in the rounding.
*
* For even more speed, we avoid doing any multiplications in the inner loop
* by precalculating the constants times Cb and Cr for all possible values.
* For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
* for 12-bit samples it is still acceptable. It's not very reasonable for
* 16-bit samples, but if you want lossless storage you shouldn't be changing
* colorspace anyway.
* The Cr=>R and Cb=>B values can be rounded to integers in advance; the
* values for the G calculation are left scaled up, since we must add them
* together before rounding.
*/
#define SCALEBITS 16 /* speediest right-shift on some machines */
#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
/*
* Initialize tables for YCC->RGB colorspace conversion.
*/
LOCAL void
build_ycc_rgb_table (j_decompress_ptr cinfo)
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
int i;
INT32 x;
SHIFT_TEMPS
cconvert->Cr_r_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(MAXJSAMPLE+1) * SIZEOF(int));
cconvert->Cb_b_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(MAXJSAMPLE+1) * SIZEOF(int));
cconvert->Cr_g_tab = (INT32 *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(MAXJSAMPLE+1) * SIZEOF(INT32));
cconvert->Cb_g_tab = (INT32 *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(MAXJSAMPLE+1) * SIZEOF(INT32));
for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
/* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
/* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
/* Cr=>R value is nearest int to 1.40200 * x */
cconvert->Cr_r_tab[i] = (int)
RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
/* Cb=>B value is nearest int to 1.77200 * x */
cconvert->Cb_b_tab[i] = (int)
RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);
/* Cr=>G value is scaled-up -0.71414 * x */
cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x;
/* Cb=>G value is scaled-up -0.34414 * x */
/* We also add in ONE_HALF so that need not do it in inner loop */
cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF;
}
}
/*
* Convert some rows of samples to the output colorspace.
*
* Note that we change from noninterleaved, one-plane-per-component format
* to interleaved-pixel format. The output buffer is therefore three times
* as wide as the input buffer.
* A starting row offset is provided only for the input buffer. The caller
* can easily adjust the passed output_buf value to accommodate any row
* offset required on that side.
*/
METHODDEF void
ycc_rgb_convert (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION input_row,
JSAMPARRAY output_buf, int num_rows)
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
register int y, cb, cr;
register JSAMPROW outptr;
register JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
register JSAMPLE * range_limit = cinfo->sample_range_limit;
register int * Crrtab = cconvert->Cr_r_tab;
register int * Cbbtab = cconvert->Cb_b_tab;
register INT32 * Crgtab = cconvert->Cr_g_tab;
register INT32 * Cbgtab = cconvert->Cb_g_tab;
SHIFT_TEMPS
while (--num_rows >= 0) {
inptr0 = input_buf[0][input_row];
inptr1 = input_buf[1][input_row];
inptr2 = input_buf[2][input_row];
input_row++;
outptr = *output_buf++;
for (col = 0; col < num_cols; col++) {
y = GETJSAMPLE(inptr0[col]);
cb = GETJSAMPLE(inptr1[col]);
cr = GETJSAMPLE(inptr2[col]);
/* Range-limiting is essential due to noise introduced by DCT losses. */
outptr[RGB_RED] = range_limit[y + Crrtab[cr]];
outptr[RGB_GREEN] = range_limit[y +
((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
SCALEBITS))];
outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]];
outptr += RGB_PIXELSIZE;
}
}
}
/**************** Cases other than YCbCr -> RGB **************/
/*
* Color conversion for no colorspace change: just copy the data,
* converting from separate-planes to interleaved representation.
*/
METHODDEF void
null_convert (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION input_row,
JSAMPARRAY output_buf, int num_rows)
{
register JSAMPROW inptr, outptr;
register JDIMENSION count;
register int num_components = cinfo->num_components;
JDIMENSION num_cols = cinfo->output_width;
int ci;
while (--num_rows >= 0) {
for (ci = 0; ci < num_components; ci++) {
inptr = input_buf[ci][input_row];
outptr = output_buf[0] + ci;
for (count = num_cols; count > 0; count--) {
*outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */
outptr += num_components;
}
}
input_row++;
output_buf++;
}
}
/*
* Color conversion for grayscale: just copy the data.
* This also works for YCbCr -> grayscale conversion, in which
* we just copy the Y (luminance) component and ignore chrominance.
*/
METHODDEF void
grayscale_convert (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION input_row,
JSAMPARRAY output_buf, int num_rows)
{
jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0,
num_rows, cinfo->output_width);
}
/*
* Adobe-style YCCK->CMYK conversion.
* We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same
* conversion as above, while passing K (black) unchanged.
* We assume build_ycc_rgb_table has been called.
*/
METHODDEF void
ycck_cmyk_convert (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION input_row,
JSAMPARRAY output_buf, int num_rows)
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
register int y, cb, cr;
register JSAMPROW outptr;
register JSAMPROW inptr0, inptr1, inptr2, inptr3;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
register JSAMPLE * range_limit = cinfo->sample_range_limit;
register int * Crrtab = cconvert->Cr_r_tab;
register int * Cbbtab = cconvert->Cb_b_tab;
register INT32 * Crgtab = cconvert->Cr_g_tab;
register INT32 * Cbgtab = cconvert->Cb_g_tab;
SHIFT_TEMPS
while (--num_rows >= 0) {
inptr0 = input_buf[0][input_row];
inptr1 = input_buf[1][input_row];
inptr2 = input_buf[2][input_row];
inptr3 = input_buf[3][input_row];
input_row++;
outptr = *output_buf++;
for (col = 0; col < num_cols; col++) {
y = GETJSAMPLE(inptr0[col]);
cb = GETJSAMPLE(inptr1[col]);
cr = GETJSAMPLE(inptr2[col]);
/* Range-limiting is essential due to noise introduced by DCT losses. */
outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */
outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */
((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
SCALEBITS)))];
outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */
/* K passes through unchanged */
outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */
outptr += 4;
}
}
}
/*
* Empty method for start_pass.
*/
METHODDEF void
start_pass_dcolor (j_decompress_ptr cinfo)
{
/* no work needed */
}
/*
* Module initialization routine for output colorspace conversion.
*/
GLOBAL void
jinit_color_deconverter (j_decompress_ptr cinfo)
{
my_cconvert_ptr cconvert;
int ci;
cconvert = (my_cconvert_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_color_deconverter));
cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert;
cconvert->pub.start_pass = start_pass_dcolor;
/* Make sure num_components agrees with jpeg_color_space */
switch (cinfo->jpeg_color_space) {
case JCS_GRAYSCALE:
if (cinfo->num_components != 1)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
break;
case JCS_RGB:
case JCS_YCbCr:
if (cinfo->num_components != 3)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
break;
case JCS_CMYK:
case JCS_YCCK:
if (cinfo->num_components != 4)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
break;
default: /* JCS_UNKNOWN can be anything */
if (cinfo->num_components < 1)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
break;
}
/* Set out_color_components and conversion method based on requested space.
* Also clear the component_needed flags for any unused components,
* so that earlier pipeline stages can avoid useless computation.
*/
switch (cinfo->out_color_space) {
case JCS_GRAYSCALE:
cinfo->out_color_components = 1;
if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
cinfo->jpeg_color_space == JCS_YCbCr) {
cconvert->pub.color_convert = grayscale_convert;
/* For color->grayscale conversion, only the Y (0) component is needed */
for (ci = 1; ci < cinfo->num_components; ci++)
cinfo->comp_info[ci].component_needed = FALSE;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_RGB:
cinfo->out_color_components = RGB_PIXELSIZE;
if (cinfo->jpeg_color_space == JCS_YCbCr) {
cconvert->pub.color_convert = ycc_rgb_convert;
build_ycc_rgb_table(cinfo);
} else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) {
cconvert->pub.color_convert = null_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_CMYK:
cinfo->out_color_components = 4;
if (cinfo->jpeg_color_space == JCS_YCCK) {
cconvert->pub.color_convert = ycck_cmyk_convert;
build_ycc_rgb_table(cinfo);
} else if (cinfo->jpeg_color_space == JCS_CMYK) {
cconvert->pub.color_convert = null_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
default:
/* Permit null conversion to same output space */
if (cinfo->out_color_space == cinfo->jpeg_color_space) {
cinfo->out_color_components = cinfo->num_components;
cconvert->pub.color_convert = null_convert;
} else /* unsupported non-null conversion */
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
}
if (cinfo->quantize_colors)
cinfo->output_components = 1; /* single colormapped output component */
else
cinfo->output_components = cinfo->out_color_components;
}

176
tools/ModView/jpeg6/jdct.h Normal file
View File

@@ -0,0 +1,176 @@
/*
* jdct.h
*
* Copyright (C) 1994, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This include file contains common declarations for the forward and
* inverse DCT modules. These declarations are private to the DCT managers
* (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms.
* The individual DCT algorithms are kept in separate files to ease
* machine-dependent tuning (e.g., assembly coding).
*/
/*
* A forward DCT routine is given a pointer to a work area of type DCTELEM[];
* the DCT is to be performed in-place in that buffer. Type DCTELEM is int
* for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT
* implementations use an array of type FAST_FLOAT, instead.)
* The DCT inputs are expected to be signed (range +-CENTERJSAMPLE).
* The DCT outputs are returned scaled up by a factor of 8; they therefore
* have a range of +-8K for 8-bit data, +-128K for 12-bit data. This
* convention improves accuracy in integer implementations and saves some
* work in floating-point ones.
* Quantization of the output coefficients is done by jcdctmgr.c.
*/
#if BITS_IN_JSAMPLE == 8
typedef int DCTELEM; /* 16 or 32 bits is fine */
#else
typedef INT32 DCTELEM; /* must have 32 bits */
#endif
typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data));
typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data));
/*
* An inverse DCT routine is given a pointer to the input JBLOCK and a pointer
* to an output sample array. The routine must dequantize the input data as
* well as perform the IDCT; for dequantization, it uses the multiplier table
* pointed to by compptr->dct_table. The output data is to be placed into the
* sample array starting at a specified column. (Any row offset needed will
* be applied to the array pointer before it is passed to the IDCT code.)
* Note that the number of samples emitted by the IDCT routine is
* DCT_scaled_size * DCT_scaled_size.
*/
/* typedef inverse_DCT_method_ptr is declared in jpegint.h */
/*
* Each IDCT routine has its own ideas about the best dct_table element type.
*/
typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */
#if BITS_IN_JSAMPLE == 8
typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */
#else
typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */
#endif
typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
/*
* Each IDCT routine is responsible for range-limiting its results and
* converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could
* be quite far out of range if the input data is corrupt, so a bulletproof
* range-limiting step is required. We use a mask-and-table-lookup method
* to do the combined operations quickly. See the comments with
* prepare_range_limit_table (in jdmaster.c) for more info.
*/
#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE)
#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
/* Short forms of external names for systems with brain-damaged linkers. */
#ifdef NEED_SHORT_EXTERNAL_NAMES
#define jpeg_fdct_islow jFDislow
#define jpeg_fdct_ifast jFDifast
#define jpeg_fdct_float jFDfloat
#define jpeg_idct_islow jRDislow
#define jpeg_idct_ifast jRDifast
#define jpeg_idct_float jRDfloat
#define jpeg_idct_4x4 jRD4x4
#define jpeg_idct_2x2 jRD2x2
#define jpeg_idct_1x1 jRD1x1
#endif /* NEED_SHORT_EXTERNAL_NAMES */
/* Extern declarations for the forward and inverse DCT routines. */
EXTERN void jpeg_fdct_islow JPP((DCTELEM * data));
EXTERN void jpeg_fdct_ifast JPP((DCTELEM * data));
EXTERN void jpeg_fdct_float JPP((FAST_FLOAT * data));
EXTERN void jpeg_idct_islow
JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
EXTERN void jpeg_idct_ifast
JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
EXTERN void jpeg_idct_float
JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
EXTERN void jpeg_idct_4x4
JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
EXTERN void jpeg_idct_2x2
JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
EXTERN void jpeg_idct_1x1
JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
/*
* Macros for handling fixed-point arithmetic; these are used by many
* but not all of the DCT/IDCT modules.
*
* All values are expected to be of type INT32.
* Fractional constants are scaled left by CONST_BITS bits.
* CONST_BITS is defined within each module using these macros,
* and may differ from one module to the next.
*/
#define ONE ((INT32) 1)
#define CONST_SCALE (ONE << CONST_BITS)
/* Convert a positive real constant to an integer scaled by CONST_SCALE.
* Caution: some C compilers fail to reduce "FIX(constant)" at compile time,
* thus causing a lot of useless floating-point operations at run time.
*/
#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5))
/* Descale and correctly round an INT32 value that's scaled by N bits.
* We assume RIGHT_SHIFT rounds towards minus infinity, so adding
* the fudge factor is correct for either sign of X.
*/
#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
* This macro is used only when the two inputs will actually be no more than
* 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
* full 32x32 multiply. This provides a useful speedup on many machines.
* Unfortunately there is no way to specify a 16x16->32 multiply portably
* in C, but some C compilers will do the right thing if you provide the
* correct combination of casts.
*/
#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const)))
#endif
#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */
#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const)))
#endif
#ifndef MULTIPLY16C16 /* default definition */
#define MULTIPLY16C16(var,const) ((var) * (const))
#endif
/* Same except both inputs are variables. */
#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2)))
#endif
#ifndef MULTIPLY16V16 /* default definition */
#define MULTIPLY16V16(var1,var2) ((var1) * (var2))
#endif

View File

@@ -0,0 +1,270 @@
/*
* jddctmgr.c
*
* Copyright (C) 1994-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains the inverse-DCT management logic.
* This code selects a particular IDCT implementation to be used,
* and it performs related housekeeping chores. No code in this file
* is executed per IDCT step, only during output pass setup.
*
* Note that the IDCT routines are responsible for performing coefficient
* dequantization as well as the IDCT proper. This module sets up the
* dequantization multiplier table needed by the IDCT routine.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jdct.h" /* Private declarations for DCT subsystem */
/*
* The decompressor input side (jdinput.c) saves away the appropriate
* quantization table for each component at the start of the first scan
* involving that component. (This is necessary in order to correctly
* decode files that reuse Q-table slots.)
* When we are ready to make an output pass, the saved Q-table is converted
* to a multiplier table that will actually be used by the IDCT routine.
* The multiplier table contents are IDCT-method-dependent. To support
* application changes in IDCT method between scans, we can remake the
* multiplier tables if necessary.
* In buffered-image mode, the first output pass may occur before any data
* has been seen for some components, and thus before their Q-tables have
* been saved away. To handle this case, multiplier tables are preset
* to zeroes; the result of the IDCT will be a neutral gray level.
*/
/* Private subobject for this module */
typedef struct {
struct jpeg_inverse_dct pub; /* public fields */
/* This array contains the IDCT method code that each multiplier table
* is currently set up for, or -1 if it's not yet set up.
* The actual multiplier tables are pointed to by dct_table in the
* per-component comp_info structures.
*/
int cur_method[MAX_COMPONENTS];
} my_idct_controller;
typedef my_idct_controller * my_idct_ptr;
/* Allocated multiplier tables: big enough for any supported variant */
typedef union {
ISLOW_MULT_TYPE islow_array[DCTSIZE2];
#ifdef DCT_IFAST_SUPPORTED
IFAST_MULT_TYPE ifast_array[DCTSIZE2];
#endif
#ifdef DCT_FLOAT_SUPPORTED
FLOAT_MULT_TYPE float_array[DCTSIZE2];
#endif
} multiplier_table;
/* The current scaled-IDCT routines require ISLOW-style multiplier tables,
* so be sure to compile that code if either ISLOW or SCALING is requested.
*/
#ifdef DCT_ISLOW_SUPPORTED
#define PROVIDE_ISLOW_TABLES
#else
#ifdef IDCT_SCALING_SUPPORTED
#define PROVIDE_ISLOW_TABLES
#endif
#endif
/*
* Prepare for an output pass.
* Here we select the proper IDCT routine for each component and build
* a matching multiplier table.
*/
METHODDEF void
start_pass (j_decompress_ptr cinfo)
{
my_idct_ptr idct = (my_idct_ptr) cinfo->idct;
int ci, i;
jpeg_component_info *compptr;
int method = 0;
inverse_DCT_method_ptr method_ptr = NULL;
JQUANT_TBL * qtbl;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Select the proper IDCT routine for this component's scaling */
switch (compptr->DCT_scaled_size) {
#ifdef IDCT_SCALING_SUPPORTED
case 1:
method_ptr = jpeg_idct_1x1;
method = JDCT_ISLOW; /* jidctred uses islow-style table */
break;
case 2:
method_ptr = jpeg_idct_2x2;
method = JDCT_ISLOW; /* jidctred uses islow-style table */
break;
case 4:
method_ptr = jpeg_idct_4x4;
method = JDCT_ISLOW; /* jidctred uses islow-style table */
break;
#endif
case DCTSIZE:
switch (cinfo->dct_method) {
#ifdef DCT_ISLOW_SUPPORTED
case JDCT_ISLOW:
method_ptr = jpeg_idct_islow;
method = JDCT_ISLOW;
break;
#endif
#ifdef DCT_IFAST_SUPPORTED
case JDCT_IFAST:
method_ptr = jpeg_idct_ifast;
method = JDCT_IFAST;
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
method_ptr = jpeg_idct_float;
method = JDCT_FLOAT;
break;
#endif
default:
ERREXIT(cinfo, JERR_NOT_COMPILED);
break;
}
break;
default:
ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->DCT_scaled_size);
break;
}
idct->pub.inverse_DCT[ci] = method_ptr;
/* Create multiplier table from quant table.
* However, we can skip this if the component is uninteresting
* or if we already built the table. Also, if no quant table
* has yet been saved for the component, we leave the
* multiplier table all-zero; we'll be reading zeroes from the
* coefficient controller's buffer anyway.
*/
if (! compptr->component_needed || idct->cur_method[ci] == method)
continue;
qtbl = compptr->quant_table;
if (qtbl == NULL) /* happens if no data yet for component */
continue;
idct->cur_method[ci] = method;
switch (method) {
#ifdef PROVIDE_ISLOW_TABLES
case JDCT_ISLOW:
{
/* For LL&M IDCT method, multipliers are equal to raw quantization
* coefficients, but are stored in natural order as ints.
*/
ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;
for (i = 0; i < DCTSIZE2; i++) {
ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[jpeg_zigzag_order[i]];
}
}
break;
#endif
#ifdef DCT_IFAST_SUPPORTED
case JDCT_IFAST:
{
/* For AA&N IDCT method, multipliers are equal to quantization
* coefficients scaled by scalefactor[row]*scalefactor[col], where
* scalefactor[0] = 1
* scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
* For integer operation, the multiplier table is to be scaled by
* IFAST_SCALE_BITS. The multipliers are stored in natural order.
*/
IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;
#define CONST_BITS 14
static const INT16 aanscales[DCTSIZE2] = {
/* precomputed values scaled up by 14 bits */
16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
};
SHIFT_TEMPS
for (i = 0; i < DCTSIZE2; i++) {
ifmtbl[i] = (IFAST_MULT_TYPE)
DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[jpeg_zigzag_order[i]],
(INT32) aanscales[i]),
CONST_BITS-IFAST_SCALE_BITS);
}
}
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
{
/* For float AA&N IDCT method, multipliers are equal to quantization
* coefficients scaled by scalefactor[row]*scalefactor[col], where
* scalefactor[0] = 1
* scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
* The multipliers are stored in natural order.
*/
FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;
int row, col;
static const double aanscalefactor[DCTSIZE] = {
1.0, 1.387039845, 1.306562965, 1.175875602,
1.0, 0.785694958, 0.541196100, 0.275899379
};
i = 0;
for (row = 0; row < DCTSIZE; row++) {
for (col = 0; col < DCTSIZE; col++) {
fmtbl[i] = (FLOAT_MULT_TYPE)
((double) qtbl->quantval[jpeg_zigzag_order[i]] *
aanscalefactor[row] * aanscalefactor[col]);
i++;
}
}
}
break;
#endif
default:
ERREXIT(cinfo, JERR_NOT_COMPILED);
break;
}
}
}
/*
* Initialize IDCT manager.
*/
GLOBAL void
jinit_inverse_dct (j_decompress_ptr cinfo)
{
my_idct_ptr idct;
int ci;
jpeg_component_info *compptr;
idct = (my_idct_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_idct_controller));
cinfo->idct = (struct jpeg_inverse_dct *) idct;
idct->pub.start_pass = start_pass;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Allocate and pre-zero a multiplier table for each component */
compptr->dct_table =
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(multiplier_table));
MEMZERO(compptr->dct_table, SIZEOF(multiplier_table));
/* Mark multiplier table not yet set up for any method */
idct->cur_method[ci] = -1;
}
}

View File

@@ -0,0 +1,574 @@
/*
* jdhuff.c
*
* Copyright (C) 1991-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains Huffman entropy decoding routines.
*
* Much of the complexity here has to do with supporting input suspension.
* If the data source module demands suspension, we want to be able to back
* up to the start of the current MCU. To do this, we copy state variables
* into local working storage, and update them back to the permanent
* storage only upon successful completion of an MCU.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jdhuff.h" /* Declarations shared with jdphuff.c */
/*
* Expanded entropy decoder object for Huffman decoding.
*
* The savable_state subrecord contains fields that change within an MCU,
* but must not be updated permanently until we complete the MCU.
*/
typedef struct {
int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
} savable_state;
/* This macro is to work around compilers with missing or broken
* structure assignment. You'll need to fix this code if you have
* such a compiler and you change MAX_COMPS_IN_SCAN.
*/
#ifndef NO_STRUCT_ASSIGN
#define ASSIGN_STATE(dest,src) ((dest) = (src))
#else
#if MAX_COMPS_IN_SCAN == 4
#define ASSIGN_STATE(dest,src) \
((dest).last_dc_val[0] = (src).last_dc_val[0], \
(dest).last_dc_val[1] = (src).last_dc_val[1], \
(dest).last_dc_val[2] = (src).last_dc_val[2], \
(dest).last_dc_val[3] = (src).last_dc_val[3])
#endif
#endif
typedef struct {
struct jpeg_entropy_decoder pub; /* public fields */
/* These fields are loaded into local variables at start of each MCU.
* In case of suspension, we exit WITHOUT updating them.
*/
bitread_perm_state bitstate; /* Bit buffer at start of MCU */
savable_state saved; /* Other state at start of MCU */
/* These fields are NOT loaded into local working state. */
unsigned int restarts_to_go; /* MCUs left in this restart interval */
/* Pointers to derived tables (these workspaces have image lifespan) */
d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
} huff_entropy_decoder;
typedef huff_entropy_decoder * huff_entropy_ptr;
/*
* Initialize for a Huffman-compressed scan.
*/
METHODDEF void
start_pass_huff_decoder (j_decompress_ptr cinfo)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int ci, dctbl, actbl;
jpeg_component_info * compptr;
/* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
* This ought to be an error condition, but we make it a warning because
* there are some baseline files out there with all zeroes in these bytes.
*/
if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 ||
cinfo->Ah != 0 || cinfo->Al != 0)
WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
dctbl = compptr->dc_tbl_no;
actbl = compptr->ac_tbl_no;
/* Make sure requested tables are present */
if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS ||
cinfo->dc_huff_tbl_ptrs[dctbl] == NULL)
ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl);
if (actbl < 0 || actbl >= NUM_HUFF_TBLS ||
cinfo->ac_huff_tbl_ptrs[actbl] == NULL)
ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl);
/* Compute derived values for Huffman tables */
/* We may do this more than once for a table, but it's not expensive */
jpeg_make_d_derived_tbl(cinfo, cinfo->dc_huff_tbl_ptrs[dctbl],
& entropy->dc_derived_tbls[dctbl]);
jpeg_make_d_derived_tbl(cinfo, cinfo->ac_huff_tbl_ptrs[actbl],
& entropy->ac_derived_tbls[actbl]);
/* Initialize DC predictions to 0 */
entropy->saved.last_dc_val[ci] = 0;
}
/* Initialize bitread state variables */
entropy->bitstate.bits_left = 0;
entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
entropy->bitstate.printed_eod = FALSE;
/* Initialize restart counter */
entropy->restarts_to_go = cinfo->restart_interval;
}
/*
* Compute the derived values for a Huffman table.
* Note this is also used by jdphuff.c.
*/
GLOBAL void
jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, JHUFF_TBL * htbl,
d_derived_tbl ** pdtbl)
{
d_derived_tbl *dtbl;
int p, i, l, si;
int lookbits, ctr;
char huffsize[257];
unsigned int huffcode[257];
unsigned int code;
/* Allocate a workspace if we haven't already done so. */
if (*pdtbl == NULL)
*pdtbl = (d_derived_tbl *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(d_derived_tbl));
dtbl = *pdtbl;
dtbl->pub = htbl; /* fill in back link */
/* Figure C.1: make table of Huffman code length for each symbol */
/* Note that this is in code-length order. */
p = 0;
for (l = 1; l <= 16; l++) {
for (i = 1; i <= (int) htbl->bits[l]; i++)
huffsize[p++] = (char) l;
}
huffsize[p] = 0;
/* Figure C.2: generate the codes themselves */
/* Note that this is in code-length order. */
code = 0;
si = huffsize[0];
p = 0;
while (huffsize[p]) {
while (((int) huffsize[p]) == si) {
huffcode[p++] = code;
code++;
}
code <<= 1;
si++;
}
/* Figure F.15: generate decoding tables for bit-sequential decoding */
p = 0;
for (l = 1; l <= 16; l++) {
if (htbl->bits[l]) {
dtbl->valptr[l] = p; /* huffval[] index of 1st symbol of code length l */
dtbl->mincode[l] = huffcode[p]; /* minimum code of length l */
p += htbl->bits[l];
dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */
} else {
dtbl->maxcode[l] = -1; /* -1 if no codes of this length */
}
}
dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */
/* Compute lookahead tables to speed up decoding.
* First we set all the table entries to 0, indicating "too long";
* then we iterate through the Huffman codes that are short enough and
* fill in all the entries that correspond to bit sequences starting
* with that code.
*/
MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits));
p = 0;
for (l = 1; l <= HUFF_LOOKAHEAD; l++) {
for (i = 1; i <= (int) htbl->bits[l]; i++, p++) {
/* l = current code's length, p = its index in huffcode[] & huffval[]. */
/* Generate left-justified code followed by all possible bit sequences */
lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l);
for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) {
dtbl->look_nbits[lookbits] = l;
dtbl->look_sym[lookbits] = htbl->huffval[p];
lookbits++;
}
}
}
}
/*
* Out-of-line code for bit fetching (shared with jdphuff.c).
* See jdhuff.h for info about usage.
* Note: current values of get_buffer and bits_left are passed as parameters,
* but are returned in the corresponding fields of the state struct.
*
* On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width
* of get_buffer to be used. (On machines with wider words, an even larger
* buffer could be used.) However, on some machines 32-bit shifts are
* quite slow and take time proportional to the number of places shifted.
* (This is true with most PC compilers, for instance.) In this case it may
* be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the
* average shift distance at the cost of more calls to jpeg_fill_bit_buffer.
*/
#ifdef SLOW_SHIFT_32
#define MIN_GET_BITS 15 /* minimum allowable value */
#else
#define MIN_GET_BITS (BIT_BUF_SIZE-7)
#endif
GLOBAL boolean
jpeg_fill_bit_buffer (bitread_working_state * state,
register bit_buf_type get_buffer, register int bits_left,
int nbits)
/* Load up the bit buffer to a depth of at least nbits */
{
/* Copy heavily used state fields into locals (hopefully registers) */
register const JOCTET * next_input_byte = state->next_input_byte;
register size_t bytes_in_buffer = state->bytes_in_buffer;
register int c;
/* Attempt to load at least MIN_GET_BITS bits into get_buffer. */
/* (It is assumed that no request will be for more than that many bits.) */
while (bits_left < MIN_GET_BITS) {
/* Attempt to read a byte */
if (state->unread_marker != 0)
goto no_more_data; /* can't advance past a marker */
if (bytes_in_buffer == 0) {
if (! (*state->cinfo->src->fill_input_buffer) (state->cinfo))
return FALSE;
next_input_byte = state->cinfo->src->next_input_byte;
bytes_in_buffer = state->cinfo->src->bytes_in_buffer;
}
bytes_in_buffer--;
c = GETJOCTET(*next_input_byte++);
/* If it's 0xFF, check and discard stuffed zero byte */
if (c == 0xFF) {
do {
if (bytes_in_buffer == 0) {
if (! (*state->cinfo->src->fill_input_buffer) (state->cinfo))
return FALSE;
next_input_byte = state->cinfo->src->next_input_byte;
bytes_in_buffer = state->cinfo->src->bytes_in_buffer;
}
bytes_in_buffer--;
c = GETJOCTET(*next_input_byte++);
} while (c == 0xFF);
if (c == 0) {
/* Found FF/00, which represents an FF data byte */
c = 0xFF;
} else {
/* Oops, it's actually a marker indicating end of compressed data. */
/* Better put it back for use later */
state->unread_marker = c;
no_more_data:
/* There should be enough bits still left in the data segment; */
/* if so, just break out of the outer while loop. */
if (bits_left >= nbits)
break;
/* Uh-oh. Report corrupted data to user and stuff zeroes into
* the data stream, so that we can produce some kind of image.
* Note that this code will be repeated for each byte demanded
* for the rest of the segment. We use a nonvolatile flag to ensure
* that only one warning message appears.
*/
if (! *(state->printed_eod_ptr)) {
WARNMS(state->cinfo, JWRN_HIT_MARKER);
*(state->printed_eod_ptr) = TRUE;
}
c = 0; /* insert a zero byte into bit buffer */
}
}
/* OK, load c into get_buffer */
get_buffer = (get_buffer << 8) | c;
bits_left += 8;
}
/* Unload the local registers */
state->next_input_byte = next_input_byte;
state->bytes_in_buffer = bytes_in_buffer;
state->get_buffer = get_buffer;
state->bits_left = bits_left;
return TRUE;
}
/*
* Out-of-line code for Huffman code decoding.
* See jdhuff.h for info about usage.
*/
GLOBAL int
jpeg_huff_decode (bitread_working_state * state,
register bit_buf_type get_buffer, register int bits_left,
d_derived_tbl * htbl, int min_bits)
{
register int l = min_bits;
register INT32 code;
/* HUFF_DECODE has determined that the code is at least min_bits */
/* bits long, so fetch that many bits in one swoop. */
CHECK_BIT_BUFFER(*state, l, return -1);
code = GET_BITS(l);
/* Collect the rest of the Huffman code one bit at a time. */
/* This is per Figure F.16 in the JPEG spec. */
while (code > htbl->maxcode[l]) {
code <<= 1;
CHECK_BIT_BUFFER(*state, 1, return -1);
code |= GET_BITS(1);
l++;
}
/* Unload the local registers */
state->get_buffer = get_buffer;
state->bits_left = bits_left;
/* With garbage input we may reach the sentinel value l = 17. */
if (l > 16) {
WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE);
return 0; /* fake a zero as the safest result */
}
return htbl->pub->huffval[ htbl->valptr[l] +
((int) (code - htbl->mincode[l])) ];
}
/*
* Figure F.12: extend sign bit.
* On some machines, a shift and add will be faster than a table lookup.
*/
#ifdef AVOID_TABLES
#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))
#else
#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
static const int extend_test[16] = /* entry n is 2**(n-1) */
{ 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
{ 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1,
((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1,
((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 };
#endif /* AVOID_TABLES */
/*
* Check for a restart marker & resynchronize decoder.
* Returns FALSE if must suspend.
*/
LOCAL boolean
process_restart (j_decompress_ptr cinfo)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int ci;
/* Throw away any unused bits remaining in bit buffer; */
/* include any full bytes in next_marker's count of discarded bytes */
cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
entropy->bitstate.bits_left = 0;
/* Advance past the RSTn marker */
if (! (*cinfo->marker->read_restart_marker) (cinfo))
return FALSE;
/* Re-initialize DC predictions to 0 */
for (ci = 0; ci < cinfo->comps_in_scan; ci++)
entropy->saved.last_dc_val[ci] = 0;
/* Reset restart counter */
entropy->restarts_to_go = cinfo->restart_interval;
/* Next segment can get another out-of-data warning */
entropy->bitstate.printed_eod = FALSE;
return TRUE;
}
/*
* Decode and return one MCU's worth of Huffman-compressed coefficients.
* The coefficients are reordered from zigzag order into natural array order,
* but are not dequantized.
*
* The i'th block of the MCU is stored into the block pointed to by
* MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER.
* (Wholesale zeroing is usually a little faster than retail...)
*
* Returns FALSE if data source requested suspension. In that case no
* changes have been made to permanent state. (Exception: some output
* coefficients may already have been assigned. This is harmless for
* this module, since we'll just re-assign them on the next call.)
*/
METHODDEF boolean
decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
register int s, k, r;
int blkn, ci;
JBLOCKROW block;
BITREAD_STATE_VARS;
savable_state state;
d_derived_tbl * dctbl;
d_derived_tbl * actbl;
jpeg_component_info * compptr;
/* Process restart marker if needed; may have to suspend */
if (cinfo->restart_interval) {
if (entropy->restarts_to_go == 0)
if (! process_restart(cinfo))
return FALSE;
}
/* Load up working state */
BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
ASSIGN_STATE(state, entropy->saved);
/* Outer loop handles each block in the MCU */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn];
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
dctbl = entropy->dc_derived_tbls[compptr->dc_tbl_no];
actbl = entropy->ac_derived_tbls[compptr->ac_tbl_no];
/* Decode a single block's worth of coefficients */
/* Section F.2.2.1: decode the DC coefficient difference */
HUFF_DECODE(s, br_state, dctbl, return FALSE, label1);
if (s) {
CHECK_BIT_BUFFER(br_state, s, return FALSE);
r = GET_BITS(s);
s = HUFF_EXTEND(r, s);
}
/* Shortcut if component's values are not interesting */
if (! compptr->component_needed)
goto skip_ACs;
/* Convert DC difference to actual value, update last_dc_val */
s += state.last_dc_val[ci];
state.last_dc_val[ci] = s;
/* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
(*block)[0] = (JCOEF) s;
/* Do we need to decode the AC coefficients for this component? */
if (compptr->DCT_scaled_size > 1) {
/* Section F.2.2.2: decode the AC coefficients */
/* Since zeroes are skipped, output area must be cleared beforehand */
for (k = 1; k < DCTSIZE2; k++) {
HUFF_DECODE(s, br_state, actbl, return FALSE, label2);
r = s >> 4;
s &= 15;
if (s) {
k += r;
CHECK_BIT_BUFFER(br_state, s, return FALSE);
r = GET_BITS(s);
s = HUFF_EXTEND(r, s);
/* Output coefficient in natural (dezigzagged) order.
* Note: the extra entries in jpeg_natural_order[] will save us
* if k >= DCTSIZE2, which could happen if the data is corrupted.
*/
(*block)[jpeg_natural_order[k]] = (JCOEF) s;
} else {
if (r != 15)
break;
k += 15;
}
}
} else {
skip_ACs:
/* Section F.2.2.2: decode the AC coefficients */
/* In this path we just discard the values */
for (k = 1; k < DCTSIZE2; k++) {
HUFF_DECODE(s, br_state, actbl, return FALSE, label3);
r = s >> 4;
s &= 15;
if (s) {
k += r;
CHECK_BIT_BUFFER(br_state, s, return FALSE);
DROP_BITS(s);
} else {
if (r != 15)
break;
k += 15;
}
}
}
}
/* Completed MCU, so update state */
BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
ASSIGN_STATE(entropy->saved, state);
/* Account for restart interval (no-op if not using restarts) */
entropy->restarts_to_go--;
return TRUE;
}
/*
* Module initialization routine for Huffman entropy decoding.
*/
GLOBAL void
jinit_huff_decoder (j_decompress_ptr cinfo)
{
huff_entropy_ptr entropy;
int i;
entropy = (huff_entropy_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(huff_entropy_decoder));
cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
entropy->pub.start_pass = start_pass_huff_decoder;
entropy->pub.decode_mcu = decode_mcu;
/* Mark tables unallocated */
for (i = 0; i < NUM_HUFF_TBLS; i++) {
entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
}
}

View File

@@ -0,0 +1,202 @@
/*
* jdhuff.h
*
* Copyright (C) 1991-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains declarations for Huffman entropy decoding routines
* that are shared between the sequential decoder (jdhuff.c) and the
* progressive decoder (jdphuff.c). No other modules need to see these.
*/
/* Short forms of external names for systems with brain-damaged linkers. */
#ifdef NEED_SHORT_EXTERNAL_NAMES
#define jpeg_make_d_derived_tbl jMkDDerived
#define jpeg_fill_bit_buffer jFilBitBuf
#define jpeg_huff_decode jHufDecode
#endif /* NEED_SHORT_EXTERNAL_NAMES */
/* Derived data constructed for each Huffman table */
#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */
typedef struct {
/* Basic tables: (element [0] of each array is unused) */
INT32 mincode[17]; /* smallest code of length k */
INT32 maxcode[18]; /* largest code of length k (-1 if none) */
/* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */
int valptr[17]; /* huffval[] index of 1st symbol of length k */
/* Link to public Huffman table (needed only in jpeg_huff_decode) */
JHUFF_TBL *pub;
/* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of
* the input data stream. If the next Huffman code is no more
* than HUFF_LOOKAHEAD bits long, we can obtain its length and
* the corresponding symbol directly from these tables.
*/
int look_nbits[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */
UINT8 look_sym[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */
} d_derived_tbl;
/* Expand a Huffman table definition into the derived format */
EXTERN void jpeg_make_d_derived_tbl JPP((j_decompress_ptr cinfo,
JHUFF_TBL * htbl, d_derived_tbl ** pdtbl));
/*
* Fetching the next N bits from the input stream is a time-critical operation
* for the Huffman decoders. We implement it with a combination of inline
* macros and out-of-line subroutines. Note that N (the number of bits
* demanded at one time) never exceeds 15 for JPEG use.
*
* We read source bytes into get_buffer and dole out bits as needed.
* If get_buffer already contains enough bits, they are fetched in-line
* by the macros CHECK_BIT_BUFFER and GET_BITS. When there aren't enough
* bits, jpeg_fill_bit_buffer is called; it will attempt to fill get_buffer
* as full as possible (not just to the number of bits needed; this
* prefetching reduces the overhead cost of calling jpeg_fill_bit_buffer).
* Note that jpeg_fill_bit_buffer may return FALSE to indicate suspension.
* On TRUE return, jpeg_fill_bit_buffer guarantees that get_buffer contains
* at least the requested number of bits --- dummy zeroes are inserted if
* necessary.
*/
typedef INT32 bit_buf_type; /* type of bit-extraction buffer */
#define BIT_BUF_SIZE 32 /* size of buffer in bits */
/* If long is > 32 bits on your machine, and shifting/masking longs is
* reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE
* appropriately should be a win. Unfortunately we can't do this with
* something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8)
* because not all machines measure sizeof in 8-bit bytes.
*/
typedef struct { /* Bitreading state saved across MCUs */
bit_buf_type get_buffer; /* current bit-extraction buffer */
int bits_left; /* # of unused bits in it */
boolean printed_eod; /* flag to suppress multiple warning msgs */
} bitread_perm_state;
typedef struct { /* Bitreading working state within an MCU */
/* current data source state */
const JOCTET * next_input_byte; /* => next byte to read from source */
size_t bytes_in_buffer; /* # of bytes remaining in source buffer */
int unread_marker; /* nonzero if we have hit a marker */
/* bit input buffer --- note these values are kept in register variables,
* not in this struct, inside the inner loops.
*/
bit_buf_type get_buffer; /* current bit-extraction buffer */
int bits_left; /* # of unused bits in it */
/* pointers needed by jpeg_fill_bit_buffer */
j_decompress_ptr cinfo; /* back link to decompress master record */
boolean * printed_eod_ptr; /* => flag in permanent state */
} bitread_working_state;
/* Macros to declare and load/save bitread local variables. */
#define BITREAD_STATE_VARS \
register bit_buf_type get_buffer; \
register int bits_left; \
bitread_working_state br_state
#define BITREAD_LOAD_STATE(cinfop,permstate) \
br_state.cinfo = cinfop; \
br_state.next_input_byte = cinfop->src->next_input_byte; \
br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \
br_state.unread_marker = cinfop->unread_marker; \
get_buffer = permstate.get_buffer; \
bits_left = permstate.bits_left; \
br_state.printed_eod_ptr = & permstate.printed_eod
#define BITREAD_SAVE_STATE(cinfop,permstate) \
cinfop->src->next_input_byte = br_state.next_input_byte; \
cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \
cinfop->unread_marker = br_state.unread_marker; \
permstate.get_buffer = get_buffer; \
permstate.bits_left = bits_left
/*
* These macros provide the in-line portion of bit fetching.
* Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer
* before using GET_BITS, PEEK_BITS, or DROP_BITS.
* The variables get_buffer and bits_left are assumed to be locals,
* but the state struct might not be (jpeg_huff_decode needs this).
* CHECK_BIT_BUFFER(state,n,action);
* Ensure there are N bits in get_buffer; if suspend, take action.
* val = GET_BITS(n);
* Fetch next N bits.
* val = PEEK_BITS(n);
* Fetch next N bits without removing them from the buffer.
* DROP_BITS(n);
* Discard next N bits.
* The value N should be a simple variable, not an expression, because it
* is evaluated multiple times.
*/
#define CHECK_BIT_BUFFER(state,nbits,action) \
{ if (bits_left < (nbits)) { \
if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \
{ action; } \
get_buffer = (state).get_buffer; bits_left = (state).bits_left; } }
#define GET_BITS(nbits) \
(((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1))
#define PEEK_BITS(nbits) \
(((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1))
#define DROP_BITS(nbits) \
(bits_left -= (nbits))
/* Load up the bit buffer to a depth of at least nbits */
EXTERN boolean jpeg_fill_bit_buffer JPP((bitread_working_state * state,
register bit_buf_type get_buffer, register int bits_left,
int nbits));
/*
* Code for extracting next Huffman-coded symbol from input bit stream.
* Again, this is time-critical and we make the main paths be macros.
*
* We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits
* without looping. Usually, more than 95% of the Huffman codes will be 8
* or fewer bits long. The few overlength codes are handled with a loop,
* which need not be inline code.
*
* Notes about the HUFF_DECODE macro:
* 1. Near the end of the data segment, we may fail to get enough bits
* for a lookahead. In that case, we do it the hard way.
* 2. If the lookahead table contains no entry, the next code must be
* more than HUFF_LOOKAHEAD bits long.
* 3. jpeg_huff_decode returns -1 if forced to suspend.
*/
#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \
{ register int nb, look; \
if (bits_left < HUFF_LOOKAHEAD) { \
if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \
get_buffer = state.get_buffer; bits_left = state.bits_left; \
if (bits_left < HUFF_LOOKAHEAD) { \
nb = 1; goto slowlabel; \
} \
} \
look = PEEK_BITS(HUFF_LOOKAHEAD); \
if ((nb = htbl->look_nbits[look]) != 0) { \
DROP_BITS(nb); \
result = htbl->look_sym[look]; \
} else { \
nb = HUFF_LOOKAHEAD+1; \
slowlabel: \
if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
{ failaction; } \
get_buffer = state.get_buffer; bits_left = state.bits_left; \
} \
}
/* Out-of-line case for Huffman code fetching */
EXTERN int jpeg_huff_decode JPP((bitread_working_state * state,
register bit_buf_type get_buffer, register int bits_left,
d_derived_tbl * htbl, int min_bits));

View File

@@ -0,0 +1,381 @@
/*
* jdinput.c
*
* Copyright (C) 1991-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains input control logic for the JPEG decompressor.
* These routines are concerned with controlling the decompressor's input
* processing (marker reading and coefficient decoding). The actual input
* reading is done in jdmarker.c, jdhuff.c, and jdphuff.c.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* Private state */
typedef struct {
struct jpeg_input_controller pub; /* public fields */
boolean inheaders; /* TRUE until first SOS is reached */
} my_input_controller;
typedef my_input_controller * my_inputctl_ptr;
/* Forward declarations */
METHODDEF int consume_markers JPP((j_decompress_ptr cinfo));
/*
* Routines to calculate various quantities related to the size of the image.
*/
LOCAL void
initial_setup (j_decompress_ptr cinfo)
/* Called once, when first SOS marker is reached */
{
int ci;
jpeg_component_info *compptr;
/* Make sure image isn't bigger than I can handle */
if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
(long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
/* For now, precision must match compiled-in value... */
if (cinfo->data_precision != BITS_IN_JSAMPLE)
ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
/* Check that number of components won't exceed internal array sizes */
if (cinfo->num_components > MAX_COMPONENTS)
ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
MAX_COMPONENTS);
/* Compute maximum sampling factors; check factor validity */
cinfo->max_h_samp_factor = 1;
cinfo->max_v_samp_factor = 1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
ERREXIT(cinfo, JERR_BAD_SAMPLING);
cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
compptr->h_samp_factor);
cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
compptr->v_samp_factor);
}
/* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE.
* In the full decompressor, this will be overridden by jdmaster.c;
* but in the transcoder, jdmaster.c is not used, so we must do it here.
*/
cinfo->min_DCT_scaled_size = DCTSIZE;
/* Compute dimensions of components */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
compptr->DCT_scaled_size = DCTSIZE;
/* Size in DCT blocks */
compptr->width_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
(long) (cinfo->max_h_samp_factor * DCTSIZE));
compptr->height_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
(long) (cinfo->max_v_samp_factor * DCTSIZE));
/* downsampled_width and downsampled_height will also be overridden by
* jdmaster.c if we are doing full decompression. The transcoder library
* doesn't use these values, but the calling application might.
*/
/* Size in samples */
compptr->downsampled_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
(long) cinfo->max_h_samp_factor);
compptr->downsampled_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
(long) cinfo->max_v_samp_factor);
/* Mark component needed, until color conversion says otherwise */
compptr->component_needed = TRUE;
/* Mark no quantization table yet saved for component */
compptr->quant_table = NULL;
}
/* Compute number of fully interleaved MCU rows. */
cinfo->total_iMCU_rows = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height,
(long) (cinfo->max_v_samp_factor*DCTSIZE));
/* Decide whether file contains multiple scans */
if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode)
cinfo->inputctl->has_multiple_scans = TRUE;
else
cinfo->inputctl->has_multiple_scans = FALSE;
}
LOCAL void
per_scan_setup (j_decompress_ptr cinfo)
/* Do computations that are needed before processing a JPEG scan */
/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */
{
int ci, mcublks, tmp;
jpeg_component_info *compptr;
if (cinfo->comps_in_scan == 1) {
/* Noninterleaved (single-component) scan */
compptr = cinfo->cur_comp_info[0];
/* Overall image size in MCUs */
cinfo->MCUs_per_row = compptr->width_in_blocks;
cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
/* For noninterleaved scan, always one block per MCU */
compptr->MCU_width = 1;
compptr->MCU_height = 1;
compptr->MCU_blocks = 1;
compptr->MCU_sample_width = compptr->DCT_scaled_size;
compptr->last_col_width = 1;
/* For noninterleaved scans, it is convenient to define last_row_height
* as the number of block rows present in the last iMCU row.
*/
tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
if (tmp == 0) tmp = compptr->v_samp_factor;
compptr->last_row_height = tmp;
/* Prepare array describing MCU composition */
cinfo->blocks_in_MCU = 1;
cinfo->MCU_membership[0] = 0;
} else {
/* Interleaved (multi-component) scan */
if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
MAX_COMPS_IN_SCAN);
/* Overall image size in MCUs */
cinfo->MCUs_per_row = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width,
(long) (cinfo->max_h_samp_factor*DCTSIZE));
cinfo->MCU_rows_in_scan = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height,
(long) (cinfo->max_v_samp_factor*DCTSIZE));
cinfo->blocks_in_MCU = 0;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* Sampling factors give # of blocks of component in each MCU */
compptr->MCU_width = compptr->h_samp_factor;
compptr->MCU_height = compptr->v_samp_factor;
compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_scaled_size;
/* Figure number of non-dummy blocks in last MCU column & row */
tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
if (tmp == 0) tmp = compptr->MCU_width;
compptr->last_col_width = tmp;
tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
if (tmp == 0) tmp = compptr->MCU_height;
compptr->last_row_height = tmp;
/* Prepare array describing MCU composition */
mcublks = compptr->MCU_blocks;
if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU)
ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
while (mcublks-- > 0) {
cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
}
}
}
}
/*
* Save away a copy of the Q-table referenced by each component present
* in the current scan, unless already saved during a prior scan.
*
* In a multiple-scan JPEG file, the encoder could assign different components
* the same Q-table slot number, but change table definitions between scans
* so that each component uses a different Q-table. (The IJG encoder is not
* currently capable of doing this, but other encoders might.) Since we want
* to be able to dequantize all the components at the end of the file, this
* means that we have to save away the table actually used for each component.
* We do this by copying the table at the start of the first scan containing
* the component.
* The JPEG spec prohibits the encoder from changing the contents of a Q-table
* slot between scans of a component using that slot. If the encoder does so
* anyway, this decoder will simply use the Q-table values that were current
* at the start of the first scan for the component.
*
* The decompressor output side looks only at the saved quant tables,
* not at the current Q-table slots.
*/
LOCAL void
latch_quant_tables (j_decompress_ptr cinfo)
{
int ci, qtblno;
jpeg_component_info *compptr;
JQUANT_TBL * qtbl;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* No work if we already saved Q-table for this component */
if (compptr->quant_table != NULL)
continue;
/* Make sure specified quantization table is present */
qtblno = compptr->quant_tbl_no;
if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
cinfo->quant_tbl_ptrs[qtblno] == NULL)
ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
/* OK, save away the quantization table */
qtbl = (JQUANT_TBL *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(JQUANT_TBL));
MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));
compptr->quant_table = qtbl;
}
}
/*
* Initialize the input modules to read a scan of compressed data.
* The first call to this is done by jdmaster.c after initializing
* the entire decompressor (during jpeg_start_decompress).
* Subsequent calls come from consume_markers, below.
*/
METHODDEF void
start_input_pass (j_decompress_ptr cinfo)
{
per_scan_setup(cinfo);
latch_quant_tables(cinfo);
(*cinfo->entropy->start_pass) (cinfo);
(*cinfo->coef->start_input_pass) (cinfo);
cinfo->inputctl->consume_input = cinfo->coef->consume_data;
}
/*
* Finish up after inputting a compressed-data scan.
* This is called by the coefficient controller after it's read all
* the expected data of the scan.
*/
METHODDEF void
finish_input_pass (j_decompress_ptr cinfo)
{
cinfo->inputctl->consume_input = consume_markers;
}
/*
* Read JPEG markers before, between, or after compressed-data scans.
* Change state as necessary when a new scan is reached.
* Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
*
* The consume_input method pointer points either here or to the
* coefficient controller's consume_data routine, depending on whether
* we are reading a compressed data segment or inter-segment markers.
*/
METHODDEF int
consume_markers (j_decompress_ptr cinfo)
{
my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
int val;
if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */
return JPEG_REACHED_EOI;
val = (*cinfo->marker->read_markers) (cinfo);
switch (val) {
case JPEG_REACHED_SOS: /* Found SOS */
if (inputctl->inheaders) { /* 1st SOS */
initial_setup(cinfo);
inputctl->inheaders = FALSE;
/* Note: start_input_pass must be called by jdmaster.c
* before any more input can be consumed. jdapi.c is
* responsible for enforcing this sequencing.
*/
} else { /* 2nd or later SOS marker */
if (! inputctl->pub.has_multiple_scans)
ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */
start_input_pass(cinfo);
}
break;
case JPEG_REACHED_EOI: /* Found EOI */
inputctl->pub.eoi_reached = TRUE;
if (inputctl->inheaders) { /* Tables-only datastream, apparently */
if (cinfo->marker->saw_SOF)
ERREXIT(cinfo, JERR_SOF_NO_SOS);
} else {
/* Prevent infinite loop in coef ctlr's decompress_data routine
* if user set output_scan_number larger than number of scans.
*/
if (cinfo->output_scan_number > cinfo->input_scan_number)
cinfo->output_scan_number = cinfo->input_scan_number;
}
break;
case JPEG_SUSPENDED:
break;
}
return val;
}
/*
* Reset state to begin a fresh datastream.
*/
METHODDEF void
reset_input_controller (j_decompress_ptr cinfo)
{
my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
inputctl->pub.consume_input = consume_markers;
inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
inputctl->pub.eoi_reached = FALSE;
inputctl->inheaders = TRUE;
/* Reset other modules */
(*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
(*cinfo->marker->reset_marker_reader) (cinfo);
/* Reset progression state -- would be cleaner if entropy decoder did this */
cinfo->coef_bits = NULL;
}
/*
* Initialize the input controller module.
* This is called only once, when the decompression object is created.
*/
GLOBAL void
jinit_input_controller (j_decompress_ptr cinfo)
{
my_inputctl_ptr inputctl;
/* Create subobject in permanent pool */
inputctl = (my_inputctl_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
SIZEOF(my_input_controller));
cinfo->inputctl = (struct jpeg_input_controller *) inputctl;
/* Initialize method pointers */
inputctl->pub.consume_input = consume_markers;
inputctl->pub.reset_input_controller = reset_input_controller;
inputctl->pub.start_input_pass = start_input_pass;
inputctl->pub.finish_input_pass = finish_input_pass;
/* Initialize state: can't use reset_input_controller since we don't
* want to try to reset other modules yet.
*/
inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
inputctl->pub.eoi_reached = FALSE;
inputctl->inheaders = TRUE;
}

View File

@@ -0,0 +1,512 @@
/*
* jdmainct.c
*
* Copyright (C) 1994-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains the main buffer controller for decompression.
* The main buffer lies between the JPEG decompressor proper and the
* post-processor; it holds downsampled data in the JPEG colorspace.
*
* Note that this code is bypassed in raw-data mode, since the application
* supplies the equivalent of the main buffer in that case.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/*
* In the current system design, the main buffer need never be a full-image
* buffer; any full-height buffers will be found inside the coefficient or
* postprocessing controllers. Nonetheless, the main controller is not
* trivial. Its responsibility is to provide context rows for upsampling/
* rescaling, and doing this in an efficient fashion is a bit tricky.
*
* Postprocessor input data is counted in "row groups". A row group
* is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
* sample rows of each component. (We require DCT_scaled_size values to be
* chosen such that these numbers are integers. In practice DCT_scaled_size
* values will likely be powers of two, so we actually have the stronger
* condition that DCT_scaled_size / min_DCT_scaled_size is an integer.)
* Upsampling will typically produce max_v_samp_factor pixel rows from each
* row group (times any additional scale factor that the upsampler is
* applying).
*
* The coefficient controller will deliver data to us one iMCU row at a time;
* each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or
* exactly min_DCT_scaled_size row groups. (This amount of data corresponds
* to one row of MCUs when the image is fully interleaved.) Note that the
* number of sample rows varies across components, but the number of row
* groups does not. Some garbage sample rows may be included in the last iMCU
* row at the bottom of the image.
*
* Depending on the vertical scaling algorithm used, the upsampler may need
* access to the sample row(s) above and below its current input row group.
* The upsampler is required to set need_context_rows TRUE at global selection
* time if so. When need_context_rows is FALSE, this controller can simply
* obtain one iMCU row at a time from the coefficient controller and dole it
* out as row groups to the postprocessor.
*
* When need_context_rows is TRUE, this controller guarantees that the buffer
* passed to postprocessing contains at least one row group's worth of samples
* above and below the row group(s) being processed. Note that the context
* rows "above" the first passed row group appear at negative row offsets in
* the passed buffer. At the top and bottom of the image, the required
* context rows are manufactured by duplicating the first or last real sample
* row; this avoids having special cases in the upsampling inner loops.
*
* The amount of context is fixed at one row group just because that's a
* convenient number for this controller to work with. The existing
* upsamplers really only need one sample row of context. An upsampler
* supporting arbitrary output rescaling might wish for more than one row
* group of context when shrinking the image; tough, we don't handle that.
* (This is justified by the assumption that downsizing will be handled mostly
* by adjusting the DCT_scaled_size values, so that the actual scale factor at
* the upsample step needn't be much less than one.)
*
* To provide the desired context, we have to retain the last two row groups
* of one iMCU row while reading in the next iMCU row. (The last row group
* can't be processed until we have another row group for its below-context,
* and so we have to save the next-to-last group too for its above-context.)
* We could do this most simply by copying data around in our buffer, but
* that'd be very slow. We can avoid copying any data by creating a rather
* strange pointer structure. Here's how it works. We allocate a workspace
* consisting of M+2 row groups (where M = min_DCT_scaled_size is the number
* of row groups per iMCU row). We create two sets of redundant pointers to
* the workspace. Labeling the physical row groups 0 to M+1, the synthesized
* pointer lists look like this:
* M+1 M-1
* master pointer --> 0 master pointer --> 0
* 1 1
* ... ...
* M-3 M-3
* M-2 M
* M-1 M+1
* M M-2
* M+1 M-1
* 0 0
* We read alternate iMCU rows using each master pointer; thus the last two
* row groups of the previous iMCU row remain un-overwritten in the workspace.
* The pointer lists are set up so that the required context rows appear to
* be adjacent to the proper places when we pass the pointer lists to the
* upsampler.
*
* The above pictures describe the normal state of the pointer lists.
* At top and bottom of the image, we diddle the pointer lists to duplicate
* the first or last sample row as necessary (this is cheaper than copying
* sample rows around).
*
* This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that
* situation each iMCU row provides only one row group so the buffering logic
* must be different (eg, we must read two iMCU rows before we can emit the
* first row group). For now, we simply do not support providing context
* rows when min_DCT_scaled_size is 1. That combination seems unlikely to
* be worth providing --- if someone wants a 1/8th-size preview, they probably
* want it quick and dirty, so a context-free upsampler is sufficient.
*/
/* Private buffer controller object */
typedef struct {
struct jpeg_d_main_controller pub; /* public fields */
/* Pointer to allocated workspace (M or M+2 row groups). */
JSAMPARRAY buffer[MAX_COMPONENTS];
boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
/* Remaining fields are only used in the context case. */
/* These are the master pointers to the funny-order pointer lists. */
JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
int whichptr; /* indicates which pointer set is now in use */
int context_state; /* process_data state machine status */
JDIMENSION rowgroups_avail; /* row groups available to postprocessor */
JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */
} my_main_controller;
typedef my_main_controller * my_main_ptr;
/* context_state values: */
#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */
#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */
#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */
/* Forward declarations */
METHODDEF void process_data_simple_main
JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
METHODDEF void process_data_context_main
JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
#ifdef QUANT_2PASS_SUPPORTED
METHODDEF void process_data_crank_post
JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
#endif
LOCAL void
alloc_funny_pointers (j_decompress_ptr cinfo)
/* Allocate space for the funny pointer lists.
* This is done only once, not once per pass.
*/
{
my_main_ptr main = (my_main_ptr) cinfo->main;
int ci, rgroup;
int M = cinfo->min_DCT_scaled_size;
jpeg_component_info *compptr;
JSAMPARRAY xbuf;
/* Get top-level space for component array pointers.
* We alloc both arrays with one call to save a few cycles.
*/
main->xbuffer[0] = (JSAMPIMAGE)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
cinfo->num_components * 2 * SIZEOF(JSAMPARRAY));
main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_DCT_scaled_size; /* height of a row group of component */
/* Get space for pointer lists --- M+4 row groups in each list.
* We alloc both pointer lists with one call to save a few cycles.
*/
xbuf = (JSAMPARRAY)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW));
xbuf += rgroup; /* want one row group at negative offsets */
main->xbuffer[0][ci] = xbuf;
xbuf += rgroup * (M + 4);
main->xbuffer[1][ci] = xbuf;
}
}
LOCAL void
make_funny_pointers (j_decompress_ptr cinfo)
/* Create the funny pointer lists discussed in the comments above.
* The actual workspace is already allocated (in main->buffer),
* and the space for the pointer lists is allocated too.
* This routine just fills in the curiously ordered lists.
* This will be repeated at the beginning of each pass.
*/
{
my_main_ptr main = (my_main_ptr) cinfo->main;
int ci, i, rgroup;
int M = cinfo->min_DCT_scaled_size;
jpeg_component_info *compptr;
JSAMPARRAY buf, xbuf0, xbuf1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_DCT_scaled_size; /* height of a row group of component */
xbuf0 = main->xbuffer[0][ci];
xbuf1 = main->xbuffer[1][ci];
/* First copy the workspace pointers as-is */
buf = main->buffer[ci];
for (i = 0; i < rgroup * (M + 2); i++) {
xbuf0[i] = xbuf1[i] = buf[i];
}
/* In the second list, put the last four row groups in swapped order */
for (i = 0; i < rgroup * 2; i++) {
xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i];
xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i];
}
/* The wraparound pointers at top and bottom will be filled later
* (see set_wraparound_pointers, below). Initially we want the "above"
* pointers to duplicate the first actual data line. This only needs
* to happen in xbuffer[0].
*/
for (i = 0; i < rgroup; i++) {
xbuf0[i - rgroup] = xbuf0[0];
}
}
}
LOCAL void
set_wraparound_pointers (j_decompress_ptr cinfo)
/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
* This changes the pointer list state from top-of-image to the normal state.
*/
{
my_main_ptr main = (my_main_ptr) cinfo->main;
int ci, i, rgroup;
int M = cinfo->min_DCT_scaled_size;
jpeg_component_info *compptr;
JSAMPARRAY xbuf0, xbuf1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_DCT_scaled_size; /* height of a row group of component */
xbuf0 = main->xbuffer[0][ci];
xbuf1 = main->xbuffer[1][ci];
for (i = 0; i < rgroup; i++) {
xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
xbuf0[rgroup*(M+2) + i] = xbuf0[i];
xbuf1[rgroup*(M+2) + i] = xbuf1[i];
}
}
}
LOCAL void
set_bottom_pointers (j_decompress_ptr cinfo)
/* Change the pointer lists to duplicate the last sample row at the bottom
* of the image. whichptr indicates which xbuffer holds the final iMCU row.
* Also sets rowgroups_avail to indicate number of nondummy row groups in row.
*/
{
my_main_ptr main = (my_main_ptr) cinfo->main;
int ci, i, rgroup, iMCUheight, rows_left;
jpeg_component_info *compptr;
JSAMPARRAY xbuf;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Count sample rows in one iMCU row and in one row group */
iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size;
rgroup = iMCUheight / cinfo->min_DCT_scaled_size;
/* Count nondummy sample rows remaining for this component */
rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight);
if (rows_left == 0) rows_left = iMCUheight;
/* Count nondummy row groups. Should get same answer for each component,
* so we need only do it once.
*/
if (ci == 0) {
main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
}
/* Duplicate the last real sample row rgroup*2 times; this pads out the
* last partial rowgroup and ensures at least one full rowgroup of context.
*/
xbuf = main->xbuffer[main->whichptr][ci];
for (i = 0; i < rgroup * 2; i++) {
xbuf[rows_left + i] = xbuf[rows_left-1];
}
}
}
/*
* Initialize for a processing pass.
*/
METHODDEF void
start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
{
my_main_ptr main = (my_main_ptr) cinfo->main;
switch (pass_mode) {
case JBUF_PASS_THRU:
if (cinfo->upsample->need_context_rows) {
main->pub.process_data = process_data_context_main;
make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
main->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
main->context_state = CTX_PREPARE_FOR_IMCU;
main->iMCU_row_ctr = 0;
} else {
/* Simple case with no context needed */
main->pub.process_data = process_data_simple_main;
}
main->buffer_full = FALSE; /* Mark buffer empty */
main->rowgroup_ctr = 0;
break;
#ifdef QUANT_2PASS_SUPPORTED
case JBUF_CRANK_DEST:
/* For last pass of 2-pass quantization, just crank the postprocessor */
main->pub.process_data = process_data_crank_post;
break;
#endif
default:
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
break;
}
}
/*
* Process some data.
* This handles the simple case where no context is required.
*/
METHODDEF void
process_data_simple_main (j_decompress_ptr cinfo,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail)
{
my_main_ptr main = (my_main_ptr) cinfo->main;
JDIMENSION rowgroups_avail;
/* Read input data if we haven't filled the main buffer yet */
if (! main->buffer_full) {
if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer))
return; /* suspension forced, can do nothing more */
main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
}
/* There are always min_DCT_scaled_size row groups in an iMCU row. */
rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size;
/* Note: at the bottom of the image, we may pass extra garbage row groups
* to the postprocessor. The postprocessor has to check for bottom
* of image anyway (at row resolution), so no point in us doing it too.
*/
/* Feed the postprocessor */
(*cinfo->post->post_process_data) (cinfo, main->buffer,
&main->rowgroup_ctr, rowgroups_avail,
output_buf, out_row_ctr, out_rows_avail);
/* Has postprocessor consumed all the data yet? If so, mark buffer empty */
if (main->rowgroup_ctr >= rowgroups_avail) {
main->buffer_full = FALSE;
main->rowgroup_ctr = 0;
}
}
/*
* Process some data.
* This handles the case where context rows must be provided.
*/
METHODDEF void
process_data_context_main (j_decompress_ptr cinfo,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail)
{
my_main_ptr main = (my_main_ptr) cinfo->main;
/* Read input data if we haven't filled the main buffer yet */
if (! main->buffer_full) {
if (! (*cinfo->coef->decompress_data) (cinfo,
main->xbuffer[main->whichptr]))
return; /* suspension forced, can do nothing more */
main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
main->iMCU_row_ctr++; /* count rows received */
}
/* Postprocessor typically will not swallow all the input data it is handed
* in one call (due to filling the output buffer first). Must be prepared
* to exit and restart. This switch lets us keep track of how far we got.
* Note that each case falls through to the next on successful completion.
*/
switch (main->context_state) {
case CTX_POSTPONED_ROW:
/* Call postprocessor using previously set pointers for postponed row */
(*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
&main->rowgroup_ctr, main->rowgroups_avail,
output_buf, out_row_ctr, out_rows_avail);
if (main->rowgroup_ctr < main->rowgroups_avail)
return; /* Need to suspend */
main->context_state = CTX_PREPARE_FOR_IMCU;
if (*out_row_ctr >= out_rows_avail)
return; /* Postprocessor exactly filled output buf */
/*FALLTHROUGH*/
case CTX_PREPARE_FOR_IMCU:
/* Prepare to process first M-1 row groups of this iMCU row */
main->rowgroup_ctr = 0;
main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1);
/* Check for bottom of image: if so, tweak pointers to "duplicate"
* the last sample row, and adjust rowgroups_avail to ignore padding rows.
*/
if (main->iMCU_row_ctr == cinfo->total_iMCU_rows)
set_bottom_pointers(cinfo);
main->context_state = CTX_PROCESS_IMCU;
/*FALLTHROUGH*/
case CTX_PROCESS_IMCU:
/* Call postprocessor using previously set pointers */
(*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
&main->rowgroup_ctr, main->rowgroups_avail,
output_buf, out_row_ctr, out_rows_avail);
if (main->rowgroup_ctr < main->rowgroups_avail)
return; /* Need to suspend */
/* After the first iMCU, change wraparound pointers to normal state */
if (main->iMCU_row_ctr == 1)
set_wraparound_pointers(cinfo);
/* Prepare to load new iMCU row using other xbuffer list */
main->whichptr ^= 1; /* 0=>1 or 1=>0 */
main->buffer_full = FALSE;
/* Still need to process last row group of this iMCU row, */
/* which is saved at index M+1 of the other xbuffer */
main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1);
main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2);
main->context_state = CTX_POSTPONED_ROW;
}
}
/*
* Process some data.
* Final pass of two-pass quantization: just call the postprocessor.
* Source data will be the postprocessor controller's internal buffer.
*/
#ifdef QUANT_2PASS_SUPPORTED
METHODDEF void
process_data_crank_post (j_decompress_ptr cinfo,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail)
{
(*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL,
(JDIMENSION *) NULL, (JDIMENSION) 0,
output_buf, out_row_ctr, out_rows_avail);
}
#endif /* QUANT_2PASS_SUPPORTED */
/*
* Initialize main buffer controller.
*/
GLOBAL void
jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
{
my_main_ptr main;
int ci, rgroup, ngroups;
jpeg_component_info *compptr;
main = (my_main_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_main_controller));
cinfo->main = (struct jpeg_d_main_controller *) main;
main->pub.start_pass = start_pass_main;
if (need_full_buffer) /* shouldn't happen */
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
/* Allocate the workspace.
* ngroups is the number of row groups we need.
*/
if (cinfo->upsample->need_context_rows) {
if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */
ERREXIT(cinfo, JERR_NOTIMPL);
alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */
ngroups = cinfo->min_DCT_scaled_size + 2;
} else {
ngroups = cinfo->min_DCT_scaled_size;
}
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_DCT_scaled_size; /* height of a row group of component */
main->buffer[ci] = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE,
compptr->width_in_blocks * compptr->DCT_scaled_size,
(JDIMENSION) (rgroup * ngroups));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,557 @@
/*
* jdmaster.c
*
* Copyright (C) 1991-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains master control logic for the JPEG decompressor.
* These routines are concerned with selecting the modules to be executed
* and with determining the number of passes and the work to be done in each
* pass.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* Private state */
typedef struct {
struct jpeg_decomp_master pub; /* public fields */
int pass_number; /* # of passes completed */
boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
/* Saved references to initialized quantizer modules,
* in case we need to switch modes.
*/
struct jpeg_color_quantizer * quantizer_1pass;
struct jpeg_color_quantizer * quantizer_2pass;
} my_decomp_master;
typedef my_decomp_master * my_master_ptr;
/*
* Determine whether merged upsample/color conversion should be used.
* CRUCIAL: this must match the actual capabilities of jdmerge.c!
*/
LOCAL boolean
use_merged_upsample (j_decompress_ptr cinfo)
{
#ifdef UPSAMPLE_MERGING_SUPPORTED
/* Merging is the equivalent of plain box-filter upsampling */
if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
return FALSE;
/* jdmerge.c only supports YCC=>RGB color conversion */
if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 ||
cinfo->out_color_space != JCS_RGB ||
cinfo->out_color_components != RGB_PIXELSIZE)
return FALSE;
/* and it only handles 2h1v or 2h2v sampling ratios */
if (cinfo->comp_info[0].h_samp_factor != 2 ||
cinfo->comp_info[1].h_samp_factor != 1 ||
cinfo->comp_info[2].h_samp_factor != 1 ||
cinfo->comp_info[0].v_samp_factor > 2 ||
cinfo->comp_info[1].v_samp_factor != 1 ||
cinfo->comp_info[2].v_samp_factor != 1)
return FALSE;
/* furthermore, it doesn't work if we've scaled the IDCTs differently */
if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size)
return FALSE;
/* ??? also need to test for upsample-time rescaling, when & if supported */
return TRUE; /* by golly, it'll work... */
#else
return FALSE;
#endif
}
/*
* Compute output image dimensions and related values.
* NOTE: this is exported for possible use by application.
* Hence it mustn't do anything that can't be done twice.
* Also note that it may be called before the master module is initialized!
*/
GLOBAL void
jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
/* Do computations that are needed before master selection phase */
{
#if 0 // JDC: commented out to remove warning
int ci;
jpeg_component_info *compptr;
#endif
/* Prevent application from calling me at wrong times */
if (cinfo->global_state != DSTATE_READY)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
#ifdef IDCT_SCALING_SUPPORTED
/* Compute actual output image dimensions and DCT scaling choices. */
if (cinfo->scale_num * 8 <= cinfo->scale_denom) {
/* Provide 1/8 scaling */
cinfo->output_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width, 8L);
cinfo->output_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, 8L);
cinfo->min_DCT_scaled_size = 1;
} else if (cinfo->scale_num * 4 <= cinfo->scale_denom) {
/* Provide 1/4 scaling */
cinfo->output_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width, 4L);
cinfo->output_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, 4L);
cinfo->min_DCT_scaled_size = 2;
} else if (cinfo->scale_num * 2 <= cinfo->scale_denom) {
/* Provide 1/2 scaling */
cinfo->output_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width, 2L);
cinfo->output_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height, 2L);
cinfo->min_DCT_scaled_size = 4;
} else {
/* Provide 1/1 scaling */
cinfo->output_width = cinfo->image_width;
cinfo->output_height = cinfo->image_height;
cinfo->min_DCT_scaled_size = DCTSIZE;
}
/* In selecting the actual DCT scaling for each component, we try to
* scale up the chroma components via IDCT scaling rather than upsampling.
* This saves time if the upsampler gets to use 1:1 scaling.
* Note this code assumes that the supported DCT scalings are powers of 2.
*/
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
int ssize = cinfo->min_DCT_scaled_size;
while (ssize < DCTSIZE &&
(compptr->h_samp_factor * ssize * 2 <=
cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) &&
(compptr->v_samp_factor * ssize * 2 <=
cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) {
ssize = ssize * 2;
}
compptr->DCT_scaled_size = ssize;
}
/* Recompute downsampled dimensions of components;
* application needs to know these if using raw downsampled data.
*/
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Size in samples, after IDCT scaling */
compptr->downsampled_width = (JDIMENSION)
jdiv_round_up((long) cinfo->image_width *
(long) (compptr->h_samp_factor * compptr->DCT_scaled_size),
(long) (cinfo->max_h_samp_factor * DCTSIZE));
compptr->downsampled_height = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height *
(long) (compptr->v_samp_factor * compptr->DCT_scaled_size),
(long) (cinfo->max_v_samp_factor * DCTSIZE));
}
#else /* !IDCT_SCALING_SUPPORTED */
/* Hardwire it to "no scaling" */
cinfo->output_width = cinfo->image_width;
cinfo->output_height = cinfo->image_height;
/* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
* and has computed unscaled downsampled_width and downsampled_height.
*/
#endif /* IDCT_SCALING_SUPPORTED */
/* Report number of components in selected colorspace. */
/* Probably this should be in the color conversion module... */
switch (cinfo->out_color_space) {
case JCS_GRAYSCALE:
cinfo->out_color_components = 1;
break;
case JCS_RGB:
#if RGB_PIXELSIZE != 3
cinfo->out_color_components = RGB_PIXELSIZE;
break;
#endif /* else share code with YCbCr */
case JCS_YCbCr:
cinfo->out_color_components = 3;
break;
case JCS_CMYK:
case JCS_YCCK:
cinfo->out_color_components = 4;
break;
default: /* else must be same colorspace as in file */
cinfo->out_color_components = cinfo->num_components;
break;
}
cinfo->output_components = (cinfo->quantize_colors ? 1 :
cinfo->out_color_components);
/* See if upsampler will want to emit more than one row at a time */
if (use_merged_upsample(cinfo))
cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;
else
cinfo->rec_outbuf_height = 1;
}
/*
* Several decompression processes need to range-limit values to the range
* 0..MAXJSAMPLE; the input value may fall somewhat outside this range
* due to noise introduced by quantization, roundoff error, etc. These
* processes are inner loops and need to be as fast as possible. On most
* machines, particularly CPUs with pipelines or instruction prefetch,
* a (subscript-check-less) C table lookup
* x = sample_range_limit[x];
* is faster than explicit tests
* if (x < 0) x = 0;
* else if (x > MAXJSAMPLE) x = MAXJSAMPLE;
* These processes all use a common table prepared by the routine below.
*
* For most steps we can mathematically guarantee that the initial value
* of x is within MAXJSAMPLE+1 of the legal range, so a table running from
* -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial
* limiting step (just after the IDCT), a wildly out-of-range value is
* possible if the input data is corrupt. To avoid any chance of indexing
* off the end of memory and getting a bad-pointer trap, we perform the
* post-IDCT limiting thus:
* x = range_limit[x & MASK];
* where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit
* samples. Under normal circumstances this is more than enough range and
* a correct output will be generated; with bogus input data the mask will
* cause wraparound, and we will safely generate a bogus-but-in-range output.
* For the post-IDCT step, we want to convert the data from signed to unsigned
* representation by adding CENTERJSAMPLE at the same time that we limit it.
* So the post-IDCT limiting table ends up looking like this:
* CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE,
* MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
* 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
* 0,1,...,CENTERJSAMPLE-1
* Negative inputs select values from the upper half of the table after
* masking.
*
* We can save some space by overlapping the start of the post-IDCT table
* with the simpler range limiting table. The post-IDCT table begins at
* sample_range_limit + CENTERJSAMPLE.
*
* Note that the table is allocated in near data space on PCs; it's small
* enough and used often enough to justify this.
*/
LOCAL void
prepare_range_limit_table (j_decompress_ptr cinfo)
/* Allocate and fill in the sample_range_limit table */
{
JSAMPLE * table;
int i;
table = (JSAMPLE *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE));
table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */
cinfo->sample_range_limit = table;
/* First segment of "simple" table: limit[x] = 0 for x < 0 */
MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
/* Main part of "simple" table: limit[x] = x */
for (i = 0; i <= MAXJSAMPLE; i++)
table[i] = (JSAMPLE) i;
table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
/* End of simple table, rest of first half of post-IDCT table */
for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++)
table[i] = MAXJSAMPLE;
/* Second half of post-IDCT table */
MEMZERO(table + (2 * (MAXJSAMPLE+1)),
(2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE));
MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE),
cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE));
}
/*
* Master selection of decompression modules.
* This is done once at jpeg_start_decompress time. We determine
* which modules will be used and give them appropriate initialization calls.
* We also initialize the decompressor input side to begin consuming data.
*
* Since jpeg_read_header has finished, we know what is in the SOF
* and (first) SOS markers. We also have all the application parameter
* settings.
*/
LOCAL void
master_selection (j_decompress_ptr cinfo)
{
my_master_ptr master = (my_master_ptr) cinfo->master;
boolean use_c_buffer;
long samplesperrow;
JDIMENSION jd_samplesperrow;
/* Initialize dimensions and other stuff */
jpeg_calc_output_dimensions(cinfo);
prepare_range_limit_table(cinfo);
/* Width of an output scanline must be representable as JDIMENSION. */
samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components;
jd_samplesperrow = (JDIMENSION) samplesperrow;
if ((long) jd_samplesperrow != samplesperrow)
ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
/* Initialize my private state */
master->pass_number = 0;
master->using_merged_upsample = use_merged_upsample(cinfo);
/* Color quantizer selection */
master->quantizer_1pass = NULL;
master->quantizer_2pass = NULL;
/* No mode changes if not using buffered-image mode. */
if (! cinfo->quantize_colors || ! cinfo->buffered_image) {
cinfo->enable_1pass_quant = FALSE;
cinfo->enable_external_quant = FALSE;
cinfo->enable_2pass_quant = FALSE;
}
if (cinfo->quantize_colors) {
if (cinfo->raw_data_out)
ERREXIT(cinfo, JERR_NOTIMPL);
/* 2-pass quantizer only works in 3-component color space. */
if (cinfo->out_color_components != 3) {
cinfo->enable_1pass_quant = TRUE;
cinfo->enable_external_quant = FALSE;
cinfo->enable_2pass_quant = FALSE;
cinfo->colormap = NULL;
} else if (cinfo->colormap != NULL) {
cinfo->enable_external_quant = TRUE;
} else if (cinfo->two_pass_quantize) {
cinfo->enable_2pass_quant = TRUE;
} else {
cinfo->enable_1pass_quant = TRUE;
}
if (cinfo->enable_1pass_quant) {
#ifdef QUANT_1PASS_SUPPORTED
jinit_1pass_quantizer(cinfo);
master->quantizer_1pass = cinfo->cquantize;
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
}
/* We use the 2-pass code to map to external colormaps. */
if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {
#ifdef QUANT_2PASS_SUPPORTED
jinit_2pass_quantizer(cinfo);
master->quantizer_2pass = cinfo->cquantize;
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
}
/* If both quantizers are initialized, the 2-pass one is left active;
* this is necessary for starting with quantization to an external map.
*/
}
/* Post-processing: in particular, color conversion first */
if (! cinfo->raw_data_out) {
if (master->using_merged_upsample) {
#ifdef UPSAMPLE_MERGING_SUPPORTED
jinit_merged_upsampler(cinfo); /* does color conversion too */
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
jinit_color_deconverter(cinfo);
jinit_upsampler(cinfo);
}
jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
}
/* Inverse DCT */
jinit_inverse_dct(cinfo);
/* Entropy decoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->progressive_mode) {
#ifdef D_PROGRESSIVE_SUPPORTED
jinit_phuff_decoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_huff_decoder(cinfo);
}
/* Initialize principal buffer controllers. */
use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
jinit_d_coef_controller(cinfo, use_c_buffer);
if (! cinfo->raw_data_out)
jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
/* We can now tell the memory manager to allocate virtual arrays. */
(*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
/* Initialize input side of decompressor to consume first scan. */
(*cinfo->inputctl->start_input_pass) (cinfo);
#ifdef D_MULTISCAN_FILES_SUPPORTED
/* If jpeg_start_decompress will read the whole file, initialize
* progress monitoring appropriately. The input step is counted
* as one pass.
*/
if (cinfo->progress != NULL && ! cinfo->buffered_image &&
cinfo->inputctl->has_multiple_scans) {
int nscans;
/* Estimate number of scans to set pass_limit. */
if (cinfo->progressive_mode) {
/* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
nscans = 2 + 3 * cinfo->num_components;
} else {
/* For a nonprogressive multiscan file, estimate 1 scan per component. */
nscans = cinfo->num_components;
}
cinfo->progress->pass_counter = 0L;
cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
cinfo->progress->completed_passes = 0;
cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2);
/* Count the input pass as done */
master->pass_number++;
}
#endif /* D_MULTISCAN_FILES_SUPPORTED */
}
/*
* Per-pass setup.
* This is called at the beginning of each output pass. We determine which
* modules will be active during this pass and give them appropriate
* start_pass calls. We also set is_dummy_pass to indicate whether this
* is a "real" output pass or a dummy pass for color quantization.
* (In the latter case, jdapi.c will crank the pass to completion.)
*/
METHODDEF void
prepare_for_output_pass (j_decompress_ptr cinfo)
{
my_master_ptr master = (my_master_ptr) cinfo->master;
if (master->pub.is_dummy_pass) {
#ifdef QUANT_2PASS_SUPPORTED
/* Final pass of 2-pass quantization */
master->pub.is_dummy_pass = FALSE;
(*cinfo->cquantize->start_pass) (cinfo, FALSE);
(*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST);
(*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif /* QUANT_2PASS_SUPPORTED */
} else {
if (cinfo->quantize_colors && cinfo->colormap == NULL) {
/* Select new quantization method */
if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {
cinfo->cquantize = master->quantizer_2pass;
master->pub.is_dummy_pass = TRUE;
} else if (cinfo->enable_1pass_quant) {
cinfo->cquantize = master->quantizer_1pass;
} else {
ERREXIT(cinfo, JERR_MODE_CHANGE);
}
}
(*cinfo->idct->start_pass) (cinfo);
(*cinfo->coef->start_output_pass) (cinfo);
if (! cinfo->raw_data_out) {
if (! master->using_merged_upsample)
(*cinfo->cconvert->start_pass) (cinfo);
(*cinfo->upsample->start_pass) (cinfo);
if (cinfo->quantize_colors)
(*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass);
(*cinfo->post->start_pass) (cinfo,
(master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
(*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
}
}
/* Set up progress monitor's pass info if present */
if (cinfo->progress != NULL) {
cinfo->progress->completed_passes = master->pass_number;
cinfo->progress->total_passes = master->pass_number +
(master->pub.is_dummy_pass ? 2 : 1);
/* In buffered-image mode, we assume one more output pass if EOI not
* yet reached, but no more passes if EOI has been reached.
*/
if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) {
cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1);
}
}
}
/*
* Finish up at end of an output pass.
*/
METHODDEF void
finish_output_pass (j_decompress_ptr cinfo)
{
my_master_ptr master = (my_master_ptr) cinfo->master;
if (cinfo->quantize_colors)
(*cinfo->cquantize->finish_pass) (cinfo);
master->pass_number++;
}
#ifdef D_MULTISCAN_FILES_SUPPORTED
/*
* Switch to a new external colormap between output passes.
*/
GLOBAL void
jpeg_new_colormap (j_decompress_ptr cinfo)
{
my_master_ptr master = (my_master_ptr) cinfo->master;
/* Prevent application from calling me at wrong times */
if (cinfo->global_state != DSTATE_BUFIMAGE)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->quantize_colors && cinfo->enable_external_quant &&
cinfo->colormap != NULL) {
/* Select 2-pass quantizer for external colormap use */
cinfo->cquantize = master->quantizer_2pass;
/* Notify quantizer of colormap change */
(*cinfo->cquantize->new_color_map) (cinfo);
master->pub.is_dummy_pass = FALSE; /* just in case */
} else
ERREXIT(cinfo, JERR_MODE_CHANGE);
}
#endif /* D_MULTISCAN_FILES_SUPPORTED */
/*
* Initialize master decompression control and select active modules.
* This is performed at the start of jpeg_start_decompress.
*/
GLOBAL void
jinit_master_decompress (j_decompress_ptr cinfo)
{
my_master_ptr master;
master = (my_master_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_decomp_master));
cinfo->master = (struct jpeg_decomp_master *) master;
master->pub.prepare_for_output_pass = prepare_for_output_pass;
master->pub.finish_output_pass = finish_output_pass;
master->pub.is_dummy_pass = FALSE;
master_selection(cinfo);
}

View File

@@ -0,0 +1,290 @@
/*
* jdpostct.c
*
* Copyright (C) 1994-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains the decompression postprocessing controller.
* This controller manages the upsampling, color conversion, and color
* quantization/reduction steps; specifically, it controls the buffering
* between upsample/color conversion and color quantization/reduction.
*
* If no color quantization/reduction is required, then this module has no
* work to do, and it just hands off to the upsample/color conversion code.
* An integrated upsample/convert/quantize process would replace this module
* entirely.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* Private buffer controller object */
typedef struct {
struct jpeg_d_post_controller pub; /* public fields */
/* Color quantization source buffer: this holds output data from
* the upsample/color conversion step to be passed to the quantizer.
* For two-pass color quantization, we need a full-image buffer;
* for one-pass operation, a strip buffer is sufficient.
*/
jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */
JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */
JDIMENSION strip_height; /* buffer size in rows */
/* for two-pass mode only: */
JDIMENSION starting_row; /* row # of first row in current strip */
JDIMENSION next_row; /* index of next row to fill/empty in strip */
} my_post_controller;
typedef my_post_controller * my_post_ptr;
/* Forward declarations */
METHODDEF void post_process_1pass
JPP((j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail));
#ifdef QUANT_2PASS_SUPPORTED
METHODDEF void post_process_prepass
JPP((j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail));
METHODDEF void post_process_2pass
JPP((j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail));
#endif
/*
* Initialize for a processing pass.
*/
METHODDEF void
start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
{
my_post_ptr post = (my_post_ptr) cinfo->post;
switch (pass_mode) {
case JBUF_PASS_THRU:
if (cinfo->quantize_colors) {
/* Single-pass processing with color quantization. */
post->pub.post_process_data = post_process_1pass;
/* We could be doing buffered-image output before starting a 2-pass
* color quantization; in that case, jinit_d_post_controller did not
* allocate a strip buffer. Use the virtual-array buffer as workspace.
*/
if (post->buffer == NULL) {
post->buffer = (*cinfo->mem->access_virt_sarray)
((j_common_ptr) cinfo, post->whole_image,
(JDIMENSION) 0, post->strip_height, TRUE);
}
} else {
/* For single-pass processing without color quantization,
* I have no work to do; just call the upsampler directly.
*/
post->pub.post_process_data = cinfo->upsample->upsample;
}
break;
#ifdef QUANT_2PASS_SUPPORTED
case JBUF_SAVE_AND_PASS:
/* First pass of 2-pass quantization */
if (post->whole_image == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
post->pub.post_process_data = post_process_prepass;
break;
case JBUF_CRANK_DEST:
/* Second pass of 2-pass quantization */
if (post->whole_image == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
post->pub.post_process_data = post_process_2pass;
break;
#endif /* QUANT_2PASS_SUPPORTED */
default:
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
break;
}
post->starting_row = post->next_row = 0;
}
/*
* Process some data in the one-pass (strip buffer) case.
* This is used for color precision reduction as well as one-pass quantization.
*/
METHODDEF void
post_process_1pass (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail)
{
my_post_ptr post = (my_post_ptr) cinfo->post;
JDIMENSION num_rows, max_rows;
/* Fill the buffer, but not more than what we can dump out in one go. */
/* Note we rely on the upsampler to detect bottom of image. */
max_rows = out_rows_avail - *out_row_ctr;
if (max_rows > post->strip_height)
max_rows = post->strip_height;
num_rows = 0;
(*cinfo->upsample->upsample) (cinfo,
input_buf, in_row_group_ctr, in_row_groups_avail,
post->buffer, &num_rows, max_rows);
/* Quantize and emit data. */
(*cinfo->cquantize->color_quantize) (cinfo,
post->buffer, output_buf + *out_row_ctr, (int) num_rows);
*out_row_ctr += num_rows;
}
#ifdef QUANT_2PASS_SUPPORTED
/*
* Process some data in the first pass of 2-pass quantization.
*/
METHODDEF void
post_process_prepass (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail)
{
my_post_ptr post = (my_post_ptr) cinfo->post;
JDIMENSION old_next_row, num_rows;
/* Reposition virtual buffer if at start of strip. */
if (post->next_row == 0) {
post->buffer = (*cinfo->mem->access_virt_sarray)
((j_common_ptr) cinfo, post->whole_image,
post->starting_row, post->strip_height, TRUE);
}
/* Upsample some data (up to a strip height's worth). */
old_next_row = post->next_row;
(*cinfo->upsample->upsample) (cinfo,
input_buf, in_row_group_ctr, in_row_groups_avail,
post->buffer, &post->next_row, post->strip_height);
/* Allow quantizer to scan new data. No data is emitted, */
/* but we advance out_row_ctr so outer loop can tell when we're done. */
if (post->next_row > old_next_row) {
num_rows = post->next_row - old_next_row;
(*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row,
(JSAMPARRAY) NULL, (int) num_rows);
*out_row_ctr += num_rows;
}
/* Advance if we filled the strip. */
if (post->next_row >= post->strip_height) {
post->starting_row += post->strip_height;
post->next_row = 0;
}
}
/*
* Process some data in the second pass of 2-pass quantization.
*/
METHODDEF void
post_process_2pass (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail)
{
my_post_ptr post = (my_post_ptr) cinfo->post;
JDIMENSION num_rows, max_rows;
/* Reposition virtual buffer if at start of strip. */
if (post->next_row == 0) {
post->buffer = (*cinfo->mem->access_virt_sarray)
((j_common_ptr) cinfo, post->whole_image,
post->starting_row, post->strip_height, FALSE);
}
/* Determine number of rows to emit. */
num_rows = post->strip_height - post->next_row; /* available in strip */
max_rows = out_rows_avail - *out_row_ctr; /* available in output area */
if (num_rows > max_rows)
num_rows = max_rows;
/* We have to check bottom of image here, can't depend on upsampler. */
max_rows = cinfo->output_height - post->starting_row;
if (num_rows > max_rows)
num_rows = max_rows;
/* Quantize and emit data. */
(*cinfo->cquantize->color_quantize) (cinfo,
post->buffer + post->next_row, output_buf + *out_row_ctr,
(int) num_rows);
*out_row_ctr += num_rows;
/* Advance if we filled the strip. */
post->next_row += num_rows;
if (post->next_row >= post->strip_height) {
post->starting_row += post->strip_height;
post->next_row = 0;
}
}
#endif /* QUANT_2PASS_SUPPORTED */
/*
* Initialize postprocessing controller.
*/
GLOBAL void
jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
{
my_post_ptr post;
post = (my_post_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_post_controller));
cinfo->post = (struct jpeg_d_post_controller *) post;
post->pub.start_pass = start_pass_dpost;
post->whole_image = NULL; /* flag for no virtual arrays */
post->buffer = NULL; /* flag for no strip buffer */
/* Create the quantization buffer, if needed */
if (cinfo->quantize_colors) {
/* The buffer strip height is max_v_samp_factor, which is typically
* an efficient number of rows for upsampling to return.
* (In the presence of output rescaling, we might want to be smarter?)
*/
post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor;
if (need_full_buffer) {
/* Two-pass color quantization: need full-image storage. */
/* We round up the number of rows to a multiple of the strip height. */
#ifdef QUANT_2PASS_SUPPORTED
post->whole_image = (*cinfo->mem->request_virt_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
cinfo->output_width * cinfo->out_color_components,
(JDIMENSION) jround_up((long) cinfo->output_height,
(long) post->strip_height),
post->strip_height);
#else
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
#endif /* QUANT_2PASS_SUPPORTED */
} else {
/* One-pass color quantization: just make a strip buffer. */
post->buffer = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE,
cinfo->output_width * cinfo->out_color_components,
post->strip_height);
}
}
}

View File

@@ -0,0 +1,478 @@
/*
* jdsample.c
*
* Copyright (C) 1991-1994, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains upsampling routines.
*
* Upsampling input data is counted in "row groups". A row group
* is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
* sample rows of each component. Upsampling will normally produce
* max_v_samp_factor pixel rows from each row group (but this could vary
* if the upsampler is applying a scale factor of its own).
*
* An excellent reference for image resampling is
* Digital Image Warping, George Wolberg, 1990.
* Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* Pointer to routine to upsample a single component */
typedef JMETHOD(void, upsample1_ptr,
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr));
/* Private subobject */
typedef struct {
struct jpeg_upsampler pub; /* public fields */
/* Color conversion buffer. When using separate upsampling and color
* conversion steps, this buffer holds one upsampled row group until it
* has been color converted and output.
* Note: we do not allocate any storage for component(s) which are full-size,
* ie do not need rescaling. The corresponding entry of color_buf[] is
* simply set to point to the input data array, thereby avoiding copying.
*/
JSAMPARRAY color_buf[MAX_COMPONENTS];
/* Per-component upsampling method pointers */
upsample1_ptr methods[MAX_COMPONENTS];
int next_row_out; /* counts rows emitted from color_buf */
JDIMENSION rows_to_go; /* counts rows remaining in image */
/* Height of an input row group for each component. */
int rowgroup_height[MAX_COMPONENTS];
/* These arrays save pixel expansion factors so that int_expand need not
* recompute them each time. They are unused for other upsampling methods.
*/
UINT8 h_expand[MAX_COMPONENTS];
UINT8 v_expand[MAX_COMPONENTS];
} my_upsampler;
typedef my_upsampler * my_upsample_ptr;
/*
* Initialize for an upsampling pass.
*/
METHODDEF void
start_pass_upsample (j_decompress_ptr cinfo)
{
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
/* Mark the conversion buffer empty */
upsample->next_row_out = cinfo->max_v_samp_factor;
/* Initialize total-height counter for detecting bottom of image */
upsample->rows_to_go = cinfo->output_height;
}
/*
* Control routine to do upsampling (and color conversion).
*
* In this version we upsample each component independently.
* We upsample one row group into the conversion buffer, then apply
* color conversion a row at a time.
*/
METHODDEF void
sep_upsample (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail)
{
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
int ci;
jpeg_component_info * compptr;
JDIMENSION num_rows;
/* Fill the conversion buffer, if it's empty */
if (upsample->next_row_out >= cinfo->max_v_samp_factor) {
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Invoke per-component upsample method. Notice we pass a POINTER
* to color_buf[ci], so that fullsize_upsample can change it.
*/
(*upsample->methods[ci]) (cinfo, compptr,
input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]),
upsample->color_buf + ci);
}
upsample->next_row_out = 0;
}
/* Color-convert and emit rows */
/* How many we have in the buffer: */
num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out);
/* Not more than the distance to the end of the image. Need this test
* in case the image height is not a multiple of max_v_samp_factor:
*/
if (num_rows > upsample->rows_to_go)
num_rows = upsample->rows_to_go;
/* And not more than what the client can accept: */
out_rows_avail -= *out_row_ctr;
if (num_rows > out_rows_avail)
num_rows = out_rows_avail;
(*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf,
(JDIMENSION) upsample->next_row_out,
output_buf + *out_row_ctr,
(int) num_rows);
/* Adjust counts */
*out_row_ctr += num_rows;
upsample->rows_to_go -= num_rows;
upsample->next_row_out += num_rows;
/* When the buffer is emptied, declare this input row group consumed */
if (upsample->next_row_out >= cinfo->max_v_samp_factor)
(*in_row_group_ctr)++;
}
/*
* These are the routines invoked by sep_upsample to upsample pixel values
* of a single component. One row group is processed per call.
*/
/*
* For full-size components, we just make color_buf[ci] point at the
* input buffer, and thus avoid copying any data. Note that this is
* safe only because sep_upsample doesn't declare the input row group
* "consumed" until we are done color converting and emitting it.
*/
METHODDEF void
fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
{
*output_data_ptr = input_data;
}
/*
* This is a no-op version used for "uninteresting" components.
* These components will not be referenced by color conversion.
*/
METHODDEF void
noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
{
*output_data_ptr = NULL; /* safety check */
}
/*
* This version handles any integral sampling ratios.
* This is not used for typical JPEG files, so it need not be fast.
* Nor, for that matter, is it particularly accurate: the algorithm is
* simple replication of the input pixel onto the corresponding output
* pixels. The hi-falutin sampling literature refers to this as a
* "box filter". A box filter tends to introduce visible artifacts,
* so if you are actually going to use 3:1 or 4:1 sampling ratios
* you would be well advised to improve this code.
*/
METHODDEF void
int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
{
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
JSAMPARRAY output_data = *output_data_ptr;
register JSAMPROW inptr, outptr;
register JSAMPLE invalue;
register int h;
JSAMPROW outend;
int h_expand, v_expand;
int inrow, outrow;
h_expand = upsample->h_expand[compptr->component_index];
v_expand = upsample->v_expand[compptr->component_index];
inrow = outrow = 0;
while (outrow < cinfo->max_v_samp_factor) {
/* Generate one output row with proper horizontal expansion */
inptr = input_data[inrow];
outptr = output_data[outrow];
outend = outptr + cinfo->output_width;
while (outptr < outend) {
invalue = *inptr++; /* don't need GETJSAMPLE() here */
for (h = h_expand; h > 0; h--) {
*outptr++ = invalue;
}
}
/* Generate any additional output rows by duplicating the first one */
if (v_expand > 1) {
jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
v_expand-1, cinfo->output_width);
}
inrow++;
outrow += v_expand;
}
}
/*
* Fast processing for the common case of 2:1 horizontal and 1:1 vertical.
* It's still a box filter.
*/
METHODDEF void
h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
{
JSAMPARRAY output_data = *output_data_ptr;
register JSAMPROW inptr, outptr;
register JSAMPLE invalue;
JSAMPROW outend;
int inrow;
for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
inptr = input_data[inrow];
outptr = output_data[inrow];
outend = outptr + cinfo->output_width;
while (outptr < outend) {
invalue = *inptr++; /* don't need GETJSAMPLE() here */
*outptr++ = invalue;
*outptr++ = invalue;
}
}
}
/*
* Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
* It's still a box filter.
*/
METHODDEF void
h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
{
JSAMPARRAY output_data = *output_data_ptr;
register JSAMPROW inptr, outptr;
register JSAMPLE invalue;
JSAMPROW outend;
int inrow, outrow;
inrow = outrow = 0;
while (outrow < cinfo->max_v_samp_factor) {
inptr = input_data[inrow];
outptr = output_data[outrow];
outend = outptr + cinfo->output_width;
while (outptr < outend) {
invalue = *inptr++; /* don't need GETJSAMPLE() here */
*outptr++ = invalue;
*outptr++ = invalue;
}
jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
1, cinfo->output_width);
inrow++;
outrow += 2;
}
}
/*
* Fancy processing for the common case of 2:1 horizontal and 1:1 vertical.
*
* The upsampling algorithm is linear interpolation between pixel centers,
* also known as a "triangle filter". This is a good compromise between
* speed and visual quality. The centers of the output pixels are 1/4 and 3/4
* of the way between input pixel centers.
*
* A note about the "bias" calculations: when rounding fractional values to
* integer, we do not want to always round 0.5 up to the next integer.
* If we did that, we'd introduce a noticeable bias towards larger values.
* Instead, this code is arranged so that 0.5 will be rounded up or down at
* alternate pixel locations (a simple ordered dither pattern).
*/
METHODDEF void
h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
{
JSAMPARRAY output_data = *output_data_ptr;
register JSAMPROW inptr, outptr;
register int invalue;
register JDIMENSION colctr;
int inrow;
for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
inptr = input_data[inrow];
outptr = output_data[inrow];
/* Special case for first column */
invalue = GETJSAMPLE(*inptr++);
*outptr++ = (JSAMPLE) invalue;
*outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2);
for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
/* General case: 3/4 * nearer pixel + 1/4 * further pixel */
invalue = GETJSAMPLE(*inptr++) * 3;
*outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2);
*outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2);
}
/* Special case for last column */
invalue = GETJSAMPLE(*inptr);
*outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2);
*outptr++ = (JSAMPLE) invalue;
}
}
/*
* Fancy processing for the common case of 2:1 horizontal and 2:1 vertical.
* Again a triangle filter; see comments for h2v1 case, above.
*
* It is OK for us to reference the adjacent input rows because we demanded
* context from the main buffer controller (see initialization code).
*/
METHODDEF void
h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
{
JSAMPARRAY output_data = *output_data_ptr;
register JSAMPROW inptr0, inptr1, outptr;
#if BITS_IN_JSAMPLE == 8
register int thiscolsum, lastcolsum, nextcolsum;
#else
register INT32 thiscolsum, lastcolsum, nextcolsum;
#endif
register JDIMENSION colctr;
int inrow, outrow, v;
inrow = outrow = 0;
while (outrow < cinfo->max_v_samp_factor) {
for (v = 0; v < 2; v++) {
/* inptr0 points to nearest input row, inptr1 points to next nearest */
inptr0 = input_data[inrow];
if (v == 0) /* next nearest is row above */
inptr1 = input_data[inrow-1];
else /* next nearest is row below */
inptr1 = input_data[inrow+1];
outptr = output_data[outrow++];
/* Special case for first column */
thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
*outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4);
*outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4);
lastcolsum = thiscolsum; thiscolsum = nextcolsum;
for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
/* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */
/* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */
nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++);
*outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4);
*outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4);
lastcolsum = thiscolsum; thiscolsum = nextcolsum;
}
/* Special case for last column */
*outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4);
*outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4);
}
inrow++;
}
}
/*
* Module initialization routine for upsampling.
*/
GLOBAL void
jinit_upsampler (j_decompress_ptr cinfo)
{
my_upsample_ptr upsample;
int ci;
jpeg_component_info * compptr;
boolean need_buffer, do_fancy;
int h_in_group, v_in_group, h_out_group, v_out_group;
upsample = (my_upsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
SIZEOF(my_upsampler));
cinfo->upsample = (struct jpeg_upsampler *) upsample;
upsample->pub.start_pass = start_pass_upsample;
upsample->pub.upsample = sep_upsample;
upsample->pub.need_context_rows = FALSE; /* until we find out differently */
if (cinfo->CCIR601_sampling) /* this isn't supported */
ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
/* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1,
* so don't ask for it.
*/
do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1;
/* Verify we can handle the sampling factors, select per-component methods,
* and create storage as needed.
*/
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Compute size of an "input group" after IDCT scaling. This many samples
* are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
*/
h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_DCT_scaled_size;
v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
cinfo->min_DCT_scaled_size;
h_out_group = cinfo->max_h_samp_factor;
v_out_group = cinfo->max_v_samp_factor;
upsample->rowgroup_height[ci] = v_in_group; /* save for use later */
need_buffer = TRUE;
if (! compptr->component_needed) {
/* Don't bother to upsample an uninteresting component. */
upsample->methods[ci] = noop_upsample;
need_buffer = FALSE;
} else if (h_in_group == h_out_group && v_in_group == v_out_group) {
/* Fullsize components can be processed without any work. */
upsample->methods[ci] = fullsize_upsample;
need_buffer = FALSE;
} else if (h_in_group * 2 == h_out_group &&
v_in_group == v_out_group) {
/* Special cases for 2h1v upsampling */
if (do_fancy && compptr->downsampled_width > 2)
upsample->methods[ci] = h2v1_fancy_upsample;
else
upsample->methods[ci] = h2v1_upsample;
} else if (h_in_group * 2 == h_out_group &&
v_in_group * 2 == v_out_group) {
/* Special cases for 2h2v upsampling */
if (do_fancy && compptr->downsampled_width > 2) {
upsample->methods[ci] = h2v2_fancy_upsample;
upsample->pub.need_context_rows = TRUE;
} else
upsample->methods[ci] = h2v2_upsample;
} else if ((h_out_group % h_in_group) == 0 &&
(v_out_group % v_in_group) == 0) {
/* Generic integral-factors upsampling method */
upsample->methods[ci] = int_upsample;
upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group);
upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group);
} else
ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
if (need_buffer) {
upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE,
(JDIMENSION) jround_up((long) cinfo->output_width,
(long) cinfo->max_h_samp_factor),
(JDIMENSION) cinfo->max_v_samp_factor);
}
}
}

View File

@@ -0,0 +1,122 @@
/*
* jdtrans.c
*
* Copyright (C) 1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains library routines for transcoding decompression,
* that is, reading raw DCT coefficient arrays from an input JPEG file.
* The routines in jdapimin.c will also be needed by a transcoder.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/* Forward declarations */
LOCAL void transdecode_master_selection JPP((j_decompress_ptr cinfo));
/*
* Read the coefficient arrays from a JPEG file.
* jpeg_read_header must be completed before calling this.
*
* The entire image is read into a set of virtual coefficient-block arrays,
* one per component. The return value is a pointer to the array of
* virtual-array descriptors. These can be manipulated directly via the
* JPEG memory manager, or handed off to jpeg_write_coefficients().
* To release the memory occupied by the virtual arrays, call
* jpeg_finish_decompress() when done with the data.
*
* Returns NULL if suspended. This case need be checked only if
* a suspending data source is used.
*/
GLOBAL jvirt_barray_ptr *
jpeg_read_coefficients (j_decompress_ptr cinfo)
{
if (cinfo->global_state == DSTATE_READY) {
/* First call: initialize active modules */
transdecode_master_selection(cinfo);
cinfo->global_state = DSTATE_RDCOEFS;
} else if (cinfo->global_state != DSTATE_RDCOEFS)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
/* Absorb whole file into the coef buffer */
for (;;) {
int retcode;
/* Call progress monitor hook if present */
if (cinfo->progress != NULL)
(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
/* Absorb some more input */
retcode = (*cinfo->inputctl->consume_input) (cinfo);
if (retcode == JPEG_SUSPENDED)
return NULL;
if (retcode == JPEG_REACHED_EOI)
break;
/* Advance progress counter if appropriate */
if (cinfo->progress != NULL &&
(retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
/* startup underestimated number of scans; ratchet up one scan */
cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
}
}
}
/* Set state so that jpeg_finish_decompress does the right thing */
cinfo->global_state = DSTATE_STOPPING;
return cinfo->coef->coef_arrays;
}
/*
* Master selection of decompression modules for transcoding.
* This substitutes for jdmaster.c's initialization of the full decompressor.
*/
LOCAL void
transdecode_master_selection (j_decompress_ptr cinfo)
{
/* Entropy decoding: either Huffman or arithmetic coding. */
if (cinfo->arith_code) {
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
} else {
if (cinfo->progressive_mode) {
#ifdef D_PROGRESSIVE_SUPPORTED
jinit_phuff_decoder(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else
jinit_huff_decoder(cinfo);
}
/* Always get a full-image coefficient buffer. */
jinit_d_coef_controller(cinfo, TRUE);
/* We can now tell the memory manager to allocate virtual arrays. */
(*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
/* Initialize input side of decompressor to consume first scan. */
(*cinfo->inputctl->start_input_pass) (cinfo);
/* Initialize progress monitoring. */
if (cinfo->progress != NULL) {
int nscans;
/* Estimate number of scans to set pass_limit. */
if (cinfo->progressive_mode) {
/* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
nscans = 2 + 3 * cinfo->num_components;
} else if (cinfo->inputctl->has_multiple_scans) {
/* For a nonprogressive multiscan file, estimate 1 scan per component. */
nscans = cinfo->num_components;
} else {
nscans = 1;
}
cinfo->progress->pass_counter = 0L;
cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
cinfo->progress->completed_passes = 0;
cinfo->progress->total_passes = 1;
}
}

View File

@@ -0,0 +1,240 @@
/*
* jerror.c
*
* Copyright (C) 1991-1994, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains simple error-reporting and trace-message routines.
* These are suitable for Unix-like systems and others where writing to
* stderr is the right thing to do. Many applications will want to replace
* some or all of these routines.
*
* These routines are used by both the compression and decompression code.
*/
/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
#include "jinclude.h"
#include "jpeglib.h"
#include "jversion.h"
#include "jerror.h"
#ifndef EXIT_FAILURE /* define exit() codes if not provided */
#define EXIT_FAILURE 1
#endif
/*
* Create the message string table.
* We do this from the master message list in jerror.h by re-reading
* jerror.h with a suitable definition for macro JMESSAGE.
* The message table is made an external symbol just in case any applications
* want to refer to it directly.
*/
#ifdef NEED_SHORT_EXTERNAL_NAMES
#define jpeg_std_message_table jMsgTable
#endif
#define JMESSAGE(code,string) string ,
const char * const jpeg_std_message_table[] = {
#include "jerror.h"
NULL
};
/*
* Error exit handler: must not return to caller.
*
* Applications may override this if they want to get control back after
* an error. Typically one would longjmp somewhere instead of exiting.
* The setjmp buffer can be made a private field within an expanded error
* handler object. Note that the info needed to generate an error message
* is stored in the error object, so you can generate the message now or
* later, at your convenience.
* You should make sure that the JPEG object is cleaned up (with jpeg_abort
* or jpeg_destroy) at some point.
*/
METHODDEF void
error_exit (j_common_ptr cinfo)
{
char buffer[JMSG_LENGTH_MAX];
/* Create the message */
(*cinfo->err->format_message) (cinfo, buffer);
/* Let the memory manager delete any temp files before we die */
jpeg_destroy(cinfo);
// -slc
#if 0
ri.Error( ERR_FATAL, "%s\n", buffer );
#else
ERROR_STRING_NO_RETURN(buffer);
#endif
}
/*
* Actual output of an error or trace message.
* Applications may override this method to send JPEG messages somewhere
* other than stderr.
*/
METHODDEF void
output_message (j_common_ptr cinfo)
{
char buffer[JMSG_LENGTH_MAX];
/* Create the message */
(*cinfo->err->format_message) (cinfo, buffer);
// -slc
#if 0
/* Send it to stderr, adding a newline */
ri.Printf(PRINT_ALL, "%s\n", buffer);
#else
MESSAGE_STRING(buffer);
#endif
}
/*
* Decide whether to emit a trace or warning message.
* msg_level is one of:
* -1: recoverable corrupt-data warning, may want to abort.
* 0: important advisory messages (always display to user).
* 1: first level of tracing detail.
* 2,3,...: successively more detailed tracing messages.
* An application might override this method if it wanted to abort on warnings
* or change the policy about which messages to display.
*/
METHODDEF void
emit_message (j_common_ptr cinfo, int msg_level)
{
struct jpeg_error_mgr * err = cinfo->err;
if (msg_level < 0) {
/* It's a warning message. Since corrupt files may generate many warnings,
* the policy implemented here is to show only the first warning,
* unless trace_level >= 3.
*/
if (err->num_warnings == 0 || err->trace_level >= 3)
(*err->output_message) (cinfo);
/* Always count warnings in num_warnings. */
err->num_warnings++;
} else {
/* It's a trace message. Show it if trace_level >= msg_level. */
if (err->trace_level >= msg_level)
(*err->output_message) (cinfo);
}
}
/*
* Format a message string for the most recent JPEG error or message.
* The message is stored into buffer, which should be at least JMSG_LENGTH_MAX
* characters. Note that no '\n' character is added to the string.
* Few applications should need to override this method.
*/
METHODDEF void
format_message (j_common_ptr cinfo, char * buffer)
{
struct jpeg_error_mgr * err = cinfo->err;
int msg_code = err->msg_code;
const char * msgtext = NULL;
const char * msgptr;
char ch;
boolean isstring;
/* Look up message string in proper table */
if (msg_code > 0 && msg_code <= err->last_jpeg_message) {
msgtext = err->jpeg_message_table[msg_code];
} else if (err->addon_message_table != NULL &&
msg_code >= err->first_addon_message &&
msg_code <= err->last_addon_message) {
msgtext = err->addon_message_table[msg_code - err->first_addon_message];
}
/* Defend against bogus message number */
if (msgtext == NULL) {
err->msg_parm.i[0] = msg_code;
msgtext = err->jpeg_message_table[0];
}
/* Check for string parameter, as indicated by %s in the message text */
isstring = FALSE;
msgptr = msgtext;
while ((ch = *msgptr++) != '\0') {
if (ch == '%') {
if (*msgptr == 's') isstring = TRUE;
break;
}
}
/* Format the message into the passed buffer */
if (isstring)
sprintf(buffer, msgtext, err->msg_parm.s);
else
sprintf(buffer, msgtext,
err->msg_parm.i[0], err->msg_parm.i[1],
err->msg_parm.i[2], err->msg_parm.i[3],
err->msg_parm.i[4], err->msg_parm.i[5],
err->msg_parm.i[6], err->msg_parm.i[7]);
}
/*
* Reset error state variables at start of a new image.
* This is called during compression startup to reset trace/error
* processing to default state, without losing any application-specific
* method pointers. An application might possibly want to override
* this method if it has additional error processing state.
*/
METHODDEF void
reset_error_mgr (j_common_ptr cinfo)
{
cinfo->err->num_warnings = 0;
/* trace_level is not reset since it is an application-supplied parameter */
cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */
}
/*
* Fill in the standard error-handling methods in a jpeg_error_mgr object.
* Typical call is:
* struct jpeg_compress_struct cinfo;
* struct jpeg_error_mgr err;
*
* cinfo.err = jpeg_std_error(&err);
* after which the application may override some of the methods.
*/
GLOBAL struct jpeg_error_mgr *
jpeg_std_error (struct jpeg_error_mgr * err)
{
err->error_exit = error_exit;
err->emit_message = emit_message;
err->output_message = output_message;
err->format_message = format_message;
err->reset_error_mgr = reset_error_mgr;
err->trace_level = 0; /* default = no tracing */
err->num_warnings = 0; /* no warnings emitted yet */
err->msg_code = 0; /* may be useful as a flag for "no error" */
/* Initialize message table pointers */
err->jpeg_message_table = jpeg_std_message_table;
err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;
err->addon_message_table = NULL;
err->first_addon_message = 0; /* for safety */
err->last_addon_message = 0;
return err;
}

View File

@@ -0,0 +1,273 @@
/*
* jerror.h
*
* Copyright (C) 1994-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file defines the error and message codes for the JPEG library.
* Edit this file to add new codes, or to translate the message strings to
* some other language.
* A set of error-reporting macros are defined too. Some applications using
* the JPEG library may wish to include this file to get the error codes
* and/or the macros.
*/
/*
* To define the enum list of message codes, include this file without
* defining macro JMESSAGE. To create a message string table, include it
* again with a suitable JMESSAGE definition (see jerror.c for an example).
*/
#ifndef JMESSAGE
#ifndef JERROR_H
/* First time through, define the enum list */
#define JMAKE_ENUM_LIST
#else
/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
#define JMESSAGE(code,string)
#endif /* JERROR_H */
#endif /* JMESSAGE */
#ifdef JMAKE_ENUM_LIST
typedef enum {
#define JMESSAGE(code,string) code ,
#endif /* JMAKE_ENUM_LIST */
JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */
/* For maintenance convenience, list is alphabetical by message code name */
JMESSAGE(JERR_ARITH_NOTIMPL,
"Sorry, there are legal restrictions on arithmetic coding")
JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length")
JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan")
JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
JMESSAGE(JERR_BAD_PROGRESSION,
"Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d")
JMESSAGE(JERR_BAD_PROG_SCRIPT,
"Invalid progressive parameters at scan script entry %d")
JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access")
JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small")
JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here")
JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet")
JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d")
JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request")
JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d")
JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x")
JMESSAGE(JERR_DHT_COUNTS, "Bogus DHT counts")
JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d")
JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d")
JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)")
JMESSAGE(JERR_EMS_READ, "Read from EMS failed")
JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed")
JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan")
JMESSAGE(JERR_FILE_READ, "Input file read error")
JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?")
JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet")
JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow")
JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry")
JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels")
JMESSAGE(JERR_INPUT_EMPTY, "Empty input file")
JMESSAGE(JERR_INPUT_EOF, "Premature end of input file")
JMESSAGE(JERR_MISMATCHED_QUANT_TABLE,
"Cannot transcode due to multiple use of quantization table %d")
JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data")
JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change")
JMESSAGE(JERR_NOTIMPL, "Not implemented yet")
JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x")
JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)")
JMESSAGE(JERR_QUANT_COMPONENTS,
"Cannot quantize more than %d color components")
JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors")
JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors")
JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers")
JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker")
JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x")
JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers")
JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF")
JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s")
JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file")
JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file")
JMESSAGE(JERR_TFILE_WRITE,
"Write failed on temporary file --- out of disk space?")
JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines")
JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x")
JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up")
JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation")
JMESSAGE(JERR_XMS_READ, "Read from XMS failed")
JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed")
JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT)
JMESSAGE(JMSG_VERSION, JVERSION)
JMESSAGE(JTRC_16BIT_TABLES,
"Caution: quantization tables are too coarse for baseline JPEG")
JMESSAGE(JTRC_ADOBE,
"Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d")
JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u")
JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u")
JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x")
JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x")
JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d")
JMESSAGE(JTRC_DRI, "Define Restart Interval %u")
JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u")
JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u")
JMESSAGE(JTRC_EOI, "End Of Image")
JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d")
JMESSAGE(JTRC_JFIF, "JFIF APP0 marker, density %dx%d %d")
JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE,
"Warning: thumbnail image size does not match data length %u")
JMESSAGE(JTRC_JFIF_MINOR, "Unknown JFIF minor revision number %d.%02d")
JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image")
JMESSAGE(JTRC_MISC_MARKER, "Skipping marker 0x%02x, length %u")
JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x")
JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u")
JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors")
JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors")
JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization")
JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d")
JMESSAGE(JTRC_RST, "RST%d")
JMESSAGE(JTRC_SMOOTH_NOTIMPL,
"Smoothing not supported with nonstandard sampling ratios")
JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d")
JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d")
JMESSAGE(JTRC_SOI, "Start of Image")
JMESSAGE(JTRC_SOS, "Start Of Scan: %d components")
JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d")
JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d")
JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s")
JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s")
JMESSAGE(JTRC_UNKNOWN_IDS,
"Unrecognized component IDs %d %d %d, assuming YCbCr")
JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
JMESSAGE(JWRN_BOGUS_PROGRESSION,
"Inconsistent progression sequence for component %d coefficient %d")
JMESSAGE(JWRN_EXTRANEOUS_DATA,
"Corrupt JPEG data: %u extraneous bytes before marker 0x%02x")
JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment")
JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code")
JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d")
JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file")
JMESSAGE(JWRN_MUST_RESYNC,
"Corrupt JPEG data: found marker 0x%02x instead of RST%d")
JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG")
JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")
#ifdef JMAKE_ENUM_LIST
JMSG_LASTMSGCODE
} J_MESSAGE_CODE;
#undef JMAKE_ENUM_LIST
#endif /* JMAKE_ENUM_LIST */
/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
#undef JMESSAGE
#ifndef JERROR_H
#define JERROR_H
/* Macros to simplify using the error and trace message stuff */
/* The first parameter is either type of cinfo pointer */
/* Fatal errors (print message and exit) */
#define ERREXIT(cinfo,code) \
((cinfo)->err->msg_code = (code), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define ERREXIT1(cinfo,code,p1) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define ERREXIT2(cinfo,code,p1,p2) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(cinfo)->err->msg_parm.i[1] = (p2), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define ERREXIT3(cinfo,code,p1,p2,p3) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(cinfo)->err->msg_parm.i[1] = (p2), \
(cinfo)->err->msg_parm.i[2] = (p3), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(cinfo)->err->msg_parm.i[1] = (p2), \
(cinfo)->err->msg_parm.i[2] = (p3), \
(cinfo)->err->msg_parm.i[3] = (p4), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define ERREXITS(cinfo,code,str) \
((cinfo)->err->msg_code = (code), \
strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
(*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
#define MAKESTMT(stuff) do { stuff } while (0)
/* Nonfatal errors (we can keep going, but the data is probably corrupt) */
#define WARNMS(cinfo,code) \
((cinfo)->err->msg_code = (code), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
#define WARNMS1(cinfo,code,p1) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
#define WARNMS2(cinfo,code,p1,p2) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(cinfo)->err->msg_parm.i[1] = (p2), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
/* Informational/debugging messages */
#define TRACEMS(cinfo,lvl,code) \
((cinfo)->err->msg_code = (code), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
#define TRACEMS1(cinfo,lvl,code,p1) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
#define TRACEMS2(cinfo,lvl,code,p1,p2) \
((cinfo)->err->msg_code = (code), \
(cinfo)->err->msg_parm.i[0] = (p1), \
(cinfo)->err->msg_parm.i[1] = (p2), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \
MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
_mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \
(cinfo)->err->msg_code = (code); \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \
MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
_mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
(cinfo)->err->msg_code = (code); \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \
MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
_mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
_mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \
(cinfo)->err->msg_code = (code); \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
#define TRACEMSS(cinfo,lvl,code,str) \
((cinfo)->err->msg_code = (code), \
strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
(*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
#endif /* JERROR_H */

View File

@@ -0,0 +1,241 @@
/*
* jidctflt.c
*
* Copyright (C) 1994, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains a floating-point implementation of the
* inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
* must also perform dequantization of the input coefficients.
*
* This implementation should be more accurate than either of the integer
* IDCT implementations. However, it may not give the same results on all
* machines because of differences in roundoff behavior. Speed will depend
* on the hardware's floating point capacity.
*
* A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
* on each row (or vice versa, but it's more convenient to emit a row at
* a time). Direct algorithms are also available, but they are much more
* complex and seem not to be any faster when reduced to code.
*
* This implementation is based on Arai, Agui, and Nakajima's algorithm for
* scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
* Japanese, but the algorithm is described in the Pennebaker & Mitchell
* JPEG textbook (see REFERENCES section in file README). The following code
* is based directly on figure 4-8 in P&M.
* While an 8-point DCT cannot be done in less than 11 multiplies, it is
* possible to arrange the computation so that many of the multiplies are
* simple scalings of the final outputs. These multiplies can then be
* folded into the multiplications or divisions by the JPEG quantization
* table entries. The AA&N method leaves only 5 multiplies and 29 adds
* to be done in the DCT itself.
* The primary disadvantage of this method is that with a fixed-point
* implementation, accuracy is lost due to imprecise representation of the
* scaled quantization values. However, that problem does not arise if
* we use floating point arithmetic.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jdct.h" /* Private declarations for DCT subsystem */
#ifdef DCT_FLOAT_SUPPORTED
/*
* This module is specialized to the case DCTSIZE = 8.
*/
#if DCTSIZE != 8
Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
#endif
/* Dequantize a coefficient by multiplying it by the multiplier-table
* entry; produce a float result.
*/
#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval))
/*
* Perform dequantization and inverse DCT on one block of coefficients.
*/
GLOBAL void
jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JCOEFPTR coef_block,
JSAMPARRAY output_buf, JDIMENSION output_col)
{
FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
FAST_FLOAT z5, z10, z11, z12, z13;
JCOEFPTR inptr;
FLOAT_MULT_TYPE * quantptr;
FAST_FLOAT * wsptr;
JSAMPROW outptr;
JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
SHIFT_TEMPS
/* Pass 1: process columns from input, store into work array. */
inptr = coef_block;
quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table;
wsptr = workspace;
for (ctr = DCTSIZE; ctr > 0; ctr--) {
/* Due to quantization, we will usually find that many of the input
* coefficients are zero, especially the AC terms. We can exploit this
* by short-circuiting the IDCT calculation for any column in which all
* the AC terms are zero. In that case each output is equal to the
* DC coefficient (with scale factor as needed).
* With typical images and quantization tables, half or more of the
* column DCT calculations can be simplified this way.
*/
if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] |
inptr[DCTSIZE*4] | inptr[DCTSIZE*5] | inptr[DCTSIZE*6] |
inptr[DCTSIZE*7]) == 0) {
/* AC terms all zero */
FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
wsptr[DCTSIZE*0] = dcval;
wsptr[DCTSIZE*1] = dcval;
wsptr[DCTSIZE*2] = dcval;
wsptr[DCTSIZE*3] = dcval;
wsptr[DCTSIZE*4] = dcval;
wsptr[DCTSIZE*5] = dcval;
wsptr[DCTSIZE*6] = dcval;
wsptr[DCTSIZE*7] = dcval;
inptr++; /* advance pointers to next column */
quantptr++;
wsptr++;
continue;
}
/* Even part */
tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
tmp10 = tmp0 + tmp2; /* phase 3 */
tmp11 = tmp0 - tmp2;
tmp13 = tmp1 + tmp3; /* phases 5-3 */
tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
tmp0 = tmp10 + tmp13; /* phase 2 */
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
/* Odd part */
tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
z13 = tmp6 + tmp5; /* phase 6 */
z10 = tmp6 - tmp5;
z11 = tmp4 + tmp7;
z12 = tmp4 - tmp7;
tmp7 = z11 + z13; /* phase 5 */
tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
tmp6 = tmp12 - tmp7; /* phase 2 */
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
wsptr[DCTSIZE*0] = tmp0 + tmp7;
wsptr[DCTSIZE*7] = tmp0 - tmp7;
wsptr[DCTSIZE*1] = tmp1 + tmp6;
wsptr[DCTSIZE*6] = tmp1 - tmp6;
wsptr[DCTSIZE*2] = tmp2 + tmp5;
wsptr[DCTSIZE*5] = tmp2 - tmp5;
wsptr[DCTSIZE*4] = tmp3 + tmp4;
wsptr[DCTSIZE*3] = tmp3 - tmp4;
inptr++; /* advance pointers to next column */
quantptr++;
wsptr++;
}
/* Pass 2: process rows from work array, store into output array. */
/* Note that we must descale the results by a factor of 8 == 2**3. */
wsptr = workspace;
for (ctr = 0; ctr < DCTSIZE; ctr++) {
outptr = output_buf[ctr] + output_col;
/* Rows of zeroes can be exploited in the same way as we did with columns.
* However, the column calculation has created many nonzero AC terms, so
* the simplification applies less often (typically 5% to 10% of the time).
* And testing floats for zero is relatively expensive, so we don't bother.
*/
/* Even part */
tmp10 = wsptr[0] + wsptr[4];
tmp11 = wsptr[0] - wsptr[4];
tmp13 = wsptr[2] + wsptr[6];
tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
tmp0 = tmp10 + tmp13;
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
/* Odd part */
z13 = wsptr[5] + wsptr[3];
z10 = wsptr[5] - wsptr[3];
z11 = wsptr[1] + wsptr[7];
z12 = wsptr[1] - wsptr[7];
tmp7 = z11 + z13;
tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
tmp6 = tmp12 - tmp7;
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
/* Final output stage: scale down by a factor of 8 and range-limit */
outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3)
& RANGE_MASK];
outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3)
& RANGE_MASK];
outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3)
& RANGE_MASK];
outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3)
& RANGE_MASK];
outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3)
& RANGE_MASK];
outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3)
& RANGE_MASK];
outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3)
& RANGE_MASK];
outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3)
& RANGE_MASK];
wsptr += DCTSIZE; /* advance pointer to next row */
}
}
#endif /* DCT_FLOAT_SUPPORTED */

View File

@@ -0,0 +1,105 @@
/*
* jinclude.h
*
* Copyright (C) 1991-1994, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file exists to provide a single place to fix any problems with
* including the wrong system include files. (Common problems are taken
* care of by the standard jconfig symbols, but on really weird systems
* you may have to edit this file.)
*
* NOTE: this file is NOT intended to be included by applications using the
* JPEG library. Most applications need only include jpeglib.h.
*/
#ifdef __cplusplus
extern "C"
{
#endif
/* Include auto-config file to find out which system include files we need. */
#include "jconfig.h" /* auto configuration options */
#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */
/*
* We need the NULL macro and size_t typedef.
* On an ANSI-conforming system it is sufficient to include <stddef.h>.
* Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to
* pull in <sys/types.h> as well.
* Note that the core JPEG library does not require <stdio.h>;
* only the default error handler and data source/destination modules do.
* But we must pull it in because of the references to FILE in jpeglib.h.
* You can remove those references if you want to compile without <stdio.h>.
*/
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef NEED_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <stdio.h>
/*
* We need memory copying and zeroing functions, plus strncpy().
* ANSI and System V implementations declare these in <string.h>.
* BSD doesn't have the mem() functions, but it does have bcopy()/bzero().
* Some systems may declare memset and memcpy in <memory.h>.
*
* NOTE: we assume the size parameters to these functions are of type size_t.
* Change the casts in these macros if not!
*/
#ifdef NEED_BSD_STRINGS
#include <strings.h>
#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size))
#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size))
#else /* not BSD, assume ANSI/SysV string lib */
#include <string.h>
#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size))
#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size))
#endif
/*
* In ANSI C, and indeed any rational implementation, size_t is also the
* type returned by sizeof(). However, it seems there are some irrational
* implementations out there, in which sizeof() returns an int even though
* size_t is defined as long or unsigned long. To ensure consistent results
* we always use this SIZEOF() macro in place of using sizeof() directly.
*/
#define SIZEOF(object) ((size_t) sizeof(object))
/*
* The modules that use fread() and fwrite() always invoke them through
* these macros. On some systems you may need to twiddle the argument casts.
* CAUTION: argument order is different from underlying functions!
*/
#define JFREAD(file,buf,sizeofbuf) \
((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
#define JFWRITE(file,buf,sizeofbuf) \
((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
#ifdef __cplusplus
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,123 @@
/*
* jmemnobs.c
*
* Copyright (C) 1992-1994, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file provides a really simple implementation of the system-
* dependent portion of the JPEG memory manager. This implementation
* assumes that no backing-store files are needed: all required space
* can be obtained from ri.Malloc().
* This is very portable in the sense that it'll compile on almost anything,
* but you'd better have lots of main memory (or virtual memory) if you want
* to process big images.
* Note that the max_memory_to_use option is ignored by this implementation.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jmemsys.h" /* import the system-dependent declarations */
/*
* Memory allocation and ri.Freeing are controlled by the regular library
* routines ri.Malloc() and ri.Free().
*/
GLOBAL void *
jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
{
// -slc
#if 0
return (void *) ri.Malloc(sizeofobject);
#else
return JPG_Malloc(sizeofobject);
#endif
}
GLOBAL void
jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
{
// -slc
#if 0
ri.Free(object);
#else
JPG_Free(object);
#endif
}
/*
* "Large" objects are treated the same as "small" ones.
* NB: although we include FAR keywords in the routine declarations,
* this file won't actually work in 80x86 small/medium model; at least,
* you probably won't be able to process useful-size images in only 64KB.
*/
GLOBAL void FAR *
jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
{
// -slc
#if 0
return (void FAR *) ri.Malloc(sizeofobject);
#else
return JPG_Malloc(sizeofobject);
#endif
}
GLOBAL void
jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
{
// -slc
#if 0
ri.Free(object);
#else
JPG_Free(object);
#endif
}
/*
* This routine computes the total memory space available for allocation.
* Here we always say, "we got all you want bud!"
*/
GLOBAL long
jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
long max_bytes_needed, long already_allocated)
{
return max_bytes_needed;
}
/*
* Backing store (temporary file) management.
* Since jpeg_mem_available always promised the moon,
* this should never be called and we can just error out.
*/
GLOBAL void
jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
long total_bytes_needed)
{
ERREXIT(cinfo, JERR_NO_BACKING_STORE);
}
/*
* These routines take care of any system-dependent initialization and
* cleanup required. Here, there isn't any.
*/
GLOBAL long
jpeg_mem_init (j_common_ptr cinfo)
{
return 0; /* just set max_memory_to_use to 0 */
}
GLOBAL void
jpeg_mem_term (j_common_ptr cinfo)
{
/* no work */
}

View File

@@ -0,0 +1,182 @@
/*
* jmemsys.h
*
* Copyright (C) 1992-1994, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This include file defines the interface between the system-independent
* and system-dependent portions of the JPEG memory manager. No other
* modules need include it. (The system-independent portion is jmemmgr.c;
* there are several different versions of the system-dependent portion.)
*
* This file works as-is for the system-dependent memory managers supplied
* in the IJG distribution. You may need to modify it if you write a
* custom memory manager. If system-dependent changes are needed in
* this file, the best method is to #ifdef them based on a configuration
* symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR.
*/
/* Short forms of external names for systems with brain-damaged linkers. */
#ifdef NEED_SHORT_EXTERNAL_NAMES
#define jpeg_get_small jGetSmall
#define jpeg_free_small jFreeSmall
#define jpeg_get_large jGetLarge
#define jpeg_free_large jFreeLarge
#define jpeg_mem_available jMemAvail
#define jpeg_open_backing_store jOpenBackStore
#define jpeg_mem_init jMemInit
#define jpeg_mem_term jMemTerm
#endif /* NEED_SHORT_EXTERNAL_NAMES */
/*
* These two functions are used to allocate and release small chunks of
* memory. (Typically the total amount requested through jpeg_get_small is
* no more than 20K or so; this will be requested in chunks of a few K each.)
* Behavior should be the same as for the standard library functions malloc
* and free; in particular, jpeg_get_small must return NULL on failure.
* On most systems, these ARE malloc and free. jpeg_free_small is passed the
* size of the object being freed, just in case it's needed.
* On an 80x86 machine using small-data memory model, these manage near heap.
*/
EXTERN void * jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject));
EXTERN void jpeg_free_small JPP((j_common_ptr cinfo, void * object,
size_t sizeofobject));
/*
* These two functions are used to allocate and release large chunks of
* memory (up to the total free space designated by jpeg_mem_available).
* The interface is the same as above, except that on an 80x86 machine,
* far pointers are used. On most other machines these are identical to
* the jpeg_get/free_small routines; but we keep them separate anyway,
* in case a different allocation strategy is desirable for large chunks.
*/
EXTERN void FAR * jpeg_get_large JPP((j_common_ptr cinfo,size_t sizeofobject));
EXTERN void jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object,
size_t sizeofobject));
/*
* The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may
* be requested in a single call to jpeg_get_large (and jpeg_get_small for that
* matter, but that case should never come into play). This macro is needed
* to model the 64Kb-segment-size limit of far addressing on 80x86 machines.
* On those machines, we expect that jconfig.h will provide a proper value.
* On machines with 32-bit flat address spaces, any large constant may be used.
*
* NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type
* size_t and will be a multiple of sizeof(align_type).
*/
#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */
#define MAX_ALLOC_CHUNK 1000000000L
#endif
/*
* This routine computes the total space still available for allocation by
* jpeg_get_large. If more space than this is needed, backing store will be
* used. NOTE: any memory already allocated must not be counted.
*
* There is a minimum space requirement, corresponding to the minimum
* feasible buffer sizes; jmemmgr.c will request that much space even if
* jpeg_mem_available returns zero. The maximum space needed, enough to hold
* all working storage in memory, is also passed in case it is useful.
* Finally, the total space already allocated is passed. If no better
* method is available, cinfo->mem->max_memory_to_use - already_allocated
* is often a suitable calculation.
*
* It is OK for jpeg_mem_available to underestimate the space available
* (that'll just lead to more backing-store access than is really necessary).
* However, an overestimate will lead to failure. Hence it's wise to subtract
* a slop factor from the true available space. 5% should be enough.
*
* On machines with lots of virtual memory, any large constant may be returned.
* Conversely, zero may be returned to always use the minimum amount of memory.
*/
EXTERN long jpeg_mem_available JPP((j_common_ptr cinfo,
long min_bytes_needed,
long max_bytes_needed,
long already_allocated));
/*
* This structure holds whatever state is needed to access a single
* backing-store object. The read/write/close method pointers are called
* by jmemmgr.c to manipulate the backing-store object; all other fields
* are private to the system-dependent backing store routines.
*/
#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */
#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */
typedef unsigned short XMSH; /* type of extended-memory handles */
typedef unsigned short EMSH; /* type of expanded-memory handles */
typedef union {
short file_handle; /* DOS file handle if it's a temp file */
XMSH xms_handle; /* handle if it's a chunk of XMS */
EMSH ems_handle; /* handle if it's a chunk of EMS */
} handle_union;
#endif /* USE_MSDOS_MEMMGR */
typedef struct backing_store_struct * backing_store_ptr;
typedef struct backing_store_struct {
/* Methods for reading/writing/closing this backing-store object */
JMETHOD(void, read_backing_store, (j_common_ptr cinfo,
backing_store_ptr info,
void FAR * buffer_address,
long file_offset, long byte_count));
JMETHOD(void, write_backing_store, (j_common_ptr cinfo,
backing_store_ptr info,
void FAR * buffer_address,
long file_offset, long byte_count));
JMETHOD(void, close_backing_store, (j_common_ptr cinfo,
backing_store_ptr info));
/* Private fields for system-dependent backing-store management */
#ifdef USE_MSDOS_MEMMGR
/* For the MS-DOS manager (jmemdos.c), we need: */
handle_union handle; /* reference to backing-store storage object */
char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
#else
/* For a typical implementation with temp files, we need: */
FILE * temp_file; /* stdio reference to temp file */
char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */
#endif
} backing_store_info;
/*
* Initial opening of a backing-store object. This must fill in the
* read/write/close pointers in the object. The read/write routines
* may take an error exit if the specified maximum file size is exceeded.
* (If jpeg_mem_available always returns a large value, this routine can
* just take an error exit.)
*/
EXTERN void jpeg_open_backing_store JPP((j_common_ptr cinfo,
backing_store_ptr info,
long total_bytes_needed));
/*
* These routines take care of any system-dependent initialization and
* cleanup required. jpeg_mem_init will be called before anything is
* allocated (and, therefore, nothing in cinfo is of use except the error
* manager pointer). It should return a suitable default value for
* max_memory_to_use; this may subsequently be overridden by the surrounding
* application. (Note that max_memory_to_use is only important if
* jpeg_mem_available chooses to consult it ... no one else will.)
* jpeg_mem_term may assume that all requested memory has been freed and that
* all opened backing-store objects have been closed.
*/
EXTERN long jpeg_mem_init JPP((j_common_ptr cinfo));
EXTERN void jpeg_mem_term JPP((j_common_ptr cinfo));

View File

@@ -0,0 +1,352 @@
/*
* jmorecfg.h
*
* Copyright (C) 1991-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains additional configuration options that customize the
* JPEG software for special applications or support machine-dependent
* optimizations. Most users will not need to touch this file.
*/
/*
* Define BITS_IN_JSAMPLE as either
* 8 for 8-bit sample values (the usual setting)
* 12 for 12-bit sample values
* Only 8 and 12 are legal data precisions for lossy JPEG according to the
* JPEG standard, and the IJG code does not support anything else!
* We do not support run-time selection of data precision, sorry.
*/
#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
/*
* Maximum number of components (color channels) allowed in JPEG image.
* To meet the letter of the JPEG spec, set this to 255. However, darn
* few applications need more than 4 channels (maybe 5 for CMYK + alpha
* mask). We recommend 10 as a reasonable compromise; use 4 if you are
* really short on memory. (Each allowed component costs a hundred or so
* bytes of storage, whether actually used in an image or not.)
*/
#define MAX_COMPONENTS 10 /* maximum number of image components */
/*
* Basic data types.
* You may need to change these if you have a machine with unusual data
* type sizes; for example, "char" not 8 bits, "short" not 16 bits,
* or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits,
* but it had better be at least 16.
*/
/* Representation of a single sample (pixel element value).
* We frequently allocate large arrays of these, so it's important to keep
* them small. But if you have memory to burn and access to char or short
* arrays is very slow on your hardware, you might want to change these.
*/
#if BITS_IN_JSAMPLE == 8
/* JSAMPLE should be the smallest type that will hold the values 0..255.
* You can use a signed char by having GETJSAMPLE mask it with 0xFF.
*/
#ifdef HAVE_UNSIGNED_CHAR
typedef unsigned char JSAMPLE;
#define GETJSAMPLE(value) ((int) (value))
#else /* not HAVE_UNSIGNED_CHAR */
typedef char JSAMPLE;
#ifdef CHAR_IS_UNSIGNED
#define GETJSAMPLE(value) ((int) (value))
#else
#define GETJSAMPLE(value) ((int) (value) & 0xFF)
#endif /* CHAR_IS_UNSIGNED */
#endif /* HAVE_UNSIGNED_CHAR */
#define MAXJSAMPLE 255
#define CENTERJSAMPLE 128
#endif /* BITS_IN_JSAMPLE == 8 */
#if BITS_IN_JSAMPLE == 12
/* JSAMPLE should be the smallest type that will hold the values 0..4095.
* On nearly all machines "short" will do nicely.
*/
typedef short JSAMPLE;
#define GETJSAMPLE(value) ((int) (value))
#define MAXJSAMPLE 4095
#define CENTERJSAMPLE 2048
#endif /* BITS_IN_JSAMPLE == 12 */
/* Representation of a DCT frequency coefficient.
* This should be a signed value of at least 16 bits; "short" is usually OK.
* Again, we allocate large arrays of these, but you can change to int
* if you have memory to burn and "short" is really slow.
*/
typedef short JCOEF;
/* Compressed datastreams are represented as arrays of JOCTET.
* These must be EXACTLY 8 bits wide, at least once they are written to
* external storage. Note that when using the stdio data source/destination
* managers, this is also the data type passed to fread/fwrite.
*/
#ifdef HAVE_UNSIGNED_CHAR
typedef unsigned char JOCTET;
#define GETJOCTET(value) (value)
#else /* not HAVE_UNSIGNED_CHAR */
typedef char JOCTET;
#ifdef CHAR_IS_UNSIGNED
#define GETJOCTET(value) (value)
#else
#define GETJOCTET(value) ((value) & 0xFF)
#endif /* CHAR_IS_UNSIGNED */
#endif /* HAVE_UNSIGNED_CHAR */
/* These typedefs are used for various table entries and so forth.
* They must be at least as wide as specified; but making them too big
* won't cost a huge amount of memory, so we don't provide special
* extraction code like we did for JSAMPLE. (In other words, these
* typedefs live at a different point on the speed/space tradeoff curve.)
*/
/* UINT8 must hold at least the values 0..255. */
#ifdef HAVE_UNSIGNED_CHAR
#ifndef UINT8
typedef unsigned char UINT8;
#endif
#else /* not HAVE_UNSIGNED_CHAR */
#ifdef CHAR_IS_UNSIGNED
typedef char UINT8;
#else /* not CHAR_IS_UNSIGNED */
typedef short UINT8;
#endif /* CHAR_IS_UNSIGNED */
#endif /* HAVE_UNSIGNED_CHAR */
/* UINT16 must hold at least the values 0..65535. */
#ifdef HAVE_UNSIGNED_SHORT
#ifndef UINT16
typedef unsigned short UINT16;
#endif
#else /* not HAVE_UNSIGNED_SHORT */
typedef unsigned int UINT16;
#endif /* HAVE_UNSIGNED_SHORT */
/* INT16 must hold at least the values -32768..32767. */
#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */
#ifndef INT16
typedef short INT16;
#endif
#endif
/* INT32 must hold at least signed 32-bit values. */
//#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */
//typedef long INT32;
//#endif
/* Datatype used for image dimensions. The JPEG standard only supports
* images up to 64K*64K due to 16-bit fields in SOF markers. Therefore
* "unsigned int" is sufficient on all machines. However, if you need to
* handle larger images and you don't mind deviating from the spec, you
* can change this datatype.
*/
typedef unsigned int JDIMENSION;
#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */
/* These defines are used in all function definitions and extern declarations.
* You could modify them if you need to change function linkage conventions.
* Another application is to make all functions global for use with debuggers
* or code profilers that require it.
*/
#define METHODDEF static /* a function called through method pointers */
#define LOCAL static /* a function used only in its module */
#define GLOBAL /* a function referenced thru EXTERNs */
#define EXTERN extern /* a reference to a GLOBAL function */
/* Here is the pseudo-keyword for declaring pointers that must be "far"
* on 80x86 machines. Most of the specialized coding for 80x86 is handled
* by just saying "FAR *" where such a pointer is needed. In a few places
* explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol.
*/
#ifdef NEED_FAR_POINTERS
#undef FAR
#define FAR far
#else
#undef FAR
#define FAR
#endif
/*
* On a few systems, type boolean and/or its values FALSE, TRUE may appear
* in standard header files. Or you may have conflicts with application-
* specific header files that you want to include together with these files.
* Defining HAVE_BOOLEAN before including jpeglib.h should make it work.
*/
//#ifndef HAVE_BOOLEAN
//typedef int boolean;
//#endif
#ifndef FALSE /* in case these macros already exist */
#define FALSE 0 /* values of boolean */
#endif
#ifndef TRUE
#define TRUE 1
#endif
/*
* The remaining options affect code selection within the JPEG library,
* but they don't need to be visible to most applications using the library.
* To minimize application namespace pollution, the symbols won't be
* defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined.
*/
#ifdef JPEG_INTERNALS
#define JPEG_INTERNAL_OPTIONS
#endif
#ifdef JPEG_INTERNAL_OPTIONS
/*
* These defines indicate whether to include various optional functions.
* Undefining some of these symbols will produce a smaller but less capable
* library. Note that you can leave certain source files out of the
* compilation/linking process if you've #undef'd the corresponding symbols.
* (You may HAVE to do that if your compiler doesn't like null source files.)
*/
/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */
/* Capability options common to encoder and decoder: */
#undef DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */
#undef DCT_IFAST_SUPPORTED /* faster, less accurate integer method */
#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */
/* Encoder capability options: */
#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */
#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */
/* Note: if you selected 12-bit data precision, it is dangerous to turn off
* ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit
* precision, so jchuff.c normally uses entropy optimization to compute
* usable tables for higher precision. If you don't want to do optimization,
* you'll have to supply different default Huffman tables.
* The exact same statements apply for progressive JPEG: the default tables
* don't work for progressive mode. (This may get fixed, however.)
*/
#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */
/* Decoder capability options: */
#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */
#undef D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
#undef D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
#undef BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */
#undef IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */
#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */
#undef UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */
#undef QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */
#undef QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */
/* more capability options later, no doubt */
/*
* Ordering of RGB data in scanlines passed to or from the application.
* If your application wants to deal with data in the order B,G,R, just
* change these macros. You can also deal with formats such as R,G,B,X
* (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing
* the offsets will also change the order in which colormap data is organized.
* RESTRICTIONS:
* 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats.
* 2. These macros only affect RGB<=>YCbCr color conversion, so they are not
* useful if you are using JPEG color spaces other than YCbCr or grayscale.
* 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE
* is not 3 (they don't understand about dummy color components!). So you
* can't use color quantization if you change that value.
*/
#define RGB_RED 0 /* Offset of Red in an RGB scanline element */
#define RGB_GREEN 1 /* Offset of Green */
#define RGB_BLUE 2 /* Offset of Blue */
#define RGB_PIXELSIZE 4 /* JSAMPLEs per RGB scanline element */
/* Definitions for speed-related optimizations. */
/* If your compiler supports inline functions, define INLINE
* as the inline keyword; otherwise define it as empty.
*/
#ifndef INLINE
#ifdef __GNUC__ /* for instance, GNU C knows about inline */
#define INLINE __inline__
#endif
#ifndef INLINE
#define INLINE /* default is to define it as empty */
#endif
#endif
/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying
* two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER
* as short on such a machine. MULTIPLIER must be at least 16 bits wide.
*/
#ifndef MULTIPLIER
#define MULTIPLIER int /* type for fastest integer multiply */
#endif
/* FAST_FLOAT should be either float or double, whichever is done faster
* by your compiler. (Note that this type is only used in the floating point
* DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.)
* Typically, float is faster in ANSI C compilers, while double is faster in
* pre-ANSI compilers (because they insist on converting to double anyway).
* The code below therefore chooses float if we have ANSI-style prototypes.
*/
#ifndef FAST_FLOAT
#ifdef HAVE_PROTOTYPES
#define FAST_FLOAT float
#else
#define FAST_FLOAT double
#endif
#endif
#endif /* JPEG_INTERNAL_OPTIONS */

View File

@@ -0,0 +1,388 @@
/*
* jpegint.h
*
* Copyright (C) 1991-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file provides common declarations for the various JPEG modules.
* These declarations are considered internal to the JPEG library; most
* applications using the library shouldn't need to include this file.
*/
/* Declarations for both compression & decompression */
typedef enum { /* Operating modes for buffer controllers */
JBUF_PASS_THRU, /* Plain stripwise operation */
/* Remaining modes require a full-image buffer to have been created */
JBUF_SAVE_SOURCE, /* Run source subobject only, save output */
JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */
JBUF_SAVE_AND_PASS /* Run both subobjects, save output */
} J_BUF_MODE;
/* Values of global_state field (jdapi.c has some dependencies on ordering!) */
#define CSTATE_START 100 /* after create_compress */
#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */
#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */
#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */
#define DSTATE_START 200 /* after create_decompress */
#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */
#define DSTATE_READY 202 /* found SOS, ready for start_decompress */
#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/
#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */
#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */
#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */
#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */
#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */
#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */
#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */
/* Declarations for compression modules */
/* Master control module */
struct jpeg_comp_master {
JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo));
JMETHOD(void, pass_startup, (j_compress_ptr cinfo));
JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
/* State variables made visible to other modules */
boolean call_pass_startup; /* True if pass_startup must be called */
boolean is_last_pass; /* True during last pass */
};
/* Main buffer control (downsampled-data buffer) */
struct jpeg_c_main_controller {
JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
JMETHOD(void, process_data, (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail));
};
/* Compression preprocessing (downsampling input buffer control) */
struct jpeg_c_prep_controller {
JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
JMETHOD(void, pre_process_data, (j_compress_ptr cinfo,
JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail,
JSAMPIMAGE output_buf,
JDIMENSION *out_row_group_ctr,
JDIMENSION out_row_groups_avail));
};
/* Coefficient buffer control */
struct jpeg_c_coef_controller {
JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
JMETHOD(boolean, compress_data, (j_compress_ptr cinfo,
JSAMPIMAGE input_buf));
};
/* Colorspace conversion */
struct jpeg_color_converter {
JMETHOD(void, start_pass, (j_compress_ptr cinfo));
JMETHOD(void, color_convert, (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows));
};
/* Downsampling */
struct jpeg_downsampler {
JMETHOD(void, start_pass, (j_compress_ptr cinfo));
JMETHOD(void, downsample, (j_compress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION in_row_index,
JSAMPIMAGE output_buf,
JDIMENSION out_row_group_index));
boolean need_context_rows; /* TRUE if need rows above & below */
};
/* Forward DCT (also controls coefficient quantization) */
struct jpeg_forward_dct {
JMETHOD(void, start_pass, (j_compress_ptr cinfo));
/* perhaps this should be an array??? */
JMETHOD(void, forward_DCT, (j_compress_ptr cinfo,
jpeg_component_info * compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks));
};
/* Entropy encoding */
struct jpeg_entropy_encoder {
JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics));
JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data));
JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
};
/* Marker writing */
struct jpeg_marker_writer {
/* write_any_marker is exported for use by applications */
/* Probably only COM and APPn markers should be written */
JMETHOD(void, write_any_marker, (j_compress_ptr cinfo, int marker,
const JOCTET *dataptr, unsigned int datalen));
JMETHOD(void, write_file_header, (j_compress_ptr cinfo));
JMETHOD(void, write_frame_header, (j_compress_ptr cinfo));
JMETHOD(void, write_scan_header, (j_compress_ptr cinfo));
JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo));
JMETHOD(void, write_tables_only, (j_compress_ptr cinfo));
};
/* Declarations for decompression modules */
/* Master control module */
struct jpeg_decomp_master {
JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo));
JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo));
/* State variables made visible to other modules */
boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */
};
/* Input control module */
struct jpeg_input_controller {
JMETHOD(int, consume_input, (j_decompress_ptr cinfo));
JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo));
JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo));
/* State variables made visible to other modules */
boolean has_multiple_scans; /* True if file has multiple scans */
boolean eoi_reached; /* True when EOI has been consumed */
};
/* Main buffer control (downsampled-data buffer) */
struct jpeg_d_main_controller {
JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
JMETHOD(void, process_data, (j_decompress_ptr cinfo,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail));
};
/* Coefficient buffer control */
struct jpeg_d_coef_controller {
JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
JMETHOD(int, consume_data, (j_decompress_ptr cinfo));
JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo));
JMETHOD(int, decompress_data, (j_decompress_ptr cinfo,
JSAMPIMAGE output_buf));
/* Pointer to array of coefficient virtual arrays, or NULL if none */
jvirt_barray_ptr *coef_arrays;
};
/* Decompression postprocessing (color quantization buffer control) */
struct jpeg_d_post_controller {
JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
JMETHOD(void, post_process_data, (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail));
};
/* Marker reading & parsing */
struct jpeg_marker_reader {
JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo));
/* Read markers until SOS or EOI.
* Returns same codes as are defined for jpeg_consume_input:
* JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
*/
JMETHOD(int, read_markers, (j_decompress_ptr cinfo));
/* Read a restart marker --- exported for use by entropy decoder only */
jpeg_marker_parser_method read_restart_marker;
/* Application-overridable marker processing methods */
jpeg_marker_parser_method process_COM;
jpeg_marker_parser_method process_APPn[16];
/* State of marker reader --- nominally internal, but applications
* supplying COM or APPn handlers might like to know the state.
*/
boolean saw_SOI; /* found SOI? */
boolean saw_SOF; /* found SOF? */
int next_restart_num; /* next restart number expected (0-7) */
unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */
};
/* Entropy decoding */
struct jpeg_entropy_decoder {
JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo,
JBLOCKROW *MCU_data));
};
/* Inverse DCT (also performs dequantization) */
typedef JMETHOD(void, inverse_DCT_method_ptr,
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
JCOEFPTR coef_block,
JSAMPARRAY output_buf, JDIMENSION output_col));
struct jpeg_inverse_dct {
JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
/* It is useful to allow each component to have a separate IDCT method. */
inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
};
/* Upsampling (note that upsampler must also call color converter) */
struct jpeg_upsampler {
JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
JMETHOD(void, upsample, (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail));
boolean need_context_rows; /* TRUE if need rows above & below */
};
/* Colorspace conversion */
struct jpeg_color_deconverter {
JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
JMETHOD(void, color_convert, (j_decompress_ptr cinfo,
JSAMPIMAGE input_buf, JDIMENSION input_row,
JSAMPARRAY output_buf, int num_rows));
};
/* Color quantization or color precision reduction */
struct jpeg_color_quantizer {
JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan));
JMETHOD(void, color_quantize, (j_decompress_ptr cinfo,
JSAMPARRAY input_buf, JSAMPARRAY output_buf,
int num_rows));
JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));
JMETHOD(void, new_color_map, (j_decompress_ptr cinfo));
};
/* Miscellaneous useful macros */
#undef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#undef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
/* We assume that right shift corresponds to signed division by 2 with
* rounding towards minus infinity. This is correct for typical "arithmetic
* shift" instructions that shift in copies of the sign bit. But some
* C compilers implement >> with an unsigned shift. For these machines you
* must define RIGHT_SHIFT_IS_UNSIGNED.
* RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
* It is only applied with constant shift counts. SHIFT_TEMPS must be
* included in the variables of any routine using RIGHT_SHIFT.
*/
#ifdef RIGHT_SHIFT_IS_UNSIGNED
#define SHIFT_TEMPS INT32 shift_temp;
#define RIGHT_SHIFT(x,shft) \
((shift_temp = (x)) < 0 ? \
(shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
(shift_temp >> (shft)))
#else
#define SHIFT_TEMPS
#define RIGHT_SHIFT(x,shft) ((x) >> (shft))
#endif
/* Short forms of external names for systems with brain-damaged linkers. */
#ifdef NEED_SHORT_EXTERNAL_NAMES
#define jinit_compress_master jICompress
#define jinit_c_master_control jICMaster
#define jinit_c_main_controller jICMainC
#define jinit_c_prep_controller jICPrepC
#define jinit_c_coef_controller jICCoefC
#define jinit_color_converter jICColor
#define jinit_downsampler jIDownsampler
#define jinit_forward_dct jIFDCT
#define jinit_huff_encoder jIHEncoder
#define jinit_phuff_encoder jIPHEncoder
#define jinit_marker_writer jIMWriter
#define jinit_master_decompress jIDMaster
#define jinit_d_main_controller jIDMainC
#define jinit_d_coef_controller jIDCoefC
#define jinit_d_post_controller jIDPostC
#define jinit_input_controller jIInCtlr
#define jinit_marker_reader jIMReader
#define jinit_huff_decoder jIHDecoder
#define jinit_phuff_decoder jIPHDecoder
#define jinit_inverse_dct jIIDCT
#define jinit_upsampler jIUpsampler
#define jinit_color_deconverter jIDColor
#define jinit_1pass_quantizer jI1Quant
#define jinit_2pass_quantizer jI2Quant
#define jinit_merged_upsampler jIMUpsampler
#define jinit_memory_mgr jIMemMgr
#define jdiv_round_up jDivRound
#define jround_up jRound
#define jcopy_sample_rows jCopySamples
#define jcopy_block_row jCopyBlocks
#define jzero_far jZeroFar
#define jpeg_zigzag_order jZIGTable
#define jpeg_natural_order jZAGTable
#endif /* NEED_SHORT_EXTERNAL_NAMES */
/* Compression module initialization routines */
EXTERN void jinit_compress_master JPP((j_compress_ptr cinfo));
EXTERN void jinit_c_master_control JPP((j_compress_ptr cinfo,
boolean transcode_only));
EXTERN void jinit_c_main_controller JPP((j_compress_ptr cinfo,
boolean need_full_buffer));
EXTERN void jinit_c_prep_controller JPP((j_compress_ptr cinfo,
boolean need_full_buffer));
EXTERN void jinit_c_coef_controller JPP((j_compress_ptr cinfo,
boolean need_full_buffer));
EXTERN void jinit_color_converter JPP((j_compress_ptr cinfo));
EXTERN void jinit_downsampler JPP((j_compress_ptr cinfo));
EXTERN void jinit_forward_dct JPP((j_compress_ptr cinfo));
EXTERN void jinit_huff_encoder JPP((j_compress_ptr cinfo));
EXTERN void jinit_phuff_encoder JPP((j_compress_ptr cinfo));
EXTERN void jinit_marker_writer JPP((j_compress_ptr cinfo));
/* Decompression module initialization routines */
EXTERN void jinit_master_decompress JPP((j_decompress_ptr cinfo));
EXTERN void jinit_d_main_controller JPP((j_decompress_ptr cinfo,
boolean need_full_buffer));
EXTERN void jinit_d_coef_controller JPP((j_decompress_ptr cinfo,
boolean need_full_buffer));
EXTERN void jinit_d_post_controller JPP((j_decompress_ptr cinfo,
boolean need_full_buffer));
EXTERN void jinit_input_controller JPP((j_decompress_ptr cinfo));
EXTERN void jinit_marker_reader JPP((j_decompress_ptr cinfo));
EXTERN void jinit_huff_decoder JPP((j_decompress_ptr cinfo));
EXTERN void jinit_phuff_decoder JPP((j_decompress_ptr cinfo));
EXTERN void jinit_inverse_dct JPP((j_decompress_ptr cinfo));
EXTERN void jinit_upsampler JPP((j_decompress_ptr cinfo));
EXTERN void jinit_color_deconverter JPP((j_decompress_ptr cinfo));
EXTERN void jinit_1pass_quantizer JPP((j_decompress_ptr cinfo));
EXTERN void jinit_2pass_quantizer JPP((j_decompress_ptr cinfo));
EXTERN void jinit_merged_upsampler JPP((j_decompress_ptr cinfo));
/* Memory manager initialization */
EXTERN void jinit_memory_mgr JPP((j_common_ptr cinfo));
/* Utility routines in jutils.c */
EXTERN long jdiv_round_up JPP((long a, long b));
EXTERN long jround_up JPP((long a, long b));
EXTERN void jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
JSAMPARRAY output_array, int dest_row,
int num_rows, JDIMENSION num_cols));
EXTERN void jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row,
JDIMENSION num_blocks));
EXTERN void jzero_far JPP((void FAR * target, size_t bytestozero));
/* Constant tables in jutils.c */
extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */
extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */
/* Suppress undefined-structure complaints if necessary. */
#ifdef INCOMPLETE_TYPES_BROKEN
#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */
struct jvirt_sarray_control { long dummy; };
struct jvirt_barray_control { long dummy; };
#endif
#endif /* INCOMPLETE_TYPES_BROKEN */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,175 @@
/*
* jutils.c
*
* Copyright (C) 1991-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains tables and miscellaneous utility routines needed
* for both compression and decompression.
* Note we prefix all global names with "j" to minimize conflicts with
* a surrounding application.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
/*
* jpeg_zigzag_order[i] is the zigzag-order position of the i'th element
* of a DCT block read in natural order (left to right, top to bottom).
*/
const int jpeg_zigzag_order[DCTSIZE2] = {
0, 1, 5, 6, 14, 15, 27, 28,
2, 4, 7, 13, 16, 26, 29, 42,
3, 8, 12, 17, 25, 30, 41, 43,
9, 11, 18, 24, 31, 40, 44, 53,
10, 19, 23, 32, 39, 45, 52, 54,
20, 22, 33, 38, 46, 51, 55, 60,
21, 34, 37, 47, 50, 56, 59, 61,
35, 36, 48, 49, 57, 58, 62, 63
};
/*
* jpeg_natural_order[i] is the natural-order position of the i'th element
* of zigzag order.
*
* When reading corrupted data, the Huffman decoders could attempt
* to reference an entry beyond the end of this array (if the decoded
* zero run length reaches past the end of the block). To prevent
* wild stores without adding an inner-loop test, we put some extra
* "63"s after the real entries. This will cause the extra coefficient
* to be stored in location 63 of the block, not somewhere random.
* The worst case would be a run-length of 15, which means we need 16
* fake entries.
*/
const int jpeg_natural_order[DCTSIZE2+16] = {
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63,
63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
63, 63, 63, 63, 63, 63, 63, 63
};
/*
* Arithmetic utilities
*/
GLOBAL long
jdiv_round_up (long a, long b)
/* Compute a/b rounded up to next integer, ie, ceil(a/b) */
/* Assumes a >= 0, b > 0 */
{
return (a + b - 1L) / b;
}
GLOBAL long
jround_up (long a, long b)
/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */
/* Assumes a >= 0, b > 0 */
{
a += b - 1L;
return a - (a % b);
}
/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays
* and coefficient-block arrays. This won't work on 80x86 because the arrays
* are FAR and we're assuming a small-pointer memory model. However, some
* DOS compilers provide far-pointer versions of memcpy() and memset() even
* in the small-model libraries. These will be used if USE_FMEM is defined.
* Otherwise, the routines below do it the hard way. (The performance cost
* is not all that great, because these routines aren't very heavily used.)
*/
#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */
#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size)
#define FMEMZERO(target,size) MEMZERO(target,size)
#else /* 80x86 case, define if we can */
#ifdef USE_FMEM
#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size))
#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size))
#endif
#endif
GLOBAL void
jcopy_sample_rows (JSAMPARRAY input_array, int source_row,
JSAMPARRAY output_array, int dest_row,
int num_rows, JDIMENSION num_cols)
/* Copy some rows of samples from one place to another.
* num_rows rows are copied from input_array[source_row++]
* to output_array[dest_row++]; these areas may overlap for duplication.
* The source and destination arrays must be at least as wide as num_cols.
*/
{
register JSAMPROW inptr, outptr;
#ifdef FMEMCOPY
register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE));
#else
register JDIMENSION count;
#endif
register int row;
input_array += source_row;
output_array += dest_row;
for (row = num_rows; row > 0; row--) {
inptr = *input_array++;
outptr = *output_array++;
#ifdef FMEMCOPY
FMEMCOPY(outptr, inptr, count);
#else
for (count = num_cols; count > 0; count--)
*outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */
#endif
}
}
GLOBAL void
jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row,
JDIMENSION num_blocks)
/* Copy a row of coefficient blocks from one place to another. */
{
#ifdef FMEMCOPY
FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF)));
#else
register JCOEFPTR inptr, outptr;
register long count;
inptr = (JCOEFPTR) input_row;
outptr = (JCOEFPTR) output_row;
for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) {
*outptr++ = *inptr++;
}
#endif
}
GLOBAL void
jzero_far (void FAR * target, size_t bytestozero)
/* Zero out a chunk of FAR memory. */
/* This might be sample-array data, block-array data, or alloc_large data. */
{
#ifdef FMEMZERO
FMEMZERO(target, bytestozero);
#else
register char FAR * ptr = (char FAR *) target;
register size_t count;
for (count = bytestozero; count > 0; count--) {
*ptr++ = 0;
}
#endif
}

View File

@@ -0,0 +1,14 @@
/*
* jversion.h
*
* Copyright (C) 1991-1995, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains software version identification.
*/
#define JVERSION "6 2-Aug-95"
#define JCOPYRIGHT "Copyright (C) 1995, Thomas G. Lane"

View File

@@ -0,0 +1,248 @@
// Filename:- tr_jpeg_interace.cpp
//
#include "stdafx.h"
#include "includes.h"
#include "r_common.h"
//#include "system.h"
//#include "oddbits.h"
//#include "tr_local.h"
#include "jpeg_interface.h"
#include "jpeg6\jpeglib.h"
void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height )
{
*pic = NULL;
// static char sTEMP[]="Q:\\quake\\baseq3\\menu\\common\\cursor.jpg";
// filename = sTEMP;
/* This struct contains the JPEG decompression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
*/
struct jpeg_decompress_struct cinfo;
/* We use our private extension JPEG error handler.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
/* This struct represents a JPEG error handler. It is declared separately
* because applications often want to supply a specialized error handler
* (see the second half of this file for an example). But here we just
* take the easy way out and use the standard error handler, which will
* print a message on stderr and call exit() if compression fails.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
struct jpeg_error_mgr jerr;
/* More stuff */
JSAMPARRAY buffer; /* Output row buffer */
int row_stride; /* physical row width in output buffer */
unsigned char *out;
byte *fbuffer = NULL;
byte *bbuf;
/* In this example we want to open the input file before doing anything else,
* so that the setjmp() error recovery below can assume the file is open.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to read binary files.
*/
// LoadFile (filename, (void **)&fbuffer, false);
int iBytesRead = ri.FS_ReadFile ( ( char * ) filename, (void **)&fbuffer);
if (!fbuffer)
return;
// this JPG loader is a bit crap, and often causes read-violations because of reading an extra 4k from the input
// buffer that isn't actually there, causes problems on NT4 and NT2000, so allocate 4K more and use that instead.
//
byte *fbuffer2 = (byte*) ri.Malloc( iBytesRead+4096 );
if (!fbuffer2)
{
free(fbuffer);
return;
}
memcpy(fbuffer2,fbuffer,iBytesRead);
free(fbuffer);
fbuffer = fbuffer2;
try
{
/* Step 1: allocate and initialize JPEG decompression object */
/* We have to set up the error handler first, in case the initialization
* step fails. (Unlikely, but it could happen if you are out of memory.)
* This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo.
*/
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
jpeg_stdio_src(&cinfo, fbuffer);
/* Step 3: read file parameters with jpeg_read_header() */
(void) jpeg_read_header(&cinfo, TRUE);
/* We can ignore the return value from jpeg_read_header since
* (a) suspension is not possible with the stdio data source, and
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
* See libjpeg.doc for more info.
*/
/* Step 4: set parameters for decompression */
/* In this example, we don't need to change any of the defaults set by
* jpeg_read_header(), so we do nothing here.
*/
/* Step 5: Start decompressor */
(void) jpeg_start_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* We may need to do some setup of our own at this point before reading
* the data. After jpeg_start_decompress() we have the correct scaled
* output image dimensions available, as well as the output colormap
* if we asked for color quantization.
* In this example, we need to make an output work buffer of the right size.
*/
/* JSAMPLEs per row in output buffer */
row_stride = cinfo.output_width * cinfo.output_components;
if (cinfo.output_components!=4 && cinfo.output_components!=1 )
{
WarningBox(va("JPG %s is unsupported color depth (%d)", filename, cinfo.output_components));
}
out = (byte *) malloc(cinfo.output_width*cinfo.output_height*4);
*pic = out;
*width = cinfo.output_width;
*height = cinfo.output_height;
/* Step 6: while (scan lines remain to be read) */
/* jpeg_read_scanlines(...); */
/* Here we use the library's state variable cinfo.output_scanline as the
* loop counter, so that we don't have to keep track ourselves.
*/
while (cinfo.output_scanline < cinfo.output_height) {
/* jpeg_read_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could ask for
* more than one scanline at a time if that's more convenient.
*/
bbuf = ((out+(row_stride*cinfo.output_scanline)));
buffer = &bbuf;
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
}
// if we've just loaded a greyscale, then adjust it from 8-bit to 32bit by stretch-copying it over itself...
// (this also does the alpha stuff as well)
//
if (cinfo.output_components == 1)
{
byte *pbDest = (*pic + (cinfo.output_width * cinfo.output_height * 4))-1;
byte *pbSrc = (*pic + (cinfo.output_width * cinfo.output_height ))-1;
int iPixels = cinfo.output_width * cinfo.output_height;
for (int i=0; i<iPixels; i++)
{
byte b = *pbSrc--;
*pbDest-- = 255;
*pbDest-- = b;
*pbDest-- = b;
*pbDest-- = b;
}
}
else
{// clear all the alphas to 255
int i, j;
byte *buf;
buf = *pic;
j = cinfo.output_width * cinfo.output_height * 4;
for ( i = 3 ; i < j ; i+=4 ) {
buf[i] = 255;
}
}
/* Step 7: Finish decompression */
(void) jpeg_finish_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* Step 8: Release JPEG decompression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
}
catch(LPCSTR psMessage)
{
ErrorBox(va("JPEG read error: %s",psMessage));
jpeg_destroy_decompress(&cinfo);
// bReturn = false;
if (*pic)
{
free(*pic);
*pic = NULL;
}
}
/* After finish_decompress, we can close the input file.
* Here we postpone it until after no more JPEG errors are possible,
* so as to simplify the setjmp error logic above. (Actually, I don't
* think that jpeg_destroy can do an error exit, but why assume anything...)
*/
free(fbuffer);
/* At this point you may want to check to see whether any corrupt-data
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
*/
/* And we're done! */
}
void JPG_ErrorThrow(LPCSTR message)
{
// ri.Error( ERR_FATAL, "%s\n", message );
throw (message);
}
void JPG_MessageOut(LPCSTR message)
{
// ri.Printf(PRINT_ALL, "%s\n", message);
OutputDebugString(va("%s\n", message));
}
void *JPG_Malloc( int iSize )
{
//return (void *) ri.Malloc(iSize);
// OutputDebugString(va("%d\n", iSize));
return (void *) malloc(iSize);
}
void JPG_Free( void *pvObject)
{
//ri.Free(pvObject);
free(pvObject);
}
//////////////// eof ////////////

View File

@@ -0,0 +1,41 @@
// Filename:- jpeg_interface.h
//
#ifndef JPEG_INTERFACE_H
#define JPEG_INTERFACE_H
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef LPCSTR
typedef const char * LPCSTR;
#endif
void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height );
void JPG_ErrorThrow(LPCSTR message);
void JPG_MessageOut(LPCSTR message);
#define ERROR_STRING_NO_RETURN(message) JPG_ErrorThrow(message)
#define MESSAGE_STRING(message) JPG_MessageOut(message)
void *JPG_Malloc( int iSize );
void JPG_Free( void *pvObject);
#ifdef __cplusplus
};
#endif
#endif // #ifndef JPEG_INTERFACE_H
////////////////// eof //////////////////

1825
tools/ModView/mainfrm.cpp Normal file

File diff suppressed because it is too large Load Diff

183
tools/ModView/mainfrm.h Normal file
View File

@@ -0,0 +1,183 @@
// MainFrm.h : interface of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_MAINFRM_H__EFFD4A58_9FB9_11D4_8A94_00500424438B__INCLUDED_)
#define AFX_MAINFRM_H__EFFD4A58_9FB9_11D4_8A94_00500424438B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CMainFrame : public CFrameWnd
{
protected: // create from serialization only
CMainFrame();
DECLARE_DYNCREATE(CMainFrame)
protected:
CSplitterWnd m_splitter;
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMainFrame)
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected: // control bar embedded members
CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnFileOpen();
afx_msg void OnViewWireframe();
afx_msg void OnUpdateViewWireframe(CCmdUI* pCmdUI);
afx_msg void OnViewAlpha();
afx_msg void OnUpdateViewAlpha(CCmdUI* pCmdUI);
afx_msg void OnViewInterpolate();
afx_msg void OnUpdateViewInterpolate(CCmdUI* pCmdUI);
afx_msg void OnViewBilinear();
afx_msg void OnUpdateViewBilinear(CCmdUI* pCmdUI);
afx_msg void OnViewScreenshotFile();
afx_msg void OnViewScreenshotClipboard();
afx_msg void OnEditCopy();
afx_msg void OnEditPaste();
afx_msg void OnViewOrigin();
afx_msg void OnUpdateViewOrigin(CCmdUI* pCmdUI);
afx_msg void OnViewGlinfo();
afx_msg void OnAnimationStart();
afx_msg void OnAnimationStop();
afx_msg void OnAnimationRewind();
afx_msg void OnAnimationFaster();
afx_msg void OnAnimationSlower();
afx_msg void OnAnimationLerping();
afx_msg void OnUpdateAnimationLerping(CCmdUI* pCmdUI);
afx_msg void OnUpdateFileSave(CCmdUI* pCmdUI);
afx_msg void OnModelSaveAs();
afx_msg void OnUpdateFileSaveAs(CCmdUI* pCmdUI);
afx_msg void OnFileWriteideal();
afx_msg void OnAnimationNextframe();
afx_msg void OnAnimationPrevframe();
afx_msg void OnViewLod0();
afx_msg void OnViewLod1();
afx_msg void OnViewLod2();
afx_msg void OnViewLod3();
afx_msg void OnViewLod4();
afx_msg void OnViewLod5();
afx_msg void OnViewLod6();
afx_msg void OnViewLod7();
afx_msg void OnEditBgrndcolour();
afx_msg void OnUpdateViewBonehilite(CCmdUI* pCmdUI);
afx_msg void OnViewBonehilite();
afx_msg void OnViewNormals();
afx_msg void OnUpdateViewNormals(CCmdUI* pCmdUI);
afx_msg void OnViewSurfacehilite();
afx_msg void OnUpdateViewSurfacehilite(CCmdUI* pCmdUI);
afx_msg void OnViewVertindexes();
afx_msg void OnUpdateViewVertindexes(CCmdUI* pCmdUI);
afx_msg void OnViewFovcycle();
afx_msg void OnFileReadideal();
afx_msg void OnUpdateEditPaste(CCmdUI* pCmdUI);
afx_msg void OnFileRefreshtextures();
afx_msg void OnUpdateFilePrint(CCmdUI* pCmdUI);
afx_msg void OnUpdateFilePrintPreview(CCmdUI* pCmdUI);
afx_msg void OnUpdateFilePrintSetup(CCmdUI* pCmdUI);
afx_msg void OnUpdateEditTestfunction(CCmdUI* pCmdUI);
afx_msg void OnEditTestfunction();
afx_msg void OnFileResetviewparams();
afx_msg void OnAnimationStartwithwrapforce();
afx_msg void OnFileWritescript();
afx_msg void OnFileReadscript();
afx_msg void OnUpdateFileWritescript(CCmdUI* pCmdUI);
afx_msg void OnViewSurfacehilitewithbonerefs();
afx_msg void OnUpdateViewSurfacehilitewithbonerefs(CCmdUI* pCmdUI);
afx_msg void OnViewTagsurfaces();
afx_msg void OnUpdateViewTagsurfaces(CCmdUI* pCmdUI);
afx_msg void OnViewTagsasrgb();
afx_msg void OnUpdateViewTagsasrgb(CCmdUI* pCmdUI);
afx_msg void OnPicmip0();
afx_msg void OnUpdatePicmip0(CCmdUI* pCmdUI);
afx_msg void OnPicmip1();
afx_msg void OnUpdatePicmip1(CCmdUI* pCmdUI);
afx_msg void OnPicmip2();
afx_msg void OnUpdatePicmip2(CCmdUI* pCmdUI);
afx_msg void OnPicmip3();
afx_msg void OnUpdatePicmip3(CCmdUI* pCmdUI);
afx_msg void OnPicmip4();
afx_msg void OnPicmip5();
afx_msg void OnPicmip6();
afx_msg void OnPicmip7();
afx_msg void OnViewRuler();
afx_msg void OnUpdateViewRuler(CCmdUI* pCmdUI);
afx_msg void OnViewForcewhite();
afx_msg void OnUpdateViewForcewhite(CCmdUI* pCmdUI);
afx_msg void OnViewScreenshotClean();
afx_msg void OnUpdateViewScreenshotClean(CCmdUI* pCmdUI);
afx_msg void OnViewVertweighting();
afx_msg void OnUpdateViewVertweighting(CCmdUI* pCmdUI);
afx_msg void OnViewBbox();
afx_msg void OnUpdateViewBbox(CCmdUI* pCmdUI);
afx_msg void OnViewFloor();
afx_msg void OnUpdateViewFloor(CCmdUI* pCmdUI);
afx_msg void OnEditSetfloorAbs();
afx_msg void OnUpdateEditSetfloorAbs(CCmdUI* pCmdUI);
afx_msg void OnEditSetfloorCurrent();
afx_msg void OnUpdateEditSetfloorCurrent(CCmdUI* pCmdUI);
afx_msg void OnViewBonefiltering();
afx_msg void OnUpdateViewBonefiltering(CCmdUI* pCmdUI);
afx_msg void OnEditSetboneweightThreshhold();
afx_msg void OnUpdateEditSetboneweightThreshhold(CCmdUI* pCmdUI);
afx_msg void OnEditBoneFilterINCThreshhold();
afx_msg void OnEditBoneFilterDECThreshhold();
afx_msg void OnViewCrackviewer();
afx_msg void OnUpdateViewCrackviewer(CCmdUI* pCmdUI);
afx_msg void OnViewUnshadowablesurfaces();
afx_msg void OnUpdateViewUnshadowablesurfaces(CCmdUI* pCmdUI);
afx_msg void OnFileViewSof2Npcs();
afx_msg void OnUpdateFileViewSof2Npcs(CCmdUI* pCmdUI);
afx_msg void OnEditAllowskeletonoverrides();
afx_msg void OnUpdateEditAllowskeletonoverrides(CCmdUI* pCmdUI);
afx_msg void OnViewDoublesidedpolys();
afx_msg void OnUpdateViewDoublesidedpolys(CCmdUI* pCmdUI);
afx_msg void OnEditTopmost();
afx_msg void OnUpdateEditTopmost(CCmdUI* pCmdUI);
afx_msg void OnViewTriindexes();
afx_msg void OnUpdateViewTriindexes(CCmdUI* pCmdUI);
afx_msg void OnFileViewJk2Bots();
afx_msg void OnAnimationEndframe();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
void StatusMessage(LPCTSTR message);
afx_msg void OnFileBatchconvert();
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAINFRM_H__EFFD4A58_9FB9_11D4_8A94_00500424438B__INCLUDED_)

407
tools/ModView/matcomp.cpp Normal file
View File

@@ -0,0 +1,407 @@
// Filename:- matcomp.cpp
//
#include "stdafx.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
//
#include "MatComp.h"
#define MC_MASK_X ((1<<(MC_BITS_X))-1)
#define MC_MASK_Y ((1<<(MC_BITS_Y))-1)
#define MC_MASK_Z ((1<<(MC_BITS_Z))-1)
#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1)
#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2))
#define MC_POS_X (0)
#define MC_SHIFT_X (0)
#define MC_POS_Y ((((MC_BITS_X))/8))
#define MC_SHIFT_Y ((((MC_BITS_X)%8)))
#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8))
#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8)))
#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8))
#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8)))
#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8))
#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8)))
#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8))
#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8)))
#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8))
#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8)))
#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8))
#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8)))
#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8))
#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8)))
#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8))
#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8)))
#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8))
#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8)))
#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8))
#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8)))
void MC_Compress(const float mat[3][4],unsigned char * _comp)
{
char comp[MC_COMP_BYTES*2];
int i,val;
for (i=0;i<MC_COMP_BYTES;i++)
comp[i]=0;
val=(int)(mat[0][3]/MC_SCALE_X);
val+=1<<(MC_BITS_X-1);
if (val>=(1<<MC_BITS_X))
val=(1<<MC_BITS_X)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_X)|=((unsigned int)(val))<<MC_SHIFT_X;
val=(int)(mat[1][3]/MC_SCALE_Y);
val+=1<<(MC_BITS_Y-1);
if (val>=(1<<MC_BITS_Y))
val=(1<<MC_BITS_Y)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_Y)|=((unsigned int)(val))<<MC_SHIFT_Y;
val=(int)(mat[2][3]/MC_SCALE_Z);
val+=1<<(MC_BITS_Z-1);
if (val>=(1<<MC_BITS_Z))
val=(1<<MC_BITS_Z)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_Z)|=((unsigned int)(val))<<MC_SHIFT_Z;
val=(int)(mat[0][0]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V11)|=((unsigned int)(val))<<MC_SHIFT_V11;
val=(int)(mat[0][1]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V12)|=((unsigned int)(val))<<MC_SHIFT_V12;
val=(int)(mat[0][2]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V13)|=((unsigned int)(val))<<MC_SHIFT_V13;
val=(int)(mat[1][0]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V21)|=((unsigned int)(val))<<MC_SHIFT_V21;
val=(int)(mat[1][1]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V22)|=((unsigned int)(val))<<MC_SHIFT_V22;
val=(int)(mat[1][2]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V23)|=((unsigned int)(val))<<MC_SHIFT_V23;
val=(int)(mat[2][0]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V31)|=((unsigned int)(val))<<MC_SHIFT_V31;
val=(int)(mat[2][1]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V32)|=((unsigned int)(val))<<MC_SHIFT_V32;
val=(int)(mat[2][2]/MC_SCALE_VECT);
val+=1<<(MC_BITS_VECT-1);
if (val>=(1<<MC_BITS_VECT))
val=(1<<MC_BITS_VECT)-1;
if (val<0)
val=0;
*(unsigned int *)(comp+MC_POS_V33)|=((unsigned int)(val))<<MC_SHIFT_V33;
// I added this because the line above actually ORs data into an int at the 22 byte (from 0), and therefore technically
// is writing beyond the 24th byte of the output array. This *should** be harmless if the OR'd-in value doesn't change
// those bytes, but BoundsChecker says that it's accessing undefined memory (which it does, sometimes). This is probably
// bad, so...
memcpy(_comp,comp,MC_COMP_BYTES);
}
void MC_UnCompress(float mat[3][4],const unsigned char * comp)
{
int val;
val=(int)((unsigned short *)(comp))[0];
val-=1<<(MC_BITS_X-1);
mat[0][3]=((float)(val))*MC_SCALE_X;
val=(int)((unsigned short *)(comp))[1];
val-=1<<(MC_BITS_Y-1);
mat[1][3]=((float)(val))*MC_SCALE_Y;
val=(int)((unsigned short *)(comp))[2];
val-=1<<(MC_BITS_Z-1);
mat[2][3]=((float)(val))*MC_SCALE_Z;
val=(int)((unsigned short *)(comp))[3];
val-=1<<(MC_BITS_VECT-1);
mat[0][0]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[4];
val-=1<<(MC_BITS_VECT-1);
mat[0][1]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[5];
val-=1<<(MC_BITS_VECT-1);
mat[0][2]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[6];
val-=1<<(MC_BITS_VECT-1);
mat[1][0]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[7];
val-=1<<(MC_BITS_VECT-1);
mat[1][1]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[8];
val-=1<<(MC_BITS_VECT-1);
mat[1][2]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[9];
val-=1<<(MC_BITS_VECT-1);
mat[2][0]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[10];
val-=1<<(MC_BITS_VECT-1);
mat[2][1]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[11];
val-=1<<(MC_BITS_VECT-1);
mat[2][2]=((float)(val))*MC_SCALE_VECT;
}
/*
cqpoint_t* quaternionIndex;
FILE *out;
extern char *va(char *format, ...);
*/
void MC_UnCompressQuat(float mat[3][4],const unsigned char * comp)
{
/*
float w,x,y,z,f;
float fTx;
float fTy;
float fTz;
float fTwx;
float fTwy;
float fTwz;
float fTxx;
float fTxy;
float fTxz;
float fTyy;
float fTyz;
float fTzz;
int i;
int j;
float f1, f2, f3;
unsigned short index;
float sin_angle,a;
float mult;
float mag;
const unsigned short *pwIn = (unsigned short *) comp;
// read the angle vector index
index = *pwIn++;
// read w
w = *pwIn++;
w /=16383.0f;
w -=2.0f;
if(w < 0)
{
mult = -1.0;
}
else
{
mult = 1.0;
}
if( w > 1.0)
a = 1;
else
a = w;
// compute the sine angle
sin_angle = sqrt( 1.0 - a * a );
// compute x, y, and z
x = quaternionIndex[index].vec[0] * sin_angle * mult;
y = quaternionIndex[index].vec[1] * sin_angle * mult;
z = quaternionIndex[index].vec[2] * sin_angle * mult;
fTx = 2.0f*x;
fTy = 2.0f*y;
fTz = 2.0f*z;
fTwx = fTx*w;
fTwy = fTy*w;
fTwz = fTz*w;
fTxx = fTx*x;
fTxy = fTy*x;
fTxz = fTz*x;
fTyy = fTy*y;
fTyz = fTz*y;
fTzz = fTz*z;
// rot...
//
mat[0][0] = 1.0f-(fTyy+fTzz);
mat[0][1] = fTxy-fTwz;
mat[0][2] = fTxz+fTwy;
mat[1][0] = fTxy+fTwz;
mat[1][1] = 1.0f-(fTxx+fTzz);
mat[1][2] = fTyz-fTwx;
mat[2][0] = fTxz-fTwy;
mat[2][1] = fTyz+fTwx;
mat[2][2] = 1.0f-(fTxx+fTyy);
// xlat...
//
f = *pwIn++;
// RTCDC f = f1;
f/=64;
f-=512;
f1 = f;
mat[0][3] = f;
f = *pwIn++;
// RTCDC f = f2;
f/=64;
f-=512;
f2 = f;
mat[1][3] = f;
f = *pwIn++;
// RTCDC f = f3;
f/=64;
f-=512;
f3 = f;
mat[2][3] = f;
*/
float w,x,y,z,f;
float f1, f2, f3;
const unsigned short *pwIn = (unsigned short *) comp;
w = *pwIn++;
w/=16383.0f;
w-=2.0f;
x = *pwIn++;
x/=16383.0f;
x-=2.0f;
y = *pwIn++;
y/=16383.0f;
y-=2.0f;
z = *pwIn++;
z/=16383.0f;
z-=2.0f;
float fTx = 2.0f*x;
float fTy = 2.0f*y;
float fTz = 2.0f*z;
float fTwx = fTx*w;
float fTwy = fTy*w;
float fTwz = fTz*w;
float fTxx = fTx*x;
float fTxy = fTy*x;
float fTxz = fTz*x;
float fTyy = fTy*y;
float fTyz = fTz*y;
float fTzz = fTz*z;
// rot...
//
mat[0][0] = 1.0f-(fTyy+fTzz);
mat[0][1] = fTxy-fTwz;
mat[0][2] = fTxz+fTwy;
mat[1][0] = fTxy+fTwz;
mat[1][1] = 1.0f-(fTxx+fTzz);
mat[1][2] = fTyz-fTwx;
mat[2][0] = fTxz-fTwy;
mat[2][1] = fTyz+fTwx;
mat[2][2] = 1.0f-(fTxx+fTyy);
// xlat...
//
f = *pwIn++;
f/=64;
f-=512;
f1 = f;
mat[0][3] = f;
f = *pwIn++;
f/=64;
f-=512;
f2 = f;
mat[1][3] = f;
f = *pwIn++;
f/=64;
f-=512;
f3 = f;
mat[2][3] = f;
//OutputDebugString(va("%f %f %f %f, %f %f %f\n", x, y, z, w, f1, f2, f3));
}
////////////////// eof ////////////////

48
tools/ModView/matcomp.h Normal file
View File

@@ -0,0 +1,48 @@
// Filename:- matcomp.h
//
#ifndef MATCOMP_H
#define MATCOMP_H
//#ifdef __cplusplus
//extern "C"
//{
//#endif
#define MC_BITS_X (16)
#define MC_BITS_Y (16)
#define MC_BITS_Z (16)
#define MC_BITS_VECT (16)
#define MC_SCALE_X (1.0f/64)
#define MC_SCALE_Y (1.0f/64)
#define MC_SCALE_Z (1.0f/64)
#define MC_COMP_BYTES 24 //(((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*9)+7)/8)
void MC_Compress(const float mat[3][4],unsigned char * comp);
void MC_UnCompress(float mat[3][4],const unsigned char * comp);
void MC_UnCompressQuat(float mat[3][4],const unsigned char * comp);
/*
typedef float vec_t;
typedef vec_t vec3_t[3];
typedef struct
{
vec3_t vec;
} cqpoint_t;
extern cqpoint_t* quaternionIndex;
extern FILE* out;
*/
//#ifdef __cplusplus
//}
//#endif
#endif // #ifndef MATCOMP_H
///////////// eof ///////////

View File

@@ -0,0 +1,527 @@
// Filename:- mc_compress2
//
//
#include <math.h>
#include <windows.h>
#include "mc_compress2.h"
#include <assert.h>
extern
#ifdef _CARCASS
"C"
#endif
char *va(char *format, ...);
typedef float vec3_t[3];
#ifndef DotProduct
#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
#endif
typedef unsigned char byte;
typedef unsigned short word;
static const float gfEpsilon = 1e-03f;
#define DATA(f0,f1,f2) {f0,f1,f2}
/*static vec3_t v3VecTable[]=
{
};
*/
struct v3Struct_t
{
float f[3];
bool operator < (const v3Struct_t& _X) const {return (memcmp(f,_X.f,sizeof(f))<0);}
};
#pragma warning ( disable : 4786)
#include <map>
#include <string>
#pragma warning ( disable : 4786)
using namespace std;
typedef map<v3Struct_t,int> Table_t;
Table_t Table;
typedef map <string, float> Thing_t;
Thing_t Thing;
void crap(void)
{
OutputDebugString(va("Table size %d\n",Thing.size()));
for (Thing_t::iterator it = Thing.begin(); it!=Thing.end(); ++it)
{
const string *str = &((*it).first);
float f = (*it).second;
OutputDebugString(va("(%s) %f\n",str->c_str(),f));
}
/* OutputDebugString(va("Table size %d\n",Table.size()));
int iHighestUsageCount = 0;
int iEntry=0;
for (Table_t::iterator it = Table.begin(); it!= Table.end(); ++it)
{
v3Struct_t v3 = (*it).first;
//OutputDebugString(va("(%d) %f %f %f\n",iEntry,v3.f[0],v3.f[1],v3.f[2]));
int iUsage = (*it).second;
if (iUsage > iHighestUsageCount)
{
iHighestUsageCount = iUsage;
}
iEntry++;
}
OutputDebugString(va("Highest usage count = %d\n",iHighestUsageCount));
*/
}
inline float ACos (float fValue)
{
if ( -1.0f < fValue )
{
if ( fValue < 1.0f )
return (float)acos(fValue);
else
return 0.0f;
}
else
{
return (float) 3.14159265358979323846264;//PI;
}
}
static void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross )
{
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
static inline word SquashFloat(float f)
{
// assert(f >= -2 && f <= 2);
if (!(f >= -2 && f <= 2))
{
#ifdef _CARCASS
// crap for carcass so I collect all bad errors together before finally exiting
//
extern bool gbSquashFloatError;
if (!gbSquashFloatError)
{
printf("SquashFloat(): Fatal Error: f = %f ( range permitted: -2..2 )\n",f);
gbSquashFloatError = true;
}
#elif _MODVIEW
assert(0);
#endif
return 0;
}
f+= 2.0f; // range 0..4
f*= 16383.0f;
int iVal = f;
assert(iVal <= 65535);
return (word) iVal&65535;
}
static inline float UnSquashFloat(word w)
{
float f = w;
f/=16383.0f; //32767.0f;
f-=2.0f; //1.0f;
assert(f >= -2.0f && f<= 2.0f);
return f;
}
static inline float UnSquashXlatFloat(word w)
{
float
f = w;
f/=64;
f-=512;
return f;
}
static inline word SquashXlatFloat(float f)
{
// assert(f >= -511 && f <= 511);
if (!(f >= -511 && f <= 511))
{
#ifdef _CARCASS
// crap for carcass so I collect all bad errors together before finally exiting
//
extern bool gbSquashFloatError;
if (!gbSquashFloatError)
{
printf("SquashXlatFloat(): Fatal Error: bone translation = %f ( range permitted: -511..511 )\n( Recompile this model using carcass_prequat.exe instead )\n",f);
gbSquashFloatError = true;
}
#elif _MODVIEW
assert(0);
#endif
return 0;
}
f+= 512;
f*=64;
#ifdef _DEBUG
int iVal = (int)f;
assert( iVal >= 0 && iVal <= 65535);
#endif
word w = (word) f;
return w;
}
class Xlat
{
public:
float x,y,z;
Xlat(); // do nothing in constructor
const word *FromComp (const byte *pComp);
word *ToComp (byte *pComp);
};
const word *Xlat::FromComp(const byte *pComp)
{
const word *pwIn = (word *) pComp;
x= UnSquashXlatFloat(*pwIn++);
y= UnSquashXlatFloat(*pwIn++);
z= UnSquashXlatFloat(*pwIn++);
return pwIn;
}
word *Xlat::ToComp(byte *pComp)
{
word *pwOut = (word *) pComp;
*pwOut++ = SquashXlatFloat(x);
*pwOut++ = SquashXlatFloat(y);
*pwOut++ = SquashXlatFloat(z);
return pwOut;
}
class Quaternion
{
public:
float w,x,y,z;
Quaternion(); // do nothing in default constructor
Quaternion(float fW, float fX, float fY, float fZ);
Quaternion(const Quaternion& rkQ);
const word *FromComp (const byte *pComp);
word *ToComp (byte *pComp) const;
void To3x4 (float kRot[3][4]) const;
float Dot (const Quaternion& Q) const;
Quaternion Slerp (float fT, const Quaternion& rkP, const Quaternion& rkQ);
Quaternion& operator= (const Quaternion& rkQ);
Quaternion operator+ (const Quaternion& rkQ) const;
Quaternion operator- (const Quaternion& rkQ) const;
Quaternion operator* (const Quaternion& rkQ) const;
Quaternion operator* (float fScalar) const;
};
Quaternion::Quaternion (void)
{
}
Quaternion::Quaternion (float fW, float fX, float fY, float fZ)
{
w = fW;
x = fX;
y = fY;
z = fZ;
}
Quaternion::Quaternion (const Quaternion& rkQ)
{
w = rkQ.w;
x = rkQ.x;
y = rkQ.y;
z = rkQ.z;
}
Quaternion& Quaternion::operator= (const Quaternion& rkQ)
{
w = rkQ.w;
x = rkQ.x;
y = rkQ.y;
z = rkQ.z;
return *this;
}
Quaternion Quaternion::operator+ (const Quaternion& rkQ) const
{
return Quaternion(w+rkQ.w,x+rkQ.x,y+rkQ.y,z+rkQ.z);
}
Quaternion Quaternion::operator- (const Quaternion& rkQ) const
{
return Quaternion(w-rkQ.w,x-rkQ.x,y-rkQ.y,z-rkQ.z);
}
Quaternion Quaternion::operator* (const Quaternion& rkQ) const
{
// NOTE: Multiplication is not generally commutative, so in most
// cases p*q != q*p.
return Quaternion
(
w*rkQ.w-x*rkQ.x-y*rkQ.y-z*rkQ.z,
w*rkQ.x+x*rkQ.w+y*rkQ.z-z*rkQ.y,
w*rkQ.y+y*rkQ.w+z*rkQ.x-x*rkQ.z,
w*rkQ.z+z*rkQ.w+x*rkQ.y-y*rkQ.x
);
}
Quaternion Quaternion::operator* (float fScalar) const
{
return Quaternion(fScalar*w,fScalar*x,fScalar*y,fScalar*z);
}
float Quaternion::Dot(const Quaternion& Q) const
{
return w*Q.w + x*Q.x + y*Q.y + z*Q.z;
}
const word *Quaternion::FromComp(const byte *pComp)
{
const word *pwIn = (word *) pComp;
w = UnSquashFloat(*pwIn++);
x = UnSquashFloat(*pwIn++);
y = UnSquashFloat(*pwIn++);
z = UnSquashFloat(*pwIn++);
return pwIn;
}
word *Quaternion::ToComp(byte *pComp) const
{
word *pwOut = (word *) pComp;
*pwOut++ = SquashFloat(w);
*pwOut++ = SquashFloat(x);
*pwOut++ = SquashFloat(y);
*pwOut++ = SquashFloat(z); // 8 bytes
#ifdef _DEBUG
// measure biggest deviation...
//
#define __BLAH(_l) \
static float fMin ## _l = 0.0f, fMax ## _l = 0.0f; \
if ( _l < fMin ## _l){ \
fMin ## _l = _l; \
Thing["fMin" #_l] = _l; \
} \
if ( _l > fMax ## _l){ \
fMax ## _l = _l; \
Thing["fMax" #_l] = _l; \
}
__BLAH(w);
__BLAH(x);
__BLAH(y);
__BLAH(z);
#endif
return pwOut;
}
void Quaternion::To3x4(float kRot[3][4]) const
{
float fTx = 2.0f*x;
float fTy = 2.0f*y;
float fTz = 2.0f*z;
float fTwx = fTx*w;
float fTwy = fTy*w;
float fTwz = fTz*w;
float fTxx = fTx*x;
float fTxy = fTy*x;
float fTxz = fTz*x;
float fTyy = fTy*y;
float fTyz = fTz*y;
float fTzz = fTz*z;
kRot[0][0] = 1.0f-(fTyy+fTzz);
kRot[0][1] = fTxy-fTwz;
kRot[0][2] = fTxz+fTwy;
kRot[1][0] = fTxy+fTwz;
kRot[1][1] = 1.0f-(fTxx+fTzz);
kRot[1][2] = fTyz-fTwx;
kRot[2][0] = fTxz-fTwy;
kRot[2][1] = fTyz+fTwx;
kRot[2][2] = 1.0f-(fTxx+fTyy);
}
//----------------------------------------------------------------------------
Quaternion Quaternion::Slerp (float fT, const Quaternion& rkP,
const Quaternion& rkQ)
{
float fCos = rkP.Dot(rkQ);
float fAngle = ACos(fCos);
if ( fabs(fAngle) < gfEpsilon )
return rkP;
float fSin = sin(fAngle);
float fInvSin = 1.0f/fSin;
float fCoeff0 = sin((1.0f-fT)*fAngle)*fInvSin;
float fCoeff1 = sin(fT*fAngle)*fInvSin;
return rkP*fCoeff0 + rkQ*fCoeff1;
}
void Quaternion_3x4ToComp (const float kRot[3][4], unsigned char *pComp)
{
Quaternion Q;
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
// article "Quaternion Calculus and Fast Animation".
float fTrace = kRot[0][0]+kRot[1][1]+kRot[2][2];
float fRoot;
if ( fTrace > 0.0f )
{
// |w| > 1/2, may as well choose w > 1/2
fRoot = sqrt(fTrace + 1.0f); // 2w
Q.w = 0.5f*fRoot;
fRoot = 0.5f/fRoot; // 1/(4w)
Q.x = (kRot[2][1]-kRot[1][2])*fRoot;
Q.y = (kRot[0][2]-kRot[2][0])*fRoot;
Q.z = (kRot[1][0]-kRot[0][1])*fRoot;
}
else
{
// |w| <= 1/2
static int s_iNext[3] = { 1, 2, 0 };
int i = 0;
if ( kRot[1][1] > kRot[0][0] )
i = 1;
if ( kRot[2][2] > kRot[i][i] )
i = 2;
int j = s_iNext[i];
int k = s_iNext[j];
fRoot = sqrt(kRot[i][i]-kRot[j][j]-kRot[k][k] + 1.0f);
float* apkQuat[3] = { &Q.x, &Q.y, &Q.z };
*apkQuat[i] = 0.5f*fRoot;
fRoot = 0.5f/fRoot;
Q.w = (kRot[k][j]-kRot[j][k])*fRoot;
*apkQuat[j] = (kRot[j][i]+kRot[i][j])*fRoot;
*apkQuat[k] = (kRot[k][i]+kRot[i][k])*fRoot;
}
// copy out to dest arg...
//
word *pwOut = Q.ToComp(pComp);
// xlat...
//
*pwOut++ = SquashXlatFloat(kRot[0][3]);
*pwOut++ = SquashXlatFloat(kRot[1][3]);
*pwOut++ = SquashXlatFloat(kRot[2][3]);
}
//----------------------------------------------------------------------------
void Quaternion_3x4FromComp (float kRot[3][4], const byte *pComp)
{
Quaternion Q;
const word *pwIn = Q.FromComp(pComp);
Q.To3x4(kRot);
// xlat...
//
kRot[0][3] = UnSquashXlatFloat(*pwIn++);
kRot[1][3] = UnSquashXlatFloat(*pwIn++);
kRot[2][3] = UnSquashXlatFloat(*pwIn++);
}
void QuatSlerpCompTo3x4( float fLerp0_1,
const byte *pComp0,
const byte *pComp1,
float fDestMat[3][4]
)
{
assert(fLerp0_1 >= 0.0f && fLerp0_1 <= 1.0f);
Quaternion Q0,Q1;
float tx0,ty0,tz0; // xlats
float tx1,ty1,tz1; //
// unpack 0...
//
const word *
pwIn = Q0.FromComp(pComp0);
//
// and xlat...
//
tx0 = UnSquashXlatFloat(*pwIn++);
ty0 = UnSquashXlatFloat(*pwIn++);
tz0 = UnSquashXlatFloat(*pwIn++);
// unpack 1...
//
pwIn = Q1.FromComp(pComp1);
//
// and xlat...
//
tx1 = UnSquashXlatFloat(*pwIn++);
ty1 = UnSquashXlatFloat(*pwIn++);
tz1 = UnSquashXlatFloat(*pwIn++);
// slerp...
//
Quaternion Q2;
Q2 = Q2.Slerp(1.0f-fLerp0_1, Q0, Q1);
Q2.To3x4(fDestMat);
// lerp the xlat...
//
fDestMat[0][3] = (fLerp0_1 * tx0) + ((1.0 - fLerp0_1) * tx1);
fDestMat[1][3] = (fLerp0_1 * ty0) + ((1.0 - fLerp0_1) * ty1);
fDestMat[2][3] = (fLerp0_1 * tz0) + ((1.0 - fLerp0_1) * tz1);
}
// outputs 14 bytes
//
void MC_Compress2(const float mat[3][4],unsigned char *comp)
{
Quaternion_3x4ToComp(mat, comp);
}
void MC_UnCompress2(float mat[3][4],const unsigned char * comp)
{
Quaternion_3x4FromComp( mat, comp);
}

View File

@@ -0,0 +1,32 @@
// Filename: mc_compress2.h
//
#ifndef MC_COMPRESS2_H
#define MC_COMPRESS2_H
#ifdef __cplusplus
extern "C"
{
#endif
#pragma optimize( "p", on ) // improve floating-point consistancy (makes release do bone-pooling as good as debug)
void MC_Compress2(const float mat[3][4],unsigned char * comp);
void MC_UnCompress2(float mat[3][4],const unsigned char * comp);
void QuatSlerpCompTo3x4( float fLerp01,
const unsigned char *pComp0,
const unsigned char *pComp1,
float fDestMat[3][4]
);
#ifdef __cplusplus
}
#endif
#endif // #ifndef MC_COMPRESS2_H
///////////// eof /////////////

118
tools/ModView/md3_format.h Normal file
View File

@@ -0,0 +1,118 @@
// Filename:- md3_format.h
//
//
#ifndef MD3_FORMAT_H
#define MD3_FORMAT_H
#define MD3_IDENT (('3'<<24)+('P'<<16)+('D'<<8)+'I')
#define MD3_VERSION 15
// limits
#define MD3_MAX_LODS 3
#define MD3_MAX_TRIANGLES 8192 // per surface
#define MD3_MAX_VERTS 4096 // per surface
#define MD3_MAX_SHADERS 256 // per surface
#define MD3_MAX_FRAMES 1024 // per model
#define MD3_MAX_SURFACES 32 // per model
#define MD3_MAX_TAGS 16 // per frame
// vertex scales
#define MD3_XYZ_SCALE (1.0/64)
typedef struct md3Frame_s {
vec3_t bounds[2];
vec3_t localOrigin;
float radius;
char name[16];
} md3Frame_t;
typedef struct md3Tag_s {
char name[MAX_QPATH]; // tag name
vec3_t origin;
vec3_t axis[3];
} md3Tag_t;
/*
** md3Surface_t
**
** CHUNK SIZE
** header sizeof( md3Surface_t )
** shaders sizeof( md3Shader_t ) * numShaders
** triangles[0] sizeof( md3Triangle_t ) * numTriangles
** st sizeof( md3St_t ) * numVerts
** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
*/
typedef struct {
int ident; //
char name[MAX_QPATH]; // polyset name
int flags;
int numFrames; // all surfaces in a model should have the same
int numShaders; // all surfaces in a model should have the same
int numVerts;
int numTriangles;
int ofsTriangles;
int ofsShaders; // offset from start of md3Surface_t
int ofsSt; // texture coords are common for all frames
int ofsXyzNormals; // numVerts * numFrames
int ofsEnd; // next surface follows
} md3Surface_t;
typedef struct {
char name[MAX_QPATH];
int shaderIndex; // for in-game use
} md3Shader_t;
typedef struct {
int indexes[3];
} md3Triangle_t;
typedef struct {
float st[2];
} md3St_t;
typedef struct {
short xyz[3];
short normal;
} md3XyzNormal_t;
typedef struct {
int ident;
int version;
char name[MAX_QPATH]; // model name
int flags;
int numFrames;
int numTags;
int numSurfaces;
int numSkins;
int ofsFrames; // offset for first frame
int ofsTags; // numFrames * numTags
int ofsSurfaces; // first surface, others follow
int ofsEnd; // end of file
} md3Header_t;
#endif // #ifndef MD3_FORMAT_H
////////////////// eof ///////////////

103
tools/ModView/mdr_format.h Normal file
View File

@@ -0,0 +1,103 @@
// Filename:- mdr_format.h
//
//
#ifndef MDR_FORMAT_H
#define MDR_FORMAT_H
#define MD4_IDENT (('4'<<24)+('P'<<16)+('D'<<8)+'I')
#define MD4_VERSION 1
#define MD4_MAX_BONES 128
typedef struct {
int boneIndex; // these are indexes into the boneReferences,
float boneWeight; // not the global per-frame bone list
vec3_t offset;
} md4Weight_t;
typedef struct {
vec3_t normal;
vec2_t texCoords;
int numWeights;
md4Weight_t weights[1]; // variable sized
} md4Vertex_t;
typedef struct {
int indexes[3];
} md4Triangle_t;
typedef struct {
int ident;
char name[MAX_QPATH]; // polyset name
char shader[MAX_QPATH];
int shaderIndex; // for in-game use
int ofsHeader; // this will be a negative number
int numVerts;
int ofsVerts;
int numTriangles;
int ofsTriangles;
// Bone references are a set of ints representing all the bones
// present in any vertex weights for this surface. This is
// needed because a model may have surfaces that need to be
// drawn at different sort times, and we don't want to have
// to re-interpolate all the bones for each surface.
int numBoneReferences;
int ofsBoneReferences;
int ofsEnd; // next surface follows
} md4Surface_t;
typedef struct {
float matrix[3][4];
} md4Bone_t;
typedef struct {
vec3_t bounds[2]; // bounds of all surfaces of all LOD's for this frame
vec3_t localOrigin; // midpoint of bounds, used for sphere cull
float radius; // dist from localOrigin to corner
char name[16];
md4Bone_t bones[1]; // [numBones]
} md4Frame_t;
typedef struct {
int numSurfaces;
int ofsSurfaces; // first surface, others follow
int ofsEnd; // next lod follows
} md4LOD_t;
typedef struct {
int ident;
int version;
char name[MAX_QPATH]; // model name
// frames and bones are shared by all levels of detail
int numFrames;
int numBones;
int ofsFrames; // md4Frame_t[numFrames]
// each level of detail has completely separate sets of surfaces
int numLODs;
int ofsLODs;
int ofsEnd; // end of file
} md4Header_t;
#endif // #ifndef MDR_FORMAT_H
////////////////// eof ///////////////

423
tools/ModView/mdx_format.h Normal file
View File

@@ -0,0 +1,423 @@
// Filename:- mdx_format.h
//
// DO NOT UPDATE THIS FILE IN ANY WAY WHATSOEVER WITHOUT TELLING ME (-Ste),
// BECAUSE THE MASTER COPY IS IN A DIFFERENT SOURCESAFE DATABASE AND WILL
// JUST GET PASTED OVER THIS ONE WHENEVER I CHANGE IT.
//
//
//
// MDX file format (typically uses file extension GLX for mesh, and GLA for anim/skeleton file)
//
// Notes:
//
// - All offset fields are relative to the address of the structure they occur in
// - So far, the only external symbol needed is MAX_QPATH, plus the typedefs for vec3_t, vec2_t etc
#ifndef MDX_FORMAT_H
#define MDX_FORMAT_H
#define MDXM_IDENT (('M'<<24)+('G'<<16)+('L'<<8)+'2')
#define MDXA_IDENT (('A'<<24)+('G'<<16)+('L'<<8)+'2')
#define MAX_TAGNAME_BYTES 32 // matches MDR, can be changed if nec.
//
// normal version numbers...
//
#define MDXM_VERSION 6
#define MDXA_VERSION 6
// (Note that since there is now a "<modelname>_info.txt" file written out by carcass any changes made in here that
// introduce new data should also be reflected in the info-output)
// 32 bit-flags for ghoul2 bone properties... (all undefined fields will be blank)
//
#define G2BONEFLAG_ALWAYSXFORM 0x00000001
// same thing but for surfaces... (Carcass will only generate 1st 2 flags, others are ingame
//
#define G2SURFACEFLAG_ISBOLT 0x00000001
#define G2SURFACEFLAG_OFF 0x00000002 // saves strcmp()ing for "_off" in surface names
#define G2SURFACEFLAG_SPARE0 0x00000004 // future-expansion fields, saves invalidating models if we add more
#define G2SURFACEFLAG_SPARE1 0x00000008 //
#define G2SURFACEFLAG_SPARE2 0x00000010 //
#define G2SURFACEFLAG_SPARE3 0x00000020 //
#define G2SURFACEFLAG_SPARE4 0x00000040 //
#define G2SURFACEFLAG_SPARE5 0x00000080 //
//
#define G2SURFACEFLAG_NODESCENDANTS 0x00000100 // ingame-stuff, never generated by Carcass....
#define G2SURFACEFLAG_GENERATED 0x00000200 //
// triangle side-ordering stuff for tags...
//
#define iG2_TRISIDE_MIDDLE 1
#define iG2_TRISIDE_LONGEST 0
#define iG2_TRISIDE_SHORTEST 2
#define fG2_BONEWEIGHT_RECIPROCAL_MULT ((float)(1.0f/1023.0f))
#define iG2_BITS_PER_BONEREF 5
#define iMAX_G2_BONEREFS_PER_SURFACE (1<<iG2_BITS_PER_BONEREF) // (32)
#define iMAX_G2_BONEWEIGHTS_PER_VERT 4 // can't just be blindly increased, affects cache size etc
#define iG2_BONEWEIGHT_TOPBITS_SHIFT ((iG2_BITS_PER_BONEREF * iMAX_G2_BONEWEIGHTS_PER_VERT) - 8) // 8 bits because of 8 in the BoneWeight[] array entry
#define iG2_BONEWEIGHT_TOPBITS_AND 0x300 // 2 bits, giving 10 total, or 10 bits, for 1023/1024 above
#define sDEFAULT_GLA_NAME "*default" // used when making special simple ghoul2 models, usually from MD3 files
////////////////////////////////////
//
// these structs are defined here purely because of structure dependancy order...
//
/*
#ifdef __cplusplus
struct mdxmWeight_t
#else
typedef struct
#endif
{
int boneIndex; // these are indexes into the surface boneReferences, not the global bone index
float boneWeight; // not the global per-frame bone list
// I'm defining this '<' operator so this struct can be used with an STL <set>...
// (note that I've defined it using '>' internally, so it sorts with higher weights being "less", for distance weight-culling
//
#ifdef __cplusplus
bool operator < (const mdxmWeight_t& _X) const {return (boneWeight>_X.boneWeight);}
#endif
}
#ifndef __cplusplus
mdxmWeight_t
#endif
;
*/
/*
#ifdef __cplusplus
struct mdxaCompBone_t
#else
typedef struct
#endif
{
unsigned char Comp[24]; // MC_COMP_BYTES is in MatComp.h, but don't want to couple
// I'm defining this '<' operator so this struct can be used as an STL <map> key...
//
#ifdef __cplusplus
bool operator < (const mdxaCompBone_t& _X) const {return (memcmp(Comp,_X.Comp,sizeof(Comp))<0);}
#endif
}
#ifndef __cplusplus
mdxaCompBone_t
#endif
;
*/
#ifdef __cplusplus
struct mdxaCompQuatBone_t
#else
typedef struct
#endif
{
unsigned char Comp[14];
// I'm defining this '<' operator so this struct can be used as an STL <map> key...
//
#ifdef __cplusplus
bool operator < (const mdxaCompQuatBone_t& _X) const {return (memcmp(Comp,_X.Comp,sizeof(Comp))<0);}
#endif
}
#ifndef __cplusplus
mdxaCompQuatBone_t
#endif
;
#ifndef MDXABONEDEF
typedef struct {
float matrix[3][4];
} mdxaBone_t;
#endif
////////////////////////////////////
// mdxHeader_t - this contains the header for the file, with sanity checking and version checking, plus number of lod's to be expected
//
typedef struct {
//
// ( first 3 fields are same format as MD3/MDR so we can apply easy model-format-type checks )
//
int ident; // "IDP3" = MD3, "RDM5" = MDR, "2LGM"(GL2 Mesh) = MDX (cruddy char order I know, but I'm following what was there in other versions)
int version; // 1,2,3 etc as per format revision
char name[MAX_QPATH]; // model name (eg "models/players/marine.glm") // note: extension supplied
char animName[MAX_QPATH];// name of animation file this mesh requires // note: extension missing
int animIndex; // filled in by game (carcass defaults it to 0)
int numBones; // (for ingame version-checks only, ensure we don't ref more bones than skel file has)
int numLODs;
int ofsLODs;
int numSurfaces; // now that surfaces are drawn hierarchically, we have same # per LOD
int ofsSurfHierarchy;
int ofsEnd; // EOF, which of course gives overall file size
} mdxmHeader_t;
// for each surface (doesn't actually need a struct for this, just makes source clearer)
// {
typedef struct
{
int offsets[1]; // variable sized (mdxmHeader_t->numSurfaces), each offset points to a mdxmSurfHierarchy_t below
} mdxmHierarchyOffsets_t;
// }
// for each surface... (mdxmHeader_t->numSurfaces)
// {
// mdxmSurfHierarchy_t - contains hierarchical info for surfaces...
typedef struct {
char name[MAX_QPATH];
unsigned int flags;
char shader[MAX_QPATH];
int shaderIndex; // for in-game use (carcass defaults to 0)
int parentIndex; // this points to the index in the file of the parent surface. -1 if null/root
int numChildren; // number of surfaces which are children of this one
int childIndexes[1]; // [mdxmSurfHierarch_t->numChildren] (variable sized)
} mdxmSurfHierarchy_t; // struct size = (int)( &((mdxmSurfHierarch_t *)0)->childIndexes[ mdxmSurfHierarch_t->numChildren ] );
// }
// for each LOD... (mdxmHeader_t->numLODs)
// {
// mdxLOD_t - this contains the header for this LOD. Contains num of surfaces, offset to surfaces and offset to next LOD. Surfaces are shader sorted, so each surface = 1 shader
typedef struct {
// (used to contain numSurface/ofsSurfaces fields, but these are same per LOD level now)
//
int ofsEnd; // offset to next LOD
} mdxmLOD_t;
typedef struct { // added in GLM version 3 for ingame use at Jake's request
int offsets[1]; // variable sized (mdxmHeader_t->numSurfaces), each offset points to surfaces below
} mdxmLODSurfOffset_t;
// for each surface... (mdxmHeader_t->numSurfaces)
// {
// mdxSurface_t - reuse of header format containing surface name, number of bones, offset to poly data and number of polys, offset to vertex information, and number of verts. NOTE offsets are relative to this header.
typedef struct {
int ident; // this one field at least should be kept, since the game-engine may switch-case (but currently=0 in carcass)
int thisSurfaceIndex; // 0...mdxmHeader_t->numSurfaces-1 (because of how ingame renderer works)
int ofsHeader; // this will be a negative number, pointing back to main header
int numVerts;
int ofsVerts;
int numTriangles;
int ofsTriangles;
// Bone references are a set of ints representing all the bones
// present in any vertex weights for this surface. This is
// needed because a model may have surfaces that need to be
// drawn at different sort times, and we don't want to have
// to re-interpolate all the bones for each surface.
//
int numBoneReferences;
int ofsBoneReferences;
int ofsEnd; // next surface follows
} mdxmSurface_t;
// for each triangle... (mdxmSurface_t->numTriangles)
// {
// mdxTriangle_t - contains indexes into verts. One struct entry per poly.
typedef struct {
int indexes[3];
} mdxmTriangle_t;
// }
// for each vert... (mdxmSurface_t->numVerts)
// {
// mdxVertex_t - this is an array with number of verts from the surface definition as its bounds. It contains normal info, texture coors and number of weightings for this bone
// (this is now kept at 32 bytes for cache-aligning)
typedef struct {
vec3_t normal;
vec3_t vertCoords;
// packed int...
unsigned int uiNmWeightsAndBoneIndexes; // 32 bits. format:
// 31 & 30: 0..3 (= 1..4) weight count
// 29 & 28 (spare)
// 2 bit pairs at 20,22,24,26 are 2-bit overflows from 4 BonWeights below (20=[0], 22=[1]) etc)
// 5-bits each (iG2_BITS_PER_BONEREF) for boneweights
// effectively a packed int, each bone weight converted from 0..1 float to 0..255 int...
// promote each entry to float and multiply by fG2_BONEWEIGHT_RECIPROCAL_MULT to convert.
byte BoneWeightings[iMAX_G2_BONEWEIGHTS_PER_VERT]; // 4
} mdxmVertex_t;
// } vert
#ifdef __cplusplus
// these are convenience functions that I can invoked in code. Do NOT change them (because this is a shared file),
// but if you want to copy the logic out and use your own versions then fine...
//
static inline int G2_GetVertWeights( const mdxmVertex_t *pVert )
{
int iNumWeights = (pVert->uiNmWeightsAndBoneIndexes >> 30)+1; // 1..4 count
return iNumWeights;
}
static inline int G2_GetVertBoneIndex( const mdxmVertex_t *pVert, const int iWeightNum)
{
int iBoneIndex = (pVert->uiNmWeightsAndBoneIndexes>>(iG2_BITS_PER_BONEREF*iWeightNum))&((1<<iG2_BITS_PER_BONEREF)-1);
return iBoneIndex;
}
static inline float G2_GetVertBoneWeight( const mdxmVertex_t *pVert, const int iWeightNum, float &fTotalWeight, int iNumWeights )
{
float fBoneWeight;
if (iWeightNum == iNumWeights-1)
{
fBoneWeight = 1.0f-fTotalWeight;
}
else
{
int iTemp = pVert->BoneWeightings[iWeightNum];
iTemp|= (pVert->uiNmWeightsAndBoneIndexes >> (iG2_BONEWEIGHT_TOPBITS_SHIFT+(iWeightNum*2)) ) & iG2_BONEWEIGHT_TOPBITS_AND;
fBoneWeight = fG2_BONEWEIGHT_RECIPROCAL_MULT * iTemp;
fTotalWeight += fBoneWeight;
}
return fBoneWeight;
}
#endif
// for each vert... (mdxmSurface_t->numVerts) (seperated from mdxmVertex_t struct for cache reasons)
// {
// mdxVertex_t - this is an array with number of verts from the surface definition as its bounds. It contains normal info, texture coors and number of weightings for this bone
typedef struct {
vec2_t texCoords;
} mdxmVertexTexCoord_t;
// } vert
// } surface
// } LOD
//----------------------------------------------------------------------------
// seperate file here for animation data...
//
// mdxaHeader_t - this contains the header for the file, with sanity checking and version checking, plus number of lod's to be expected
//
typedef struct {
//
// ( first 3 fields are same format as MD3/MDR so we can apply easy model-format-type checks )
//
int ident; // "IDP3" = MD3, "RDM5" = MDR, "2LGA"(GL2 Anim) = MDXA
int version; // 1,2,3 etc as per format revision
//
char name[MAX_QPATH]; // GLA name (eg "skeletons/marine") // note: extension missing
float fScale; // will be zero if build before this field was defined, else scale it was built with
// frames and bones are shared by all levels of detail
//
int numFrames;
int ofsFrames; // points at mdxaFrame_t array
int numBones; // (no offset to these since they're inside the frames array)
int ofsCompBonePool; // offset to global compressed-bone pool that all frames use
int ofsSkel; // offset to mdxaSkel_t info
int ofsEnd; // EOF, which of course gives overall file size
} mdxaHeader_t;
// for each bone... (doesn't actually need a struct for this, just makes source clearer)
// {
typedef struct
{
int offsets[1]; // variable sized (mdxaHeader_t->numBones), each offset points to an mdxaSkel_t below
} mdxaSkelOffsets_t;
// }
// for each bone... (mdxaHeader_t->numBones)
// {
// mdxaSkel_t - contains hierarchical info only...
typedef struct {
char name[MAX_QPATH]; // name of bone
unsigned int flags;
int parent; // index of bone that is parent to this one, -1 = NULL/root
mdxaBone_t BasePoseMat; // base pose
mdxaBone_t BasePoseMatInv; // inverse, to save run-time calc
int numChildren; // number of children bones
int children[1]; // [mdxaSkel_t->numChildren] (variable sized)
} mdxaSkel_t; // struct size = (int)( &((mdxaSkel_t *)0)->children[ mdxaSkel_t->numChildren ] );
// }
// (offset @ mdxaHeader_t->ofsFrames)
//
// array of 3 byte indices here (hey, 25% saving over 4-byte really adds up)...
//
//
// access as follows to get the index for a given <iFrameNum, iBoneNum>
//
// (iFrameNum * mdxaHeader_t->numBones * 3) + (iBoneNum * 3)
//
// then read the int at that location and AND it with 0x00FFFFFF. I use the struct below simply for easy searches
typedef struct
{
int iIndex; // this struct for pointing purposes, need to and with 0x00FFFFFF to be meaningful
} mdxaIndex_t;
//
// (note that there's then an alignement-pad here to get the next struct back onto 32-bit alignement)
//
// this index then points into the following...
// Compressed-bone pool that all frames use (mdxaHeader_t->ofsCompBonePool) (defined at end because size unknown until end)
// for each bone in pool (unknown number, no actual total stored at the moment)...
// {
// mdxaCompBone_t (defined at file top because of struct dependancy)
// }
//---------------------------------------------------------------------------
#endif // #ifndef MDX_FORMAT_H
//////////////////////// eof ///////////////////////

5588
tools/ModView/model.cpp Normal file

File diff suppressed because it is too large Load Diff

437
tools/ModView/model.h Normal file
View File

@@ -0,0 +1,437 @@
// Filename:- model.h
//
#ifndef MODEL_H
#define MODEL_H
#include "stl.h"
////////////////////////////////////////////////
//
typedef struct
{
union
{
struct
{
unsigned int iItemType : 8; // allows 256 item types (see #defines below)
unsigned int iModelHandle : 8; // allows 256 models
unsigned int iItemNumber : 16; // allows 65536 surfaces, bones, sequences etc
};
//
UINT32 uiData;
};
} TreeItemData_t;
// max 256 of these...
//
typedef enum
{
TREEITEMTYPE_NULL=0, // nothing, ie usually a reasonable default for clicking on emptry tree space
TREEITEMTYPE_MODELNAME, // "modelname"
TREEITEMTYPE_SURFACEHEADER, // "surfaces"
TREEITEMTYPE_TAGSURFACEHEADER, // "tag surfaces"
TREEITEMTYPE_BONEHEADER, // "bones"
TREEITEMTYPE_BONEALIASHEADER, // "bone aliases"
TREEITEMTYPE_SEQUENCEHEADER, // "sequences"
TREEITEMTYPE_BOLTONSHEADER, // "BoltOns"
TREEITEMTYPE_SKINSHEADER, // "Skins available"
TREEITEMTYPE_OLDSKINSHEADER, // "Skins available"
//
// Ones beyond here should have updated code in ModelTree_GetItemText() to handle pure enquiries if nec.
//
TREEITEMTYPE_GLM_SURFACE, // a surface (index in bottom bits, currently allows 65535 surfaces)
TREEITEMTYPE_GLM_TAGSURFACE, // a surface (index in bottom bits, currently allows 65535 surfaces)
TREEITEMTYPE_GLM_BONE, // a bone (index in bottom bits, currently allows 65535 bones)
TREEITEMTYPE_GLM_BONEALIAS, // a bone alias (index in bottom bits, currently allows 65535 aliases)
TREEITEMTYPE_SEQUENCE, // a sequence (index in bottom bits, currently allows 65535 bones)
TREEITEMTYPE_SKIN, // (eg "thug")
TREEITEMTYPE_SKINETHNIC, // (eg "white")
TREEITEMTYPE_SKINMATERIAL, // (eg "face")
TREEITEMTYPE_SKINMATERIALSHADER,// (eg "models/characters/face/thug1")
TREEITEMTYPE_OLDSKIN, // (eg "blue")
} TreeTypes_e;
//
////////////////////////////////////////////////
struct ModelContainer;
typedef struct ModelContainer ModelContainer_t;
typedef vector <bool> VertIsEdge_t;
typedef map <int, VertIsEdge_t> SurfaceEdgeVertBools_t;
typedef map <int, SurfaceEdgeVertBools_t> SurfaceEdgeInfoPerLOD_t;
#include "glm_code.h"
// I wanted to put this in sequence.h, but C is crap for interdependant compiles
//
typedef struct
{
char sName[MAX_QPATH]; // eg "run1"
char sNameWithPath[2048]; // new, for tree-display purposes only. These can be REALLY long for SOF2 on drive M:
int iStartFrame;
int iFrameCount;
int iLoopFrame; // -1 for no wrap, else framenum to add to iStartFrame
int iFPS; // can be -ve for CHC to indicate backwards anims, not currently used for speed purposes though
// bool bMultiSeq;
bool bIsDefault; // only true if no anim/enum file found
} Sequence_t;
typedef vector <Sequence_t> SequenceList_t;
#include "skins.h"
#include "oldskins.h"
// I need this structure to carry any extra baggage around such as Jake's wacky bone stuff for G2...
//
// update ModelContainer_Clear() when you update this struct!
//
// (Note that these same equates are used for either surfaces or bones, but some only make sense for one or the other)
//
#define iITEMHIGHLIGHT_ALL_TAGSURFACES -4
#define iITEMHIGHLIGHT_ALIASED -3
#define iITEMHIGHLIGHT_ALL -2
#define iITEMHIGHLIGHT_NONE -1
//#define iBONEHIGHLIGHT_all_other_numbers_from_0_to_(n) // :-)
typedef struct
{
float fMat[16];
} MyGLMatrix_t;
typedef struct // currently destroyed within ModelContainer_Clear(), allocated (for bolt ons) within ModelContainer_RegisterModel()
{
/*
//ModelContainer_t *pBoltedContainer;
vector <ModelContainer_t *> vpBoltedContainers;
string sAttachName;
//
// vector < MyGLMatrix_t > MatricesPerFrame; // why the fuck doesn't this work? Dammit.
MyGLMatrix_t *pMatrices;
*/
string sAttachName;
vector <MyGLMatrix_t> vMatricesPerFrame; // why the fuck doesn't this work? Dammit.
vector <ModelContainer_t> vBoltedContainers;
} BoltPoint_t;
typedef map <string, string> MappedString_t;
typedef map <string, GLuint> MaterialBinds_t;
struct ModelContainer
{
ModelHandle_t hModel;
modtype_t eModType;
char sLocalPathName[MAX_QPATH];
//
// workspace stuff that G2 models need...
//
surfaceInfo_t slist[MAX_G2_SURFACES]; // this is the surface list for a model - most of this won't be changing so it shouldn't impact networking that badly
boneInfo_t blist[MAX_BONE_OVERRIDES]; // this is the list of bones we want to override features on. This *shouldn't* change that much - networking will take a bit of a hit on this
int iBoneNum_SecondaryStart; //-1 by default, meaning "ignore", else bone num to stop animating at from upper (eg "lower_lumbar"), and start animating from lower downwards
int iSurfaceNum_RootOverride; //-1 by default, meaning "ignore", else surf num to start rendering from
//
// a couple of tacky things that're used for bone-view highlighting and bolting
//
mdxaBone_t XFormedG2Bones [MAX_POSSIBLE_BONES];
bool XFormedG2BonesValid [MAX_POSSIBLE_BONES];
mdxaBone_t XFormedG2TagSurfs [MAX_G2_SURFACES]; // same thing for surface-bolting
bool XFormedG2TagSurfsValid [MAX_G2_SURFACES];
// linkage/bolting fields...
//
// bone bolts...
//
ModelContainer_t *pBoneBolt_ParentContainer; // NULL if root model, else parent we're bolted to
int iBoneBolt_ParentBoltIndex; // index of which bolt point on parent we're bolted to
int iBoneBolt_MaxBoltPoints; // currently will always be MAX_BOLTS, but may change on a per-model basis
vector <BoltPoint_t> tBoneBolt_BoltPoints;
//
// surface bolts...
//
ModelContainer_t *pSurfaceBolt_ParentContainer; // NULL if root model, else parent we're bolted to
int iSurfaceBolt_ParentBoltIndex; // index of which bolt point on parent we're bolted to
int iSurfaceBolt_MaxBoltPoints; // currently will always be MAX_BOLTS, but may change on a per-model basis
vector <BoltPoint_t> tSurfaceBolt_BoltPoints;
// stuff for viewer info / control etc for this model...
//
int iCurrentFrame_Primary; // for anim playback
int iCurrentFrame_Secondary;
int iOldFrame_Primary;
int iOldFrame_Secondary;
int iSequenceLockNumber_Primary; // -1 for none, else sequence number that's locked
int iSequenceLockNumber_Secondary; // -1 for none, else sequence number that's locked
int iNumFrames; // for easy frame capping
int iNumLODs;
SequenceList_t SequenceList;
bool bSeqMultiLock_Primary_Active;
bool bSeqMultiLock_Secondary_Active;
int iSeqMultiLock_Primary_SeqHint; // slightly odd usage, and self-correcting if illegal
int iSeqMultiLock_Secondary_SeqHint;//
vector <int> SeqMultiLock_Primary;
vector <int> SeqMultiLock_Secondary;
SkinSets_t SkinSets; // SOF2-format skins
SkinSetsSurfacePrefs_t SkinSetsSurfacePrefs; // SOF2-format skin surface hints
OldSkinSets_t OldSkinSets; // CHC-format skins
SurfaceEdgeInfoPerLOD_t SurfaceEdgeInfoPerLOD; // used only when crack-viewing
string strCurrentSkinFile; // used for both SOF and CHC skins
string strCurrentSkinEthnic; // only for SOF2 skins
MaterialBinds_t MaterialBinds; // constructed whenever skin details are changed, used for fast-lookup
MappedString_t MaterialShaders; // " "
//
// more freaky stuff to do with MODVIEW, rather than the format as a whole...
//
HTREEITEM hTreeItem_ModelName; // filled in by format-specific parser, so we can add a "BoltOns" treeitem later
HTREEITEM hTreeItem_BoltOns; // attached underneath hTreeItem_ModelName, and passed as parent tree item to bolted containers
//
// these 2 are just for viewing bone highlights and shouldn't be used for anything else...
//
int iNumBones; // zero for all model types other than ghoul2?, only used for loop-speed opt
int iBoneHighlightNumber; // only affects viewing of ghoul2 model types, see equates above
MappedString_t Aliases; // keyed [realname] = aliasname, opposite to what you'd expect
//
// semi-ditto here...
//
int iNumSurfaces;
int iSurfaceHighlightNumber;
// int iRenderedBoneWeightsThisSurface;
//
// stats only...
//
int iRenderedTris;
int iRenderedVerts;
int iRenderedSurfs;
int iXformedG2Bones;
int iRenderedBoneWeights;
int iOmittedBoneWeights;
// some function ptrs to be filled in by specific model types...
//
LPCSTR (*pModelInfoFunction) ( ModelHandle_t hModel );
LPCSTR (*pModelGetBoneNameFunction) ( ModelHandle_t hModel, int iBoneIndex );
LPCSTR (*pModelGetBoneBoltNameFunction) ( ModelHandle_t hModel, int iBoltIndex ); // same as above in GLM model
LPCSTR (*pModelGetSurfaceNameFunction) ( ModelHandle_t hModel, int iSurfaceIndex );
LPCSTR (*pModelGetSurfaceBoltNameFunction) ( ModelHandle_t hModel, int iSurfaceIndex );// same as above in GLM model
};
const double ANIM_SLOWER = 1.3;
const double ANIM_FASTER = 0.9;
typedef struct
{
CString strLoadedModelPath; // full disk path of primary model
// int iNumContainers; //deleteme
int iTotalContainers;
ModelContainer_t Container;
//
// user settings...
//
bool bBilinear;
bool bOriginLines;
bool bBBox;
bool bFloor;
float fFloorZ;
bool bRuler;
bool bAnimate;
bool bForceWrapWhenAnimating;
bool bInterpolate;
bool bUseAlpha;
bool bWireFrame;
bool bBoneHighlight;
bool bBoneWeightThreshholdingActive;
float fBoneWeightThreshholdPercent;
bool bSurfaceHighlight;
bool bSurfaceHighlightShowsBoneWeighting;
bool bTriIndexes;
bool bVertIndexes;
bool bVertWeighting;
bool bAtleast1VertWeightDisplayed; // tacky, but useful for reducing screen clutter
bool bVertexNormals;
bool bShowTagSurfaces;
bool bShowOriginsAsRGB;
bool bForceWhite;
bool bCleanScreenShots;
bool bFullPathsInSequenceTreeitems;
bool bCrackHighlight;
bool bShowUnshadowableSurfaces;
int iLOD;
byte _R, _G, _B; // CLS colour
double dFOV;
double dAnimSpeed;
double dTimeStamp1;
float fFramefrac;
float xPos, yPos, zPos;
float rotAngleX, rotAngleY, rotAngleZ;
float xPos_SCROLL, yPos_SCROLL, zPos_SCROLL;
float rotAngleX_SCROLL, rotAngleY_SCROLL, rotAngleZ_SCROLL;
// other crap...
//
HWND hWnd;
bool bFinished; // true only at final app shutdown, may be useful for some checks
bool bAllowGLAOverrides;
bool bShowPolysAsDoubleSided;
bool bAlwaysOnTop;
bool bSortSequencesByAlpha;
// some really tacky stuff...
//
int iSurfaceNumToHighlight; // only valid when this->bSurfaceHighlight == true
ModelHandle_t hModelToHighLight;
ModelHandle_t hModelLastLoaded; // useful for some simple batch stuff, may only be temp?
} ModViewAppVars_t;
extern ModViewAppVars_t AppVars;
void AppVars_Init(void);
void AppVars_ResetViewParams(void);
void App_OnceOnly(void);
ModelHandle_t Model_GetPrimaryHandle(void);
bool Model_Loaded(ModelHandle_t hModel = NULL);
void Model_Delete(void);
void Model_ValidateSkin( ModelHandle_t hModel, int iSkinNumber);
void Model_ApplyOldSkin( ModelHandle_t hModel, LPCSTR psSkin );
void Model_ApplyEthnicSkin(ModelHandle_t hModel, LPCSTR psSkin, LPCSTR psEthnic, bool bApplySurfacePrefs, bool bDefaultSurfaces );
bool Model_SkinHasSurfacePrefs( ModelHandle_t hModel, LPCSTR psSkin );
void Model_ApplySkinShaderVariant( ModelHandle_t hModel, LPCSTR psSkin, LPCSTR psEthnic, LPCSTR psMaterial, int iVariant );
LPCSTR Model_GetSupportedTypesFilter(bool bScriptsEtcAlsoAllowed = false);
bool Model_DeleteBoltOn(ModelHandle_t hModel, int iBoltPointToDelete, bool bBoltIsBone, int iBoltOnAtBoltPoint);
bool Model_DeleteBoltOn(ModelContainer_t *pContainer, int iBoltPointToDelete, bool bBoltIsBone, int iBoltOnAtBoltPoint);
bool Model_DeleteBoltOn(ModelContainer_t *pContainer);
bool Model_DeleteBoltOn(ModelHandle_t hModelBoltOn);
bool Model_HasParent(ModelHandle_t hModel);
int Model_CountItemsBoltedHere(ModelHandle_t hModel, int iBoltindex, bool bBoltIsBone);
bool Model_LoadPrimary(LPCSTR psFullPathedFilename);
bool Model_Save(LPCSTR psFullPathedFilename);
bool Model_LoadBoltOn(LPCSTR psFullPathedFilename, ModelHandle_t hModel, int iBoltIndex, bool bBoltIsBone, bool bBoltReplacesAllExisting);
bool Model_LoadBoltOn(LPCSTR psFullPathedFilename, ModelHandle_t hModel, LPCSTR psBoltName, bool bBoltIsBone, bool bBoltReplacesAllExisting);
int Model_GetNumBoneAliases(ModelHandle_t hModel);
bool Model_GetBoneAliasPair(ModelHandle_t hModel, int iAliasIndex, string &strRealName,string &strAliasName);
bool ModelContainer_GetBoneAliasPair(ModelContainer_t *pContainer, int iAliasIndex, string &strRealName,string &strAliasName);
int Model_GetNumSequences(ModelHandle_t hModel); // remote helper func only
LPCSTR Model_GetSequenceString(ModelHandle_t hModel, int iSequenceNum);// remote helper func only
bool Model_SetSecondaryAnimStart(ModelHandle_t hModel, int iBoneNum);
bool Model_SetSecondaryAnimStart(ModelHandle_t hModel, LPCSTR psBoneName);
int Model_GetSecondaryAnimStart(ModelHandle_t hModel);
LPCSTR Model_Info( ModelHandle_t hModel );
void Model_StartAnim(bool bForceWrap = false );
void Model_StopAnim();
float Model_GetLowestPointOnPrimaryModel(void);
LPCSTR Model_GetSurfaceName( ModelHandle_t hModel, int iSurfaceIndex );
LPCSTR Model_GetSurfaceName( ModelContainer_t *pContainer, int iSurfaceIndex );
bool Model_SurfaceIsTag( ModelContainer_t *pContainer, int iSurfaceIndex);
bool Model_SurfaceIsTag( ModelHandle_t hModel, int iSurfaceIndex);
LPCSTR Model_GetBoneName( ModelHandle_t hModel, int iBoneIndex );
int Model_GetBoltIndex( ModelHandle_t hModel, LPCSTR psBoltName, bool bBoltIsBone);
int Model_GetBoltIndex( ModelContainer_t *pContainer, LPCSTR psBoltName, bool bBoltIsBone );
LPCSTR Model_GetBoltName( ModelHandle_t hModel, int iBoltIndex, bool bBoltIsBone );
LPCSTR Model_GetBoltName( ModelContainer_t *pContainer, int iBoltIndex, bool bBoltIsBone );
LPCSTR Model_GetFullPrimaryFilename( void );
LPCSTR Model_GetFilename( ModelHandle_t hModel );
LPCSTR Model_GLMBoneInfo( ModelHandle_t hModel, int iBoneIndex );
LPCSTR Model_GLMSurfaceInfo( ModelHandle_t hModel, int iSurfaceIndex, bool bShortVersionForTag );
LPCSTR Model_GLMSurfaceVertInfo( ModelHandle_t hModel, int iSurfaceIndex );
bool Model_SurfaceContainsBoneReference(ModelHandle_t hModel, int iLODNumber, int iSurfaceNumber, int iBoneNumber);
bool Model_GLMSurface_Off(ModelHandle_t hModel, int iSurfaceIndex );
bool Model_GLMSurface_On(ModelHandle_t hModel, int iSurfaceIndex );
bool Model_GLMSurface_NoDescendants(ModelHandle_t hModel, int iSurfaceIndex );
bool Model_GLMSurface_SetStatus( ModelHandle_t hModel, int iSurfaceIndex, SurfaceOnOff_t eStatus );
bool Model_GLMSurface_SetStatus( ModelHandle_t hModel, LPCSTR psSurfaceName, SurfaceOnOff_t eStatus );
void Model_GLMSurfaces_DefaultAll(ModelHandle_t hModel);
SurfaceOnOff_t Model_GLMSurface_GetStatus( ModelHandle_t hModel, int iSurfaceIndex );
int Model_GetNumSurfacesDifferentFromDefault(ModelContainer_t *pContainer, SurfaceOnOff_t eStatus);
LPCSTR Model_GetSurfaceDifferentFromDefault(ModelContainer_t *pContainer, SurfaceOnOff_t eStatus, int iSurfaceIndex);
bool Model_SetBoneHighlight(ModelHandle_t hModel, int iBoneIndex);
bool Model_SetBoneHighlight(ModelHandle_t hModel, LPCSTR psBoneName);
bool Model_SetSurfaceHighlight(ModelHandle_t hModel, int iSurfaceindex);
bool Model_SetSurfaceHighlight(ModelHandle_t hModel, LPCSTR psSurfaceName);
int Model_EnsureGenerated_VertEdgeInfo(ModelContainer_t *pContainer, int iLOD);
int Model_EnsureGenerated_VertEdgeInfo(ModelHandle_t hModel, int iLOD);
void ModelList_ForceRedraw(void);
void ModelList_Render(int iWindowWidth, int iWindowHeight);
void ModelList_Rewind(void);
void ModelList_GoToEndFrame();
bool ModelList_StepFrame(int iStepVal, bool bAutoAnimOff = true);
bool ModelList_Animation(void);
void ModelTree_DeleteAllItems(void);
bool ModelTree_DeleteItem(HTREEITEM hTreeItem);
HTREEITEM ModelTree_GetRootItem(void);
bool ModelTree_SetItemText(HTREEITEM hTreeItem, LPCSTR psText);
LPCSTR ModelTree_GetItemText(HTREEITEM hTreeItem, bool bPure = false);
DWORD ModelTree_GetItemData(HTREEITEM hTreeItem);
HTREEITEM ModelTree_GetChildItem(HTREEITEM hTreeItem);
bool ModelTree_ItemHasChildren(HTREEITEM hTreeItem);
int ModelTree_GetChildCount(HTREEITEM hTreeItem);
void ModelTree_InsertSequences(ModelContainer_t *pContainer, HTREEITEM hTreeItem_Sequences);
void ModelTree_InsertSequences(ModelHandle_t hModel, HTREEITEM hTreeItem_Sequences);
HTREEITEM ModelTree_GetNextSiblingItem(HTREEITEM hTreeItem);
HTREEITEM ModelTree_InsertItem(LPCTSTR psName, HTREEITEM hParent, UINT32 uiUserData = NULL, HTREEITEM hInsertAfter = TVI_LAST);
HTREEITEM ModelTree_GetRootSurface(ModelHandle_t hModel);
HTREEITEM ModelTree_GetRootBone(ModelHandle_t hModel);
void R_ModelContainer_Apply(ModelContainer_t* pContainer, void (*pFunction) ( ModelContainer_t* pContainer, void *pvData), void *pvData = NULL);
ModelContainer_t* ModelContainer_FindFromModelHandle(ModelHandle_t hModel);
int ModelContainer_BoneIndexFromName(ModelContainer_t *pContainer, LPCSTR psBoneName);
void Media_Delete(void);
void AppVars_WriteIdeal(void);
void AppVars_ReadIdeal(void);
bool Model_Sequence_Lock ( ModelHandle_t hModel, int iSequenceNumber, bool bPrimary);
bool Model_Sequence_Lock ( ModelHandle_t hModel, LPCSTR psSequenceName, bool bPrimary, bool bOktoShowErrorBox = true);
bool Model_Sequence_UnLock ( ModelHandle_t hModel, bool bPrimary);
bool Model_Sequence_IsLocked ( ModelHandle_t hModel, int iSequenceNumber, bool bPrimary);
LPCSTR Model_Sequence_GetName ( ModelHandle_t hModel, int iSequenceNumber, bool bUsedForDisplay = false);
LPCSTR Model_Sequence_GetName ( ModelContainer_t *pContainer, int iSequenceNumber, bool bUsedForDisplay = false);
LPCSTR Model_Sequence_GetLockedName( ModelHandle_t hModel, bool bPrimary);
int Model_Sequence_IndexForName(ModelContainer_t *pContainer, LPCSTR psSeqName);
bool Model_SecondaryAnimLockingActive(ModelHandle_t hModel);
bool Model_SecondaryAnimLockingActive(const ModelContainer_t *pContainer);
LPCSTR Model_Sequence_GetTreeName(ModelHandle_t hModel, int iSequenceNumber);
int Model_GetG2SurfaceRootOverride (ModelContainer_t *pContainer);
int Model_GetG2SurfaceRootOverride (ModelHandle_t hModel);
bool Model_SetG2SurfaceRootOverride (ModelContainer_t *pContainer, int iSurfaceNum);
bool Model_SetG2SurfaceRootOverride (ModelContainer_t *pContainer, LPCSTR psSurfaceName);
bool Model_SetG2SurfaceRootOverride (ModelHandle_t hModel, int iSurfaceNum);
bool Model_MultiSeq_Add ( ModelHandle_t hModel, int iSequenceNumber, bool bPrimary, bool bActivate = true);
bool Model_MultiSeq_IsActive ( ModelHandle_t hModel, bool bPrimary);
bool Model_MultiSeq_IsActive ( ModelContainer_t *pContainer, bool bPrimary);
void Model_MultiSeq_SetActive( ModelHandle_t hModel, bool bPrimary, bool bActive);
int Model_MultiSeq_GetNumEntries(ModelHandle_t hModel, bool bPrimary);
int Model_MultiSeq_GetNumEntries(ModelContainer_t *pContainer, bool bPrimary);
int Model_MultiSeq_GetEntry ( ModelContainer_t *pContainer, int iEntry, bool bPrimary);
void Model_MultiSeq_Clear ( ModelHandle_t hModel, bool bPrimary);
void Model_MultiSeq_DeleteLast(ModelHandle_t hModel, bool bPrimary);
void Model_MultiSeq_Delete ( ModelHandle_t hModel, int iSeqIndex, bool bPrimary);
int Model_MultiSeq_SeqIndexFromFrame(ModelContainer_t *pContainer, int iFrame, bool bPrimary, bool bIsOldFrame );
int Model_MultiSeq_EntryIndexFromFrame(ModelContainer_t *pContainer, int iFrame, bool bPrimary );
bool Model_MultiSeq_AlreadyContains(ModelHandle_t hModel, int iSequenceNumber, bool bPrimary);
bool Model_MultiSeq_AlreadyContains(ModelContainer_t *pContainer, int iSequenceNumber, bool bPrimary);
#endif // #ifndef MODEL_H
////////////// eof /////////////

Some files were not shown because too many files have changed in this diff Show More