Hello World!

This commit is contained in:
Tim Oliver 2011-12-05 20:41:28 +08:00
commit 3efaa62d80
109 changed files with 38342 additions and 0 deletions

42
Base.h Executable file
View File

@ -0,0 +1,42 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _BASE_H_
#define _BASE_H_
#define INT32 int
#define INT16 short
#define INT8 char
#define UINT32 unsigned int
#define UINT16 unsigned short
#define UINT8 unsigned char
#define SINT32 signed int
#define SINT16 signed short
#define SINT8 signed char
typedef float Vec3[3];
typedef float Vec2[2];
typedef Vec3 Mat3x3[3];
typedef INT32 TriVec[3]; //vertex 1,2,3 of TriVec
typedef Vec2 TexVec; //Texture U/V coordinates of vertex
#endif

91
BaseMesh.h Executable file
View File

@ -0,0 +1,91 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _BASEMESH_H_
#define _BASEMESH_H_
#include "mdr.h" // for MAX_QPATH
/**START OLD STRUCTURES**/
//These structures are exactly the same in the md3 file structure.
//It is very likely that these structures will be replaced with a
//very different internal structure.
/*
typedef struct
{
//start guess
float Mins[3];
float Maxs[3];
float Position[3];
float Scale;
//end guess
char Creator[16]; //i think this is the "creator" name..
//but i'm only guessing.
} BoneFrame_t;
*/
typedef struct
{
vec3_t bounds[2];
vec3_t localOrigin;
float radius;
char name[16]; // creator
} md3BoundFrame_t;
// as with everything else in this source, this is a mess. I've replaced the original guesswork name/unknown stuff,
// but couldn't be arsed converting either the original MD3 code, or the new MDR code to use the other's labels, so...
//
typedef struct
{
/* char Name[12]; //name of 'tag' as it's usually called in the md3 files
//try to see it as a sub-mesh/seperate mesh-part
char unknown[52]; //normally filled with zeros, but there is an exception
//where it's filled with other numbers...
//it would be logical if it was part of name, because
//then name would have 64 chars.
*/
union
{
char Name[MAX_QPATH];
char name[MAX_QPATH]; // tag name
};
union
{
//unverified:
Vec3 Position; //relative position of tag
vec3_t origin;
};
union
{
Mat3x3 Matrix; //3x3 rotation matrix
vec3_t axis[3];
};
} Tag;
typedef Tag* TagFrame;
/**END OLD STRUCTURES**/
typedef Tag md3Tag_t;
#endif

240
DiskIO.cpp Executable file
View File

@ -0,0 +1,240 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.h"
#include "diskio.h"
void putLittle16 ( INT16 num , FILE *f )
{
union
{
struct
{
UINT8 b1, b2;
};
UINT16 i1;
} u;
u.i1 = num;
fputc( u.b1, f );
fputc( u.b2, f );
}
INT16 getLittle16 (FILE *f)
{
union
{
struct
{
UINT8 b1, b2;
};
UINT16 i1;
} u;
u.b1 = fgetc(f);
u.b2 = fgetc(f);
return u.i1;
}
void putLittle32 ( INT32 num , FILE *f )
{
union
{
struct
{
UINT8 b1, b2, b3, b4;
};
UINT32 i1;
} u;
u.i1 = num;
fputc( u.b1, f );
fputc( u.b2, f );
fputc( u.b3, f );
fputc( u.b4, f );
}
INT32 getLittle32 (FILE *f)
{
union
{
struct
{
UINT8 b1, b2, b3, b4;
};
UINT32 i1;
} u;
u.b1 = fgetc(f);
u.b2 = fgetc(f);
u.b3 = fgetc(f);
u.b4 = fgetc(f);
return u.i1;
}
void putLittleFloat( float num , FILE *f )//32bit floating point number
{
union
{
struct
{
UINT8 b1, b2, b3, b4;
};
float f1;
} u;
u.f1 = num;
fputc( u.b1, f );
fputc( u.b2, f );
fputc( u.b3, f );
fputc( u.b4, f );
}
float getLittleFloat (FILE *f) //32bit floating point number
{
union
{
struct
{
UINT8 b1, b2, b3, b4;
};
float f1;
} u;
u.b1 = fgetc(f);
u.b2 = fgetc(f);
u.b3 = fgetc(f);
u.b4 = fgetc(f);
return u.f1;
}
void putBig16 ( INT16 num , FILE *f )
{
union
{
struct
{
UINT8 b1, b2, b3, b4;
};
INT16 i1;
} u;
u.i1 = num;
fputc( u.b2, f );
fputc( u.b1, f );
}
INT16 getBig16 (FILE *f)
{
union
{
struct
{
UINT8 b1, b2;
};
UINT16 i1;
} u;
u.b2 = fgetc(f);
u.b1 = fgetc(f);
return u.i1;
}
void putBig32 ( INT32 num , FILE *f )
{
union
{
struct
{
UINT8 b1, b2, b3, b4;
};
INT32 i1;
} u;
u.i1 = num;
fputc( u.b4, f );
fputc( u.b3, f );
fputc( u.b2, f );
fputc( u.b1, f );
}
INT32 getBig32 (FILE *f)
{
union
{
struct
{
UINT8 b1, b2, b3, b4;
};
UINT32 i1;
} u;
u.b4 = fgetc(f);
u.b3 = fgetc(f);
u.b2 = fgetc(f);
u.b1 = fgetc(f);
return u.i1;
}
void putBigFloat ( float num , FILE *f ) //32bit floating point number
{
union
{
struct
{
UINT8 b1, b2, b3, b4;
};
float f1;
} u;
u.f1 = num;
fputc( u.b4, f );
fputc( u.b3, f );
fputc( u.b2, f );
fputc( u.b1, f );
}
float getBigFloat (FILE *f) //32bit floating point number
{
union
{
struct
{
UINT8 b1, b2, b3, b4;
};
float f1;
} u;
u.b4 = fgetc(f);
u.b3 = fgetc(f);
u.b2 = fgetc(f);
u.b1 = fgetc(f);
return u.f1;
}

43
DiskIO.h Executable file
View File

@ -0,0 +1,43 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DISKIO_H_
#define _DISKIO_H_
void putLittle16 ( INT16 num , FILE *f );
INT16 getLittle16 ( FILE *f );
void putLittle32 ( INT32 num , FILE *f );
INT32 getLittle32 ( FILE *f );
void putLittleFloat ( float num , FILE *f ); //32bit floating point number
float getLittleFloat ( FILE *f ); //32bit floating point number
void putBig16 ( INT16 num , FILE *f );
INT16 getBig16 ( FILE *f );
void putBig32 ( INT32 num , FILE *f );
INT32 getBig32 ( FILE *f );
void putBigFloat ( float num , FILE *f ); //32bit floating point number
float getBigFloat ( FILE *f ); //32bit floating point number
#define get16 getLittle16
#define get32 getLittle32
#define getFloat getLittleFloat
#define put16 putLittle16
#define put32 putLittle32
#define putFloat putLittleFloat
#endif

53
Error.cpp Executable file
View File

@ -0,0 +1,53 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.h"
/*
error handler
*/
void Error (char *error, ...)
{
va_list argptr;
char text[1024];
va_start (argptr,error);
vsprintf (text, error,argptr);
va_end (argptr);
MessageBox( NULL, text, "Error", MB_OK );
exit (1);
}
/*
debugging output
*/
void Debug (char *error, ...)
{
va_list argptr;
char text[4096];
va_start (argptr,error);
vsprintf (text, error,argptr);
va_end (argptr);
MessageBox( NULL, text, "Debug", MB_OK );
}

26
Error.h Executable file
View File

@ -0,0 +1,26 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _ERROR_H_
#define _ERROR_H_
void Error (char *error, ...);
void Debug (char *error, ...);
#endif

BIN
ID_APP.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

20
MD3View.sln Executable file
View File

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MD3View", "MD3View.vcproj", "{144114CF-2224-4770-A0C8-E87754FC2ED9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{144114CF-2224-4770-A0C8-E87754FC2ED9}.Debug|Win32.ActiveCfg = Debug|Win32
{144114CF-2224-4770-A0C8-E87754FC2ED9}.Debug|Win32.Build.0 = Debug|Win32
{144114CF-2224-4770-A0C8-E87754FC2ED9}.Release|Win32.ActiveCfg = Release|Win32
{144114CF-2224-4770-A0C8-E87754FC2ED9}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

1601
MD3View.vcproj Executable file

File diff suppressed because it is too large Load Diff

0
README Normal file
View File

823
Script.cpp Executable file
View File

@ -0,0 +1,823 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/****************/
/* !!WARNING!! */
/* UNDER HEAVY */
/* CONSTRUCTION */
/****************/
//SVR: lol
#include "system.h"
/*
special map names:
$lightmap
*white
$whiteimage
$fromblack
types of waves:
"wave","sin" ,float,float,float,float
"wave","inversesawtooth",float,float,float,float
"wave","sawtooth" ,float,float,float,float
"wave","square" ,float,float,float,float
"wave","noise" ,float,float,float,float
"wave","triangle" ,float,float,float,float
}
*/
void clean( char*& line )
{
unsigned int i;
if ( line[ 0 ] != 0 )
{
i = 0;while ( ( i < strlen( line ) ) && ( line[ i ] != '/' ) ) i++;
if ( ( line[ i ] == '/' ) && ( line[ i + 1 ] == '/' )) line[ i ] = 0;
if ( line[ 0 ] != 0 )
{
for ( i = 0 ; i < strlen( line ) ; i++ )
if ( line[ i ] == 9 ) line[ i ] = 32; else
if ( line[ i ] == 10 ) line[ i ] = 32;
i = strlen( line ) - 1 ;
while ( line[ i ] == 32 ) i--;
line[ i + 1 ] = 0;
if ( line[ 0 ] != 0 )
{
while ( line[ 0 ] == 32 ) line++;
if ( line[ 0 ] == 0 )
line = NULL;
} else
line = NULL;
} else
line = NULL;
} else
line = NULL;
}
char* getstring( char*& line )
{
if ( line != NULL )
{
unsigned int i;
char* retptr = line;
i = 0;while ( ( line[ i ] != 32 ) && ( line[ i ] != 0 ) ) i++;
if ( line[ i ] != 0 )
{
line[ i ] = 0;
line = &line[ i + 1 ];
if ( line[ 0 ] == 0 )
line = NULL;
else while ( line[ 0 ] == 32 ) line++;
} else
line = NULL;
return retptr;
} else
return NULL;
}
void Error (char *error, ...);
void Debug (char *error, ...);
/*START UNFINISHED BIT*/
class RenderPass
{
public:
//tcMod - texcoords
float rp_rotate,rp_scalex,rp_scaley,rp_scrollx,rp_scrolly,
//i don't know what the values a-d are for.
rp_turba,rp_turbb,rp_turbc,rp_turbd,
//i don't know what the values a-d are for.
rp_stretchsina,rp_stretchsinb,rp_stretchsinc,rp_stretchsind;
//various gl functions
GLenum blend_sfactor, blend_dfactor,alpha_func,depth_func;
GLclampf alpha_ref;
//misc commands
bool rp_detail,rp_depthwrite,rp_clamptexcoords;
void AddParam( char* Type, char* Var );
};
class Surface
{
public:
//surfaceparam
bool sp_trans ,sp_metalsteps,sp_nolightmap,sp_nodraw ,sp_noimpact,
sp_nonsolid ,sp_nomarks ,sp_nodrop ,sp_nodamage ,sp_playerclip,
sp_structural ,sp_slick ,sp_origin ,sp_areaportal,sp_fog,
sp_lightfilter,sp_water ,sp_slime ,sp_sky ,sp_lava;
//cull
enum {cull_none, cull_disable, cull_twosided, cull_backsided, cull_back} cull;
//misc commands
bool sf_portal,sf_fogonly,sf_nomipmaps,sf_polygonOffset,
sf_lightning,sf_backsided,sf_qer_nocarve;
float sf_light,sf_tesssize,sf_sort,sf_qer_trans,sf_q3map_backsplash,
sf_q3map_surfacelight;
char *sf_sky,*sf_q3map_lightimage,*sf_qer_editorimage;
void AddParam( char* Type, char* Var );
void AddPass( RenderPass*& Pass );
};
Surface* CreateSurface( char* Name )
{
return new Surface;
}
void RenderPass::AddParam( char* Type, char* Var )
{
char* Token;
if ( stricmp( Type , "tcMod" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after surfaceparam, but none found");
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
if ( stricmp( Token , "rotate" ) == 0 )
{
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
rp_rotate = (float)atof(Token);
} else
if ( stricmp( Token , "scale" ) == 0 )
{
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
//TODO: add check if it's really a number
rp_scalex = (float)atof(Token);
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
rp_scaley = (float)atof(Token);
} else
if ( stricmp( Token , "scroll" ) == 0 )
{
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
//TODO: add check if it's really a number
rp_scrollx = (float)atof(Token);
Token = getstring( Var );
//there is this "tcmod scroll" with four!! paramters..
//i have no idear what the other 2 are for.
// if ( Var != NULL )
// Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
rp_scrolly = (float)atof(Token);
} else
if ( stricmp( Token , "turb" ) == 0 )
{
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
//TODO: add check if it's really a number
rp_turba = (float)atof(Token);
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
//TODO: add check if it's really a number
rp_turbb = (float)atof(Token);
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
//TODO: add check if it's really a number
rp_turbc = (float)atof(Token);
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
rp_turbd = (float)atof(Token);
} else
if ( stricmp( Token , "stretch" ) == 0 )
{
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
if ( stricmp( Type , "sin" ) != 0 )
Error( "unknown tcmod stretch function: %s" , Token );
//TODO: add check if it's really a number
rp_stretchsina = (float)atof(Token);
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
//TODO: add check if it's really a number
rp_stretchsinb = (float)atof(Token);
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
//TODO: add check if it's really a number
rp_stretchsinc = (float)atof(Token);
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
rp_stretchsind = (float)atof(Token);
} else
Error("unknown tcmod command found %s:",Token);
} else
if ( stricmp( Type , "blendfunc" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after blendfunc, but none found");
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
if ( stricmp( Token , "gl_zero" ) == 0 ) blend_sfactor=GL_ZERO;else
if ( stricmp( Token , "gl_one" ) == 0 ) blend_sfactor=GL_ONE;else
if ( stricmp( Token , "gl_dst_color" ) == 0 ) blend_sfactor=GL_DST_COLOR;else
if ( stricmp( Token , "gl_one_minus_dst_color" ) == 0 ) blend_sfactor=GL_ONE_MINUS_DST_COLOR;else
if ( stricmp( Token , "gl_src_alpha" ) == 0 ) blend_sfactor=GL_SRC_ALPHA;else
if ( stricmp( Token , "gl_one_minus_src_alpha" ) == 0 ) blend_sfactor=GL_ONE_MINUS_SRC_ALPHA;else
if ( stricmp( Token , "gl_dst_alpha" ) == 0 ) blend_sfactor=GL_DST_ALPHA;else
if ( stricmp( Token , "gl_one_minus_dst_alpha" ) == 0 ) blend_sfactor=GL_ONE_MINUS_DST_ALPHA;else
if ( stricmp( Token , "gl_src_alpha_saturate" ) == 0 ) blend_sfactor=GL_SRC_ALPHA_SATURATE;
else Error( "unknown blendfunc parameter found: %s ", Token );
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
if ( stricmp( Token , "gl_zero" ) == 0 ) blend_dfactor=GL_ZERO;else
if ( stricmp( Token , "gl_one" ) == 0 ) blend_dfactor=GL_ONE;else
if ( stricmp( Token , "gl_src_color" ) == 0 ) blend_dfactor=GL_SRC_COLOR;else
if ( stricmp( Token , "gl_one_minus_dst_color" ) == 0 ) blend_dfactor=GL_ONE_MINUS_SRC_COLOR;else
if ( stricmp( Token , "gl_src_alpha" ) == 0 ) blend_dfactor=GL_SRC_ALPHA;else
if ( stricmp( Token , "gl_one_minus_src_alpha" ) == 0 ) blend_dfactor=GL_ONE_MINUS_SRC_ALPHA;else
if ( stricmp( Token , "gl_dst_alpha" ) == 0 ) blend_dfactor=GL_DST_ALPHA;else
if ( stricmp( Token , "gl_one_minus_dst_alpha" ) == 0 ) blend_dfactor=GL_ONE_MINUS_DST_ALPHA;
else Error( "unknown blendfunc parameter found: %s ", Token );
} else
if ( stricmp( Type , "alphafunc" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after alphafunc, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
if ( stricmp( Token , "gt0" ) == 0 ) {
alpha_func = GL_GREATER;alpha_ref = 0;
} else
if ( stricmp( Token , "lt128") == 0 ) {
alpha_func = GL_LESS;alpha_ref = 128;
} else
if ( stricmp( Token , "ge128") == 0 ) {
alpha_func = GL_GEQUAL;alpha_ref = 128;
}
else Error( "unknown alphafunc parameter found: %s ", Token );
} else
if ( stricmp( Type , "depthfunc" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after depthfunc, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
if ( stricmp( Token , "equal" ) == 0 ) {
depth_func = GL_EQUAL;
}
else Error( "unknown depthfunc parameter found: %s ", Token );
} else
if ( stricmp( Type , "detail" ) == 0 )
{
if ( Var != NULL )
Error( "detail followed by unexpected token: %s" , Var );
rp_detail = true;
} else
if ( stricmp( Type , "depthwrite" ) == 0 )
{
if ( Var != NULL )
Error( "depthwrite followed by unexpected token: %s" , Var );
rp_depthwrite = true;
} else
if ( stricmp( Type , "clamptexcoords" ) == 0 )
{
if ( Var != NULL )
Error( "clamptexcoords followed by unexpected token: %s" , Var );
rp_clamptexcoords = true;
} else
if ( stricmp( Type , "tcgen" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after tcgen, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
if ( stricmp( Token , "environment" ) != 0 )
Error( "unknown tcgen command found: %s ", Token );
//TODO: add functionality
// Create enviroment map
} else
if ( stricmp( Type , "map" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after map, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add functionality
// load texture map
} else
if ( stricmp( Type , "alphamap" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after alphamap, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add functionality
// load texture alphamap
} else
if ( stricmp( Type , "animmap" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after animmap, but none found");
Token = getstring( Var );
if ( Var == NULL )
Error( "unexpected end after token: %s" , Token );
// Token == unknown number
while ( ( Token = getstring( Var ) ) != NULL )
{
//TODO: add functionality
// load texture animmap
}
} else
if ( stricmp( Type , "rgbgen" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after rgbgen, but none found");
/*
{"rgbGen","wave","sin",float,float,float,float}
{"rgbGen","wave","inversesawtooth",float,float,float,float}
{"rgbGen","wave","sawtooth",float,float,float,float}
{"rgbGen","wave","square",float,float,float,float}
{"rgbGen","wave","noise",float,float,float,float}
{"rgbGen","wave","triangle",float,float,float,float}
{"rgbGen","identity"}
{"rgbGen","entity"}
{"rgbGen","exactvertex"}
{"rgbGen","vertex"}
{"rgbGen","identitylighting"}
{"rgbGen","lightingDiffuse"}
{"rgbGen","lightingSpecular"}
{"rgbGen","oneminusentity"}
*/
} else
if ( stricmp( Type , "alphagen" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after alphagen, but none found");
/*
{"colorGen","wave","sin",float,float,float,float}
{"colorGen","wave","inversesawtooth",float,float,float,float}
{"colorGen","wave","sawtooth",float,float,float,float}
{"colorGen","wave","square",float,float,float,float}
{"colorGen","wave","noise",float,float,float,float}
{"colorGen","wave","triangle",float,float,float,float}
{"colorGen","identity"}
{"colorGen","entity"}
{"colorGen","exactvertex"}
{"colorGen","vertex"}
{"colorGen","identitylighting"}
{"colorGen","lightingDiffuse"}
{"colorGen","lightingSpecular"}
{"colorGen","oneminusentity"}
*/
} else
if ( stricmp( Type , "colorgen" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after colorgen, but none found");
/*
{"alphaGen","wave","sin",float,float,float,float}
{"alphaGen","wave","inversesawtooth",float,float,float,float}
{"alphaGen","wave","sawtooth",float,float,float,float}
{"alphaGen","wave","square",float,float,float,float}
{"alphaGen","wave","noise",float,float,float,float}
{"alphaGen","wave","triangle",float,float,float,float}
{"alphaGen","identity"}
{"alphaGen","entity"}
{"alphaGen","exactvertex"}
{"alphaGen","vertex"}
{"alphaGen","identitylighting"}
{"alphaGen","lightingDiffuse"}
{"alphaGen","lightingSpecular"}
{"alphaGen","oneminusentity"}
*/
} else
Error("unknown command found: %s", Type );
}
void Surface::AddParam( char* Type, char* Var )
{
char* Token;
if ( stricmp( Type , "surfaceparam" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after surfaceparam, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
if ( stricmp( Token , "lightfilter" ) == 0 ) sp_lightfilter = true;else
if ( stricmp( Token , "playerclip" ) == 0 ) sp_playerclip = true;else
if ( stricmp( Token , "structural" ) == 0 ) sp_structural = true;else
if ( stricmp( Token , "areaportal" ) == 0 ) sp_areaportal = true;else
if ( stricmp( Token , "metalsteps" ) == 0 ) sp_metalsteps = true;else
if ( stricmp( Token , "nolightmap" ) == 0 ) sp_nolightmap = true;else
if ( stricmp( Token , "noimpact" ) == 0 ) sp_noimpact = true;else
if ( stricmp( Token , "nodamage" ) == 0 ) sp_nodamage = true;else
if ( stricmp( Token , "nonsolid" ) == 0 ) sp_nonsolid = true;else
if ( stricmp( Token , "nomarks" ) == 0 ) sp_nomarks = true;else
if ( stricmp( Token , "origin" ) == 0 ) sp_origin = true;else
if ( stricmp( Token , "nodrop" ) == 0 ) sp_nodrop = true;else
if ( stricmp( Token , "nodraw" ) == 0 ) sp_nodraw = true;else
if ( stricmp( Token , "water" ) == 0 ) sp_water = true;else
if ( stricmp( Token , "slime" ) == 0 ) sp_slime = true;else
if ( stricmp( Token , "slick" ) == 0 ) sp_slick = true;else
if ( stricmp( Token , "trans" ) == 0 ) sp_trans = true;else
if ( stricmp( Token , "lava" ) == 0 ) sp_lava = true;else
if ( stricmp( Token , "sky" ) == 0 ) sp_sky = true;else
if ( stricmp( Token , "fog" ) == 0 ) sp_fog = true;
else Error( "unknown surfaceparam variable: %s" , Token );
} else
if ( stricmp( Type , "cull" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after cull, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
if ( stricmp( Token , "none" ) == 0 ) cull = cull_none ;else
if ( stricmp( Token , "disable" ) == 0 ) cull = cull_disable ;else
if ( stricmp( Token , "twosided" ) == 0 ) cull = cull_twosided ;else
if ( stricmp( Token , "backsided" ) == 0 ) cull = cull_backsided;else
if ( stricmp( Token , "back" ) == 0 ) cull = cull_back ;
else Error( "unknown cull variable: %s" , Token );
} else
if ( stricmp( Type , "light" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after light, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
sf_light = (float)atof(Token);
} else
if ( stricmp( Type , "tesssize" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after tesssize, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
sf_tesssize = (float)atof(Token);
} else
if ( stricmp( Type , "sort" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after sort, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
sf_sort = (float)atof(Token);
} else
if ( stricmp( Type , "qer_trans" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after qer_trans, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
sf_qer_trans = (float)atof(Token);
} else
if ( stricmp( Type , "q3map_backsplash" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after q3map_backsplash, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
sf_q3map_backsplash = (float)atof(Token);
} else
if ( stricmp( Type , "q3map_surfacelight" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after q3map_surfacelight, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
sf_q3map_surfacelight = (float)atof(Token);
} else
if ( stricmp( Type , "sky" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after sky, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
sf_sky = new char[ strlen( Token ) ];
strcpy( sf_sky , Token );
} else
if ( stricmp( Type , "qer_editorimage" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after qer_editorimage, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
sf_qer_editorimage = new char[ strlen( Token ) ];
strcpy( sf_qer_editorimage , Token );
} else
if ( stricmp( Type , "q3map_lightimage" ) == 0 )
{
if ( Var == NULL )
Error( "token expected after q3map_lightimage, but none found");
Token = getstring( Var );
if ( Var != NULL )
Error( "%s followed by unexpected token: %s" , Token, Var );
//TODO: add check if it's really a number
sf_q3map_lightimage = new char[ strlen( Token ) ];
strcpy( sf_q3map_lightimage , Token );
} else
if ( stricmp( Type , "cloudparms" ) == 0 )
{
//currently ignores cloudparms
/*
{"cloudparms",int,"full"}
{"cloudparms",int,"half"}
{"cloudparms",int}
*/
} else
if ( stricmp( Type , "skyparms" ) == 0 )
{
//currently ignores skyparms
/*
{"skyparms",char*,"-","-"}
{"skyparms",int,"full","-"}
{"skyparms",int,"full","-"}
{"skyparms","-",int,"-"}
{"skyparms","full",int,"-"}
{"skyparms","half",int,"-"}
*/
} else
if ( stricmp( Type , "deformVertexes" ) == 0 )
{
//currently ignores deformVertexes
/*
{"deformVertexes","wave",int,"sin",float,float,float,float}
{"deformVertexes","autosprite"}
{"deformVertexes","autosprite2"}
{"deformVertexes","projectshadow"}
{"deformVertexes","bulge",float,float,float}
{"deformVertexes","bulge",float,float,float}
*/
} else
if ( stricmp( Type , "fogparms" ) == 0 )
{
//currently ignores fogparms
//{"fogparms",float,float,float,float,float}
} else
if ( stricmp( Type , "q3map_sun" ) == 0 )
{
//currently ignores q3map_sun
//{"q3map_sun",float,float,float,int,int,int}
} else
if ( stricmp( Type , "fogGen" ) == 0 )
{
//currently ignores fogGen
//{"fogGen","sin",float,float,float,float}
} else
if ( stricmp( Type , "blendMap" ) == 0 )
{
//currently ignores blendMap
//{"blendMap",char*,char*}
} else
if ( Var == NULL )
{
if ( stricmp( Type , "portal" ) == 0 ) sf_portal = true;else
if ( stricmp( Type , "fogonly" ) == 0 ) sf_fogonly = true;else
if ( stricmp( Type , "nomipmaps" ) == 0 ) sf_nomipmaps = true;else
if ( stricmp( Type , "polygonOffset" ) == 0 ) sf_polygonOffset = true;else
if ( stricmp( Type , "lightning" ) == 0 ) sf_lightning = true;else
if ( stricmp( Type , "backsided" ) == 0 ) sf_backsided = true;
if ( stricmp( Type , "qer_nocarve" ) == 0 ) sf_qer_nocarve = true;
else Error( "unknown token: %s" , Type );
} else
Error( "unexpected token found: %s" , Type );
}
void Surface::AddPass( RenderPass*& Pass )
{
}
/*END UNFINISHED BIT*/
char* getline( FILE*& F )
{
char line[4096];
char* lineptr = NULL;
while ( ( lineptr == NULL ) && ( !feof( F ) ) )
{
fgets( line , sizeof( line ) , F );
lineptr = line;
clean( lineptr );
}
return lineptr;
}
bool LoadScript( char* filename )
{
FILE* F;
if ( ( F = fopen( filename , "rt" ) ) != NULL )
{
char* lineptr;
while ( !feof( F ) )
{
lineptr = getline( F );
if ( lineptr != NULL )
{
char* Token = getstring( lineptr );
if ( ( stricmp( Token , "{" ) == 0 ) ||
( stricmp( Token , "}" ) == 0 ) )
{
Debug("surface expected, got: %s",Token);
return false;
} else
{
if ( lineptr != NULL ) {
Debug("surface name followed by unexpected token: %s",lineptr);
return false;
}
Surface* newSurface;
if ( ( newSurface = CreateSurface( Token ) ) != NULL )
{
lineptr = getline( F );
if ( lineptr == NULL ) {
Error("unexpected end of file"); return false;
}
Token = getstring( lineptr );
if ( stricmp( Token , "{" ) != 0 ) {
Error("unexpected token found: %s", Token); return false;
}
if ( lineptr != NULL ) {
Error("{ followed by unexpected token: %s", lineptr);
return false;
}
while ( ( ( Token = lineptr = getline( F ) ) != NULL ) &&
( ( Token = getstring( lineptr ) ) != NULL ) &&
( stricmp( Token , "}" ) != 0 ) )
{
if ( stricmp( Token , "{" ) != 0 )
{
newSurface->AddParam( Token , lineptr );
} else
{
if ( lineptr != NULL ) {
Error("{ followed by unexpected token: %s", lineptr);
return false;
}
RenderPass* newPass = new RenderPass;
while ( ( ( Token = lineptr = getline( F ) ) != NULL ) &&
( ( Token = getstring( lineptr ) ) != NULL ) &&
( stricmp( Token , "}" ) != 0 ) )
{
newPass->AddParam( Token , lineptr );
}
if ( Token == NULL ) {
Error("unexpected end of file"); return false;
}
if ( lineptr != NULL ) {
Error("} followed by unexpected token: %s ", lineptr);
return false;
}
newSurface->AddPass( newPass );
}
}
if ( Token == NULL ) {
Error("unexpected end of file"); return false;
}
if ( lineptr != NULL ) {
Error("} followed by unexpected token: %s ", lineptr);
return false;
}
} else
Error("failed to make surface");
}
}
}
fclose(F);
return true;
} else
return false;
}

97
Script.h Executable file
View File

@ -0,0 +1,97 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _RENDERPASS_H_
#define _RENDERPASS_H_
enum typeTextureEnum
{
texture_normal, texture_alpha, texture_anim
};
class RenderPass
{
public:
//tcMod - texcoords
float rp_rotate,rp_scalex,rp_scaley,rp_scrollx,rp_scrolly,
//i don't know what the values a-d are for.
rp_turba,rp_turbb,rp_turbc,rp_turbd,
//i don't know what the values a-d are for.
rp_stretchsina,rp_stretchsinb,rp_stretchsinc,rp_stretchsind;
//various gl functions
GLenum blend_sfactor,blend_dfactor,alpha_func,depth_func;
GLclampf alpha_ref;
//misc commands
bool rp_detail,rp_depthwrite,rp_clamptexcoords;
NodeDictionary AnimationFramesNames;
NodeDictionary AnimationFramesBuffers;
int AnimationFramesNum;
char* AlphaName;
GLuint AlphaBuffer;
char* TextureName;
GLuint TextureBuffer;
typeTextureEnum typeTexture;
RenderPass();
void AddParam( char* Type, char* Var );
};
typedef RenderPass* RenderPassPtr;
enum culltype {cull_normal,cull_none, cull_disable, cull_twosided, cull_backsided, cull_back};
class Surface
{
public:
//surfaceparam
bool sp_trans ,sp_metalsteps,sp_nolightmap,sp_nodraw ,sp_noimpact,
sp_nonsolid ,sp_nomarks ,sp_nodrop ,sp_nodamage ,sp_playerclip,
sp_structural ,sp_slick ,sp_origin ,sp_areaportal,sp_fog,
sp_lightfilter,sp_water ,sp_slime ,sp_sky ,sp_lava,
sf_light1;
//cull
culltype cull;
//misc commands
bool sf_portal,sf_fogonly,sf_nomipmaps,sf_polygonOffset,
sf_lightning,sf_backsided,sf_qer_nocarve;
float sf_light,sf_tesssize,sf_sort,sf_qer_trans,sf_q3map_backsplash,
sf_q3map_surfacelight;
char *sf_sky,*sf_q3map_lightimage,*sf_qer_editorimage,
*sf_qer_lightimage;
NodeDictionary RenderPasses;
UINT32 pass_num;
Surface();
~Surface();
void AddParam( char* Type, char* Var );
void AddPass ( RenderPass* Pass );
void LoadTextures();
void DestroyTextures();
};
typedef Surface* SurfacePtr;
Surface* LoadSurface( char* filename );
void freeSurface( Surface* );
#endif //_RENDERPASS_H_

332
TEXT.CPP Executable file
View File

@ -0,0 +1,332 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Some useful text display routines for text within OpenGL window panes..
//
// Uses charset from Beeb micro
//
#include "system.h"
#include "ndictionary.h" // needed so I can include "md3view.h"
#include "md3gl.h"
#include "DiskIO.h"
#include "md3view.h" // needed so I can access mdview struct
#include "text.h"
int g_iScreenWidth = 0;
int g_iScreenHeight = 0;
bool gbTextInhibit = false;
// internal protos...
//
void Text_EnsureCreated(void);
BYTE byChars[]=
{
0,0,0,0,0,0,0,0
,24,24,24,24,24,0,24,0
,108,108,108,0,0,0,0,0
,108,108,-2,108,-2,108,108,0
,12,63,104,62,11,126,24,0
,96,102,12,24,48,102,6,0
,56,108,108,56,109,102,59,0
,12,24,48,0,0,0,0,0
,12,24,48,48,48,24,12,0
,48,24,12,12,12,24,48,0
,0,24,126,60,126,24,0,0
,0,24,24,126,24,24,0,0
,0,0,0,0,0,12,12,48
,0,0,0,126,0,0,0,0
,0,0,0,0,0,0,24,24
,0,6,12,24,48,96,0,0
,60,102,110,126,118,102,60,0
,24,56,24,24,24,24,126,0
,60,102,6,12,24,48,126,0
,60,102,6,28,6,102,60,0
,12,28,60,108,126,12,12,0
,126,96,124,6,6,102,60,0
,28,48,96,124,102,102,60,0
,126,6,12,24,48,48,48,0
,60,102,102,60,102,102,60,0
,60,102,102,62,6,12,56,0
,0,0,24,24,0,24,24,0
,0,0,24,24,0,24,24,48
,12,24,48,96,48,24,12,0
,0,0,126,0,126,0,0,0
,48,24,12,6,12,24,48,0
,60,102,12,24,24,0,24,0
,60,102,110,106,110,96,60,0
,60,102,102,126,102,102,102,0
,124,102,102,124,102,102,124,0
,60,102,96,96,96,102,60,0
,120,108,102,102,102,108,120,0
,126,96,96,124,96,96,126,0
,126,96,96,124,96,96,96,0
,60,102,96,110,102,102,60,0
,102,102,102,126,102,102,102,0
,126,24,24,24,24,24,126,0
,62,12,12,12,12,108,56,0
,102,108,120,112,120,108,102,0
,96,96,96,96,96,96,126,0
,99,119,127,107,107,99,99,0
,102,102,118,126,110,102,102,0
,60,102,102,102,102,102,60,0
,124,102,102,124,96,96,96,0
,60,102,102,102,106,108,54,0
,124,102,102,124,108,102,102,0
,60,102,96,60,6,102,60,0
,126,24,24,24,24,24,24,0
,102,102,102,102,102,102,60,0
,102,102,102,102,102,60,24,0
,99,99,107,107,127,119,99,0
,102,102,60,24,60,102,102,0
,102,102,102,60,24,24,24,0
,126,6,12,24,48,96,126,0
,124,96,96,96,96,96,124,0
,0,96,48,24,12,6,0,0
,62,6,6,6,6,6,62,0
,24,60,102,66,0,0,0,0
,0,0,0,0,0,0,0,-1
,28,54,48,124,48,48,126,0
,0,0,60,6,62,102,62,0
,96,96,124,102,102,102,124,0
,0,0,60,102,96,102,60,0
,6,6,6,62,102,102,62,0
,0,0,60,102,126,96,60,0
,28,48,48,124,48,48,48,0
,0,0,62,102,102,62,6,60
,96,96,124,102,102,102,102,0
,24,0,56,24,24,24,60,0
,24,0,56,24,24,24,24,112
,96,96,102,108,120,108,102,0
,56,24,24,24,24,24,60,0
,0,0,54,127,107,99,99,0
,0,0,124,102,102,102,102,0
,0,0,60,102,102,102,60,0
,0,0,124,102,102,124,96,96
,0,0,62,102,102,62,6,7
,0,0,108,118,96,96,96,0
,0,0,62,96,60,6,124,0
,48,48,124,48,48,48,28,0
,0,0,102,102,102,102,62,0
,0,0,102,102,102,60,24,0
,0,0,99,99,107,127,54,0
,0,0,102,60,24,60,102,0
,0,0,102,102,102,62,6,60
,0,0,126,12,24,48,126,0
,12,24,24,112,24,24,12,0
,24,24,24,0,24,24,24,0
,48,24,24,14,24,24,48,0
,49,107,70,0,0,0,0,0
,126,195,219,211,211,219,195,126
};
GLuint gFontOffset;
BOOL bTextCreated=FALSE;
#define TOTALFONTENTRIES 128 // enough for all 7-bit ascii range
// This should be called once at program start, but only after OpenGL is up and running (and in context)...
//
// (Actually it's now called every time you print a string, but the bool check protects it)
//
void Text_EnsureCreated(void)
{
static bool bFlipped = FALSE;
if (!bTextCreated)
{
if (!bFlipped)
{
// first stage is to flip all the char defs top to bottom to match OpenGL format...
//
for (int i=0; i<sizeof(byChars); i+=TEXT_DEPTH)
{
// each char...
//
for (int j=0; j<4; j++)
{
byte b = byChars[i+j];
byChars[i+j] = byChars[i+(7-j)];
byChars[i+(7-j)] = b;
}// for (int j=0; j<4; j++)
}// for (int i=0; i<sizeof(byChars); i+=TEXT_DEPTH)
bFlipped = TRUE;
}// if (!bFlipped)
// make a raster Font for OpenGL...
//
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
// gFontOffset = TEXT_CALLLIST;
gFontOffset = glGenLists(TOTALFONTENTRIES);
for (int i=0; i<sizeof(byChars)/TEXT_DEPTH; i++)
{
glNewList(gFontOffset + ' '+i,GL_COMPILE);
glBitmap(TEXT_WIDTH, TEXT_DEPTH,0.0,0.0,TEXT_WIDTH,0.0,&byChars[i*TEXT_DEPTH]);
glEndList();
}
bTextCreated=TRUE;
}// if (!bTextCreated)
}// void Text_EnsureCreated(void)
// Called at end of program from scModels_Destroy() since this program doesn't appear to have
// much in the way of begin/end points to attach things to...
//
// OpenGL should still be active at this point for giving back lists, but if it isn't then I suspect
// it doesn't matter 100% since we'll be dropping back to Windows anyway which will (hopefully) free up everything.
//
void Text_Destroy(void)
{
if (bTextCreated)
{
glDeleteLists(gFontOffset,TOTALFONTENTRIES);
bTextCreated = FALSE;
}
}
// Displays a text string at a 3d world point...
//
void Text_Display(LPCSTR psString, Vec3 v3DPos, byte r, byte g, byte b)
{
if (!gbTextInhibit)
{
// it appears I have to do this in MD3View or paint messages keep getting back here even after SysOnDestroy()...
//
if (!mdview.done)
{
int iStrlen = strlen(psString);
Text_EnsureCreated();
if (iStrlen)
{
glPushAttrib(GL_LIGHTING_BIT | GL_LIST_BIT | GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glColor3ub(r,g,b);
glRasterPos3f(v3DPos[0],v3DPos[1],v3DPos[2]);
glListBase(gFontOffset);
glCallLists(iStrlen,GL_UNSIGNED_BYTE,(GLubyte *) psString);
glPopAttrib();
}
}
}
}
// Displays text at a 2d screen coord. 0,0 is top left corner, add TEXT_DEPTH per Y to go down a line
//
// Note new param 'bResizeStringIfNecessary', this is so that if a string goes off the left hand edge of the window
// it will now (instead of just not printing the entire string like OpenGL would normally do) move the print pos up
// a char each time until it fits. It may take more time to do so only set the bool true if really needed.
//
// return value is a convenient xpos for next xpos along after this strlen...
//
int Text_DisplayFlat(LPCSTR psString, int x, int y, byte r, byte g, byte b, bool bResizeStringIfNecessary /* = false */)
{
int iRetVal = x;
if (!gbTextInhibit) // this will also mean the non-existant cursor isn't moved on by the retval, but that shouldn't matter under this circumstance
{
// it appears I have to do this in MD3View or paint messages keep getting back here even after SysOnDestroy()...
//
if (!mdview.done)
{
int iStrlen = strlen(psString);
GLboolean bRasterValid;
Text_EnsureCreated();
// (source indenting only to help with gl stack status)
if (iStrlen)
{
glPushAttrib(GL_LIGHTING_BIT | GL_LIST_BIT | GL_TRANSFORM_BIT | GL_ENABLE_BIT);
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
{
glLoadIdentity();
gluOrtho2D(0.0,(GLfloat) g_iScreenWidth, 0.0, (GLfloat) g_iScreenHeight);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
glLoadIdentity();
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glColor3ub(r,g,b);
// glRasterPos2i(x,y); // from bottom left
// pre-dec to counter pre-inc coming up...
//
x-=TEXT_WIDTH;
iStrlen+=1;
psString--;
do
{
x+=TEXT_WIDTH;
iStrlen-=1;
psString++;
//
glRasterPos2i(x,(g_iScreenHeight-y)-TEXT_DEPTH);
glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID,&bRasterValid);
}
while ( bResizeStringIfNecessary && !bRasterValid && iStrlen);
if (iStrlen) // because it may have all been clipped off the left
{
glListBase(gFontOffset);
glCallLists(iStrlen,GL_UNSIGNED_BYTE,(GLubyte *) psString);
iRetVal += iStrlen*TEXT_WIDTH;
}
}
glPopMatrix(); // GL_MODELVIEW
}
glMatrixMode(GL_PROJECTION);
glPopMatrix();
//
}
glPopAttrib();
}
}
}
return iRetVal;
}
////////////////////////////// eof /////////////////////////////////

40
TEXT.H Executable file
View File

@ -0,0 +1,40 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TEXT_H
#define TEXT_H
#define TEXT_WIDTH 8
#define TEXT_DEPTH 8
//void Text_Create(void); // called automatically internally
void Text_Destroy(void); // should be called at program shutdown
void Text_Display(LPCSTR psString, Vec3 v3DPos, byte r, byte g, byte b);
int Text_DisplayFlat(LPCSTR psString, int x, int y, byte r, byte g, byte b, bool bResizeStringIfNecessary = false);
extern int g_iScreenWidth;
extern int g_iScreenHeight;
extern bool gbTextInhibit;
#endif // #ifndef TEXT_H
////////////////////////// eof ///////////////////////////

24
Targa.h Executable file
View File

@ -0,0 +1,24 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TARGA_H_
#define _TARGA_H_
bool loadTGA (char *name, byte **pixels, unsigned int *width, unsigned int *height, unsigned int *format);
#endif

845
animation.cpp Executable file
View File

@ -0,0 +1,845 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.h"
#include "ndictionary.h"
#include "md3gl.h"
#include "md3view.h"
#include "oddbits.h"
#include <vector>
#include "animation.h"
using namespace std;
int Model_EnsureCurrentFrameLegal(gl_model* model, int iNewFrame);
double getDoubleTime (void);
/*
sets all model frames to 0
*/
void rewindAnim()
{
NodePosition pos;
gl_model *model;
for (pos=mdview.modelList->first() ; pos!=NULL ; pos=mdview.modelList->after(pos))
{
model = (gl_model *)pos->element();
model->currentFrame = 0;
model->currentFrame = Model_EnsureCurrentFrameLegal(model, model->currentFrame);
}
// for (unsigned int i=0; i<mdview.model->Header.Mesh_num ; i++) {
// mdview.frames[i]=0;
// }
}
/*
exectues every frame
*/
void animation_loop()
{
NodePosition pos;
gl_model *model;
if (mdview.modelList->isEmpty())
return;
bool bModelUpdated = false;
//
// sanity check, legalise any locked frames in case they were missed elsewhere (dunno why/how that occurs, but...)
//
for (pos=mdview.modelList->first() ; pos!=NULL ; pos=mdview.modelList->after(pos))
{
model = (gl_model *)pos->element();
int iFrame = Model_EnsureCurrentFrameLegal(model, model->currentFrame);
if (model->currentFrame != iFrame)
{
model->currentFrame = iFrame;
bModelUpdated = true;
}
}
if (!mdview.animate)
{
if (mdview.interpolate)
mdview.frameFrac = 0.5f;
else
mdview.frameFrac = 0;
//if (bModelUpdated)
{
render_mdview();
swap_buffers();
}
return;
}
double timeStamp2 = getDoubleTime();
mdview.frameFrac = (float)((timeStamp2 - mdview.timeStamp1) / mdview.animSpeed);
if (mdview.frameFrac > 1.f)
{
mdview.frameFrac = 0;
mdview.timeStamp1 = timeStamp2;
for (pos=mdview.modelList->first() ; pos!=NULL ; pos=mdview.modelList->after(pos))
{
model = (gl_model *)pos->element();
model->currentFrame = GetNextFrame_MultiLocked(model, model->currentFrame, 1);
// note legalise before generic wrap, otherwise last sequence won't loop (if relevant)
//
model->currentFrame = Model_EnsureCurrentFrameLegal(model, model->currentFrame);
if (model->currentFrame == model->iNumFrames) // itu?
model->currentFrame = 0;
}
render_mdview();
swap_buffers();
}
else
if (mdview.interpolate || bModelUpdated)
{
render_mdview();
swap_buffers();
}
}
// returns index else -1 for not frame-not-found-in-sequences...
//
int GetMultiLockedSequenceIndexFromFrame(int iFrame, bool bIsUpper )
{
MultiSequenceLock_t* pMultiLock = (bIsUpper)?&MultiSequenceLock_Upper:&MultiSequenceLock_Lower;
MultiSequenceLock_t::iterator it;
int iIndex=0;
for (it = pMultiLock->begin(); it != pMultiLock->end(); ++it, iIndex++)
{
int iSeqIndex = *it;
Sequence_t* pSeq = (bIsUpper)?Animation_GetUpperSequence(iSeqIndex):Animation_GetLowerSequence(iSeqIndex);
assert(pSeq);
if (pSeq)
{
int iSeqFrameFirst = pSeq->iTargetFrame;
int iSeqFrameLast = (iSeqFrameFirst + pSeq->iFrameCount)-1;
if (iFrame >= iSeqFrameFirst && iFrame <= iSeqFrameLast)
return iIndex;
}
}
return -1;
}
Sequence_t* GetMultiLockedSequenceFromFrame(int iFrame, bool bIsUpper )
{
int iMultiLockSequenceIndex = GetMultiLockedSequenceIndexFromFrame( iFrame, bIsUpper );
if (iMultiLockSequenceIndex == -1)
return NULL;
MultiSequenceLock_t* pMultiLock = (bIsUpper)?&MultiSequenceLock_Upper:&MultiSequenceLock_Lower;
int iIndex = pMultiLock->at(iMultiLockSequenceIndex);
return bIsUpper?Animation_GetUpperSequence(iIndex):Animation_GetLowerSequence(iIndex);
}
Sequence_t *GetLockedSequence_Upper(gl_model* model)
{
if (model && (model == pModel_Upper || model->pModel_LOD0 == pModel_Upper) && iAnimLockNumber_Upper)
{
return Animation_GetUpperSequence( iAnimLockNumber_Upper-1 );
}
return NULL;
}
Sequence_t *GetLockedSequence_Lower(gl_model* model)
{
if (model && (model == pModel_Lower || model->pModel_LOD0 == pModel_Lower) && iAnimLockNumber_Lower)
{
return Animation_GetLowerSequence( iAnimLockNumber_Lower-1 );
}
return NULL;
}
// Another uberhack, sigh....
//
// gets the next frame in a multilocked sequence, where iStepVal can be +ve or -ve, (though usually just -1/0/1)
//
// (this isn't staggeringly fast at certain points, but 99% of the time it executes quickly)
//
int GetNextFrame_MultiLocked(gl_model* pModel, int iFrame, int iStepVal)
{
Sequence_t* pSeq = NULL;
bool bIsUpper = false;
if ((pSeq = GetLockedSequence_Upper(pModel)) != NULL)
bIsUpper = true;
else
if ((pSeq = GetLockedSequence_Lower(pModel)) != NULL)
bIsUpper = false;
if (pSeq && pSeq->bMultiSeq)
{
int iNewFrame = iFrame;
int iStep = (iStepVal<0)?-1:1;
for (int iStepValRemaining = iStepVal; iStepValRemaining!=0; iStepValRemaining += -iStep)
{
int iThisFrame = iNewFrame;
int iNextFrame = iNewFrame + iStep;
int iMultiLockSequenceIndex = GetMultiLockedSequenceIndexFromFrame( iThisFrame, bIsUpper );
if (iMultiLockSequenceIndex != -1)
{
MultiSequenceLock_t* pMultiLock = (bIsUpper)?&MultiSequenceLock_Upper:&MultiSequenceLock_Lower;
int iIndex = pMultiLock->at(iMultiLockSequenceIndex);
pSeq = bIsUpper?Animation_GetUpperSequence(iIndex):Animation_GetLowerSequence(iIndex);
assert(pSeq); //
if (pSeq) // itu?
{
// this is the sequence we're currently in, does the proposed next frame also sit within this one?...
//
int iSeqFrameFirst = pSeq->iTargetFrame;
int iSeqFrameLast = (iSeqFrameFirst + pSeq->iFrameCount)-1;
if (iNextFrame >= iSeqFrameFirst && iNextFrame <= iSeqFrameLast)
{
// yes, so adopt it...
//
iNewFrame = iNextFrame;
}
else
{
// new frame is outside of current group, so get the index of the sequence after (or before) this one,
// and adopt the first or last frame of it...
//
int iNumAvailableSequences = pMultiLock->size();
iMultiLockSequenceIndex += iStep;
if (iMultiLockSequenceIndex >= iNumAvailableSequences)
iMultiLockSequenceIndex = 0;
if (iMultiLockSequenceIndex < 0)
iMultiLockSequenceIndex = iNumAvailableSequences-1;
iIndex = pMultiLock->at(iMultiLockSequenceIndex);
Sequence_t* pSeq = bIsUpper?Animation_GetUpperSequence(iIndex):Animation_GetLowerSequence(iIndex);
assert(pSeq); //
if (pSeq) // itu?
{
iSeqFrameFirst = pSeq->iTargetFrame;
iSeqFrameLast = (iSeqFrameFirst + pSeq->iFrameCount)-1;
iNewFrame = (iStep>0)?iSeqFrameFirst:iSeqFrameLast;
}
else
{
return iFrame+iStepVal; // ... let the overall legaliser adjust this frame sometime after returning
}
}
}
else
{
// I don't think we'll ever get here, but I've kind of stopped caring...
//
return iFrame+iStepVal; // ... let the overall legaliser adjust this frame sometime after returning
}
}
else
{
// err...
return iFrame+iStepVal; // ... let the overall legaliser adjust this frame sometime after returning
}
}
return iNewFrame;
}
else
{
return iFrame+iStepVal;
}
}
// this only returns the legalised frame, it does NOT set it...
//
int Model_EnsureCurrentFrameLegal(gl_model* model, int iFrame)
{
Sequence_t *pSeq = NULL;
bool bIsUpper = false;
if ((pSeq = GetLockedSequence_Upper(model)) != NULL)
bIsUpper = true;
else
if ((pSeq = GetLockedSequence_Lower(model)) != NULL)
bIsUpper = false;
if (pSeq)
{
if (pSeq->bMultiSeq)
{
// multi-seq locks are a special case, the wrap logic can be pretty freaky, so...
//
if (GetMultiLockedSequenceFromFrame(iFrame, bIsUpper ))
return iFrame; // frame is ok
// if we got here then we're outside all current multi-seqs, unfortunately because the specified sequences
// can be at any position within the master list order I can't just work out which 2 sequences I'm between
// and jump to the start of the higher one, so working on the principle that 99% of the time this code is
// used when lerping between frame & frame+1 I'll see if I can find iFrame-1 anywhere...
//
iFrame--;
MultiSequenceLock_t* pMultiLock = (bIsUpper)?&MultiSequenceLock_Upper:&MultiSequenceLock_Lower;
MultiSequenceLock_t::iterator it;
for (it = pMultiLock->begin(); it != pMultiLock->end(); ++it)
{
int iSeqIndex = *it;
Sequence_t* pSeq = (bIsUpper)?Animation_GetUpperSequence(iSeqIndex):Animation_GetLowerSequence(iSeqIndex);
assert(pSeq);
if (pSeq)
{
int iSeqFrameFirst = pSeq->iTargetFrame;
int iSeqFrameLast = (iSeqFrameFirst + pSeq->iFrameCount)-1;
if (iFrame >= iSeqFrameFirst && iFrame <= iSeqFrameLast)
{
// got it, so is there another sequence after this?
//
if (++it != pMultiLock->end())
{
iSeqIndex = *it;
pSeq = (bIsUpper)?Animation_GetUpperSequence(iSeqIndex):Animation_GetLowerSequence(iSeqIndex);
assert(pSeq);
if (pSeq)
return pSeq->iTargetFrame; // return first frame of next seq in list
}
else
{
// reached end of list...
//
break;
}
}
}
}
// sod it, whatever happened, let's start at the beginning of the list again...
//
it = pMultiLock->begin();
int iSeqIndex = *it;
pSeq = (bIsUpper)?Animation_GetUpperSequence(iSeqIndex):Animation_GetLowerSequence(iSeqIndex);
assert(pSeq);
if (pSeq)
iFrame = pSeq->iTargetFrame;
}
else
{
if (iFrame > (pSeq->iTargetFrame+pSeq->iFrameCount)-1)
{
// OOR above, loop or wrap?...
//
if (pSeq->iLoopFrame != -1)
{
// account for loop frame...
//
iFrame = pSeq->iTargetFrame + pSeq->iLoopFrame;
}
else
{
// no loop, straight wrap...
//
// iFrame = pSeq->iTargetFrame; // wrap
iFrame =(pSeq->iTargetFrame+pSeq->iFrameCount)-1; // stop at end
}
}
else
if (iFrame < pSeq->iTargetFrame)
{
// OOR below, wrap only...
//
iFrame = pSeq->iTargetFrame;
}
}
}
//sanity
if (iFrame > (int)model->iNumFrames)
{
iFrame = model->iNumFrames;
}
return iFrame;
}
void SetLODLevel(int iLOD)
{
mdview.iLODLevel = iLOD;
}
void FrameAdvanceAnim(int iStepVal) // basically I only use this as +/-1, but other vals should be ok
{
NodePosition pos;
gl_model *model;
for (pos=mdview.modelList->first() ; pos!=NULL ; pos=mdview.modelList->after(pos))
{
model = (gl_model *)pos->element();
model->currentFrame = GetNextFrame_MultiLocked(model, model->currentFrame, iStepVal);
model->currentFrame = Model_EnsureCurrentFrameLegal(model, model->currentFrame); // handle range locking before generic wrap check
int iFrame = model->currentFrame; // saves messing with unsigned/signed range conflicts
// technically this isn't 100% correct if you were stepping by other values than +/- 1 because I'm
// just wrapping to the other end of the range, and not taking into account the amount that you
// overflowed it by. If you want to alter this then help yourself.
//
if (iFrame >= (int)(model->iNumFrames))
{
iFrame = 0;
}
if (iFrame <0) // fix for unsigned
{
iFrame = model->iNumFrames-1;
}
model->currentFrame = iFrame;
}
mdview.animate = false;
}
vector < Sequence_t > Sequences_LowerAnims;
vector < Sequence_t > Sequences_UpperAnims;
MultiSequenceLock_t MultiSequenceLock_Upper;
MultiSequenceLock_t MultiSequenceLock_Lower;
Sequence_t Sequence_Upper_Fake;
Sequence_t Sequence_Lower_Fake;
int iAnimLockNumber_Upper = 0;
int iAnimLockNumber_Lower = 0;
int iAnimDisplayNumber_Upper = 0;
int iAnimDisplayNumber_Lower = 0;
int iAnimLockLongestString= 0; // for aesthetics
gl_model* pModel_Lower = NULL;
gl_model* pModel_Upper = NULL;
int Animation_GetNumLowerSequences(void)
{
return Sequences_LowerAnims.size();
}
int Animation_GetNumUpperSequences(void)
{
return Sequences_UpperAnims.size();
}
// iIndex either = 0-based index if +ve, or -2 (because of blah-1 before call)
//
Sequence_t* Animation_GetLowerSequence(int iIndex)
{
if (iIndex<0) // bleh...
return &Sequence_Lower_Fake;
return &Sequences_LowerAnims[iIndex];
}
// iIndex either = 0-based index if +ve, or -2 (because of blah-1 before call)
//
Sequence_t* Animation_GetUpperSequence(int iIndex)
{
if (iIndex<0) // bleh...
return &Sequence_Upper_Fake;
return &Sequences_UpperAnims[iIndex];
}
// to do a request by Shubes, this works out which sequence you would be in on this frame if you were in a lock...
//
Sequence_t* Animation_FromUpperFrame( int iFrame )
{
int iLoopCount = Animation_GetNumUpperSequences();
for (int i=0; i<iLoopCount; i++)
{
Sequence_t *pSeq = Animation_GetUpperSequence(i);
if (iFrame >= pSeq->iTargetFrame &&
iFrame < pSeq->iTargetFrame + pSeq->iFrameCount
)
{
return pSeq;
}
}
return NULL;
}
Sequence_t* Animation_FromLowerFrame( int iFrame )
{
int iLoopCount = Animation_GetNumLowerSequences();
for (int i=0; i<iLoopCount; i++)
{
Sequence_t *pSeq = Animation_GetLowerSequence(i);
if (iFrame >= pSeq->iTargetFrame &&
iFrame < pSeq->iTargetFrame + pSeq->iFrameCount
)
{
return pSeq;
}
}
return NULL;
}
void ClearAnimationCFG()
{
Sequences_LowerAnims.clear();
Sequences_UpperAnims.clear();
Menu_UpperAnims_Clear();
Menu_LowerAnims_Clear();
Sequence_Upper_Fake.bMultiSeq = true;
Sequence_Lower_Fake.bMultiSeq = true;
iAnimLockNumber_Upper = 0;
iAnimLockNumber_Lower = 0;
iAnimDisplayNumber_Upper = 0;
iAnimDisplayNumber_Lower = 0;
iAnimLockLongestString= 0;
pModel_Lower = NULL;
pModel_Upper = NULL;
mdview.xPos = 0.0f;
mdview.yPos = 0.0f;
mdview.rotAngleX =
mdview.rotAngleY = 0.0f;
mdview.rotAngleZ = -90.0f;
mdview.bAnimCFGLoaded = false;
mdview.bAnimIsMultiPlayerFormat = false;
}
void ReportFrameMismatches(Sequence_t* pSeq, gl_model* pModel)
{
if (pSeq)
{
int iModelAnims = pModel->iNumFrames;
int iCFGAnims = pSeq->iTargetFrame + pSeq->iFrameCount; // no need to -1 because of 0-based indexing
if (iModelAnims > iCFGAnims)
{
WarningBox(va("Model : \"%s\"\n\n... has %d frames, but animations for it only use %d frames\n\n( ... so %d frame(s) are currently just wasting space )",pModel->sMDXFullPathname,iModelAnims,iCFGAnims, iModelAnims-iCFGAnims ));
}
else
if (iModelAnims < iCFGAnims)
{
ErrorBox(va("Model : \"%s\"\n\n... has %d frames, but animations for it assume %d frames\n\n( ... so you'll get errors accessing the last %d frame(s)! )",pModel->sMDXFullPathname,iModelAnims,iCFGAnims, iCFGAnims-iModelAnims));
}
}
}
// 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...
//
void LoadAnimationCFG(LPCSTR psFullPath, HDC hDC) // hDC for text metrics
{
int iLongestTextMetric = 0;
SIZE Size;
bool bOk = false;
FILE *handle = fopen(psFullPath,"rt");
if (handle)
{
mdview.bAnimCFGLoaded = true;
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.iTargetFrame, &seq.iFrameCount, &seq.iLoopFrame, &seq.iFrameSpeed );
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.iTargetFrame, &seq.iFrameCount, &seq.iLoopFrame, &seq.iFrameSpeed );
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.iTargetFrame;
}
if ( !strnicmp(sLine,"LEGS_",5))
{
if (iFirstFrameAfterTorso == -1)
{
iFirstFrameAfterTorso = seq.iTargetFrame;
}
// now correct the leg framenumber...
//
if (iFirstFrameAfterBoth != -1) // if it did, then there'd be no torso frames, so no adj nec.
{
seq.iTargetFrame -= (iFirstFrameAfterTorso - iFirstFrameAfterBoth);
}
}
bElementsScannedOk = true;
}
}
}
if (bElementsScannedOk)
{
seq.sName = sLine;
//
// this line seems to be ok...
//
// OutputDebugString(va("%s %d %d %d %d\n",seq.sName.c_str(), seq.iTargetFrame, 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 < (int)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 < (int)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).iTargetFrame,((*it).iTargetFrame+(*it).iFrameCount)-1,((*it).iLoopFrame==-1)?"":va(" Loop %d",(*it).iTargetFrame+(*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).iTargetFrame,((*it).iTargetFrame+(*it).iFrameCount)-1,((*it).iLoopFrame==-1)?"":va(" Loop %d",(*it).iTargetFrame+(*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);
}
}
}

68
animation.h Executable file
View File

@ -0,0 +1,68 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANIMATION_H
#define ANIMATION_H
#include <vector>
#include <set>
#include <list>
using namespace std;
typedef vector<int> MultiSequenceLock_t;
extern MultiSequenceLock_t MultiSequenceLock_Upper;
extern MultiSequenceLock_t MultiSequenceLock_Lower;
typedef struct
{
string sName;
int iTargetFrame;
int iFrameCount;
int iLoopFrame;
int iFrameSpeed;
bool bMultiSeq;
} Sequence_t;
int GetNextFrame_MultiLocked(gl_model* pModel, int iFrame, int iStepVal);
Sequence_t* GetMultiLockedSequenceFromFrame(int iFrame, bool bIsUpper );
int Model_EnsureCurrentFrameLegal(gl_model* model, int iFrame);
Sequence_t* Animation_GetLowerSequence(int iIndex);
Sequence_t* Animation_GetUpperSequence(int iIndex);
int Animation_GetNumLowerSequences(void);
int Animation_GetNumUpperSequences(void);
Sequence_t* Animation_FromUpperFrame(int iFrame);
Sequence_t* Animation_FromLowerFrame(int iFrame);
void ClearAnimationCFG();
void LoadAnimationCFG(LPCSTR psFullPath, HDC hDC);
extern int iAnimLockNumber_Upper;
extern int iAnimLockNumber_Lower;
extern int iAnimDisplayNumber_Upper;
extern int iAnimDisplayNumber_Lower;
extern int iAnimLockLongestString;
extern gl_model* pModel_Lower;
extern gl_model* pModel_Upper;
#endif // #ifndef ANIMATION_H
//////////////////// eof //////////////////////

274
bmp.cpp Executable file
View File

@ -0,0 +1,274 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <windows.h>
#include <stdio.h>
#include <assert.h>
// #include "oddbits.h"
#include "bmp.h"
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;
}
// open 24-bit RGB file either to disk or memory
//
// if psFileName == NULL, open memory file instead
//
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;
///////
if (pBMP)
{
free(pBMP);
pBMP = NULL;
}
fhBMP = NULL;
///////
if (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;
}
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)
//
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)
//
bool BMP_Close(LPCSTR psFilename, bool bFlipFinal)
{
if (fhBMP)
{
fclose (fhBMP);
}
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;
}
////////////////// eof //////////////////

51
bmp.h Executable file
View File

@ -0,0 +1,51 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BMP_H
#define BMP_H
#ifndef BITMAPINFOHEADER
#include <windows.h>
#endif
#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;
bool BMP_Open (LPCSTR psFilename, int iWidth, int iHeight);
bool BMP_WritePixel (byte Red, byte Green, byte Blue);
bool BMP_WriteLinePadding(int iPixelsPerLine);
bool BMP_Close (LPCSTR psFilename, bool bFlipFinal);
bool BMP_GetMemDIB (void *&pvAddress, int &iBytes);
#endif // #ifndef BMP_H
/////////////////// eof ////////////////////

89
clipboard.cpp Executable file
View File

@ -0,0 +1,89 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include "oddbits.h"
#include "clipboard.h"
extern HWND mainhWnd;
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(mainhWnd))
{
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(mainhWnd))
{
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;
}
//////////////// eof ////////////////

30
clipboard.h Executable file
View File

@ -0,0 +1,30 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLIPBOARD_H
#define CLIPBOARD_H
BOOL Clipboard_SendString(LPCSTR psString);
BOOL ClipBoard_SendDIB(LPVOID pvData, int iBytes);
#endif
/////////////////// eof //////////////////

341
drag.cpp Executable file
View File

@ -0,0 +1,341 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.h"
#include "ndictionary.h"
#include "md3gl.h"
#include "md3view.h"
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;
}
bool drag( 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)
{
mdview.xPos += ((float)(x - m_x)/10.f) * MOUSE_XPOS_SCALE;
mdview.yPos -= ((float)(y - m_y)/10.f) * MOUSE_YPOS_SCALE;
}
else
{
s = GetAsyncKeyState(0x5A); // Z key
if ( s&0x8000)
{
mdview.rotAngleZ += (float)(x - m_x) * MOUSE_ROT_SCALE;
// mdview.rotAngleZ += (float)(y - m_y) * MOUSE_ROT_SCALE;
if (mdview.rotAngleZ> 360.0f) mdview.rotAngleZ=mdview.rotAngleZ-360.0f;
if (mdview.rotAngleZ<-360.0f) mdview.rotAngleZ=mdview.rotAngleZ+360.0f;
}
else
{
mdview.rotAngleY += (float)(x - m_x) * MOUSE_ROT_SCALE;
mdview.rotAngleX += (float)(y - m_y) * MOUSE_ROT_SCALE;
if (mdview.rotAngleY> 360.0f) mdview.rotAngleY=mdview.rotAngleY-360.0f;
if (mdview.rotAngleY<-360.0f) mdview.rotAngleY=mdview.rotAngleY+360.0f;
if (mdview.rotAngleX> 360.0f) mdview.rotAngleX=mdview.rotAngleX-360.0f;
if (mdview.rotAngleX<-360.0f) mdview.rotAngleX=mdview.rotAngleX+360.0f;
}
}
repaint_main();
set_cursor( m_x, m_y );
bRepaintAndSetCursor = true;
}
} else
if ( keyFlags & KEY_RBUTTON )
{
if ( y != m_y )
{
mdview.zPos += ((float)(y - m_y)/10.f) * MOUSE_ZPOS_SCALE;
if (mdview.zPos<-1000.f) mdview.zPos=-1000.f;
if (mdview.zPos> 1000.f) mdview.zPos= 1000.f;
InvalidateRect( mdview.hwnd, NULL, FALSE );
set_cursor( m_x , m_y );
bRepaintAndSetCursor = true;
}
}
}
return bRepaintAndSetCursor;
}
void end_drag( mkey_enum keyFlags, int x, int y )
{
}
/*
=======
rotates an object by placing a trackball sphere around it
=======
*/
/*
int ModelControl::TrackballRotate(SNodePrimitive *shape, int sx, int sy, int ex, int ey)
{
if (!m_shape) return 0;
// simple quick method to avoid NAN results
if ((abs(sx - ex) < 2) && (abs(sy - ey) < 2)) {
return 0;
}
IAVector scale( TRACKBALL_SCALE, TRACKBALL_SCALE, TRACKBALL_SCALE);
IAMatrix tbMatrix = scale_mat(scale) * shape->m_inv_CTM;
IAPoint isecPnt2, isecPnt1, center, origin;
IAVector vec1, vec2, crossVec;
Idouble dotA, angle;
if (!m_tracer->ISectRayWithSphere( tbMatrix, &isecPnt1, sx, sy,
m_scene->width(), m_scene->height() )) {
return 0;
}
if (!m_tracer->ISectRayWithSphere( tbMatrix, &isecPnt2, ex, ey,
m_scene->width(), m_scene->height() )) {
return 0;
}
center = shape->m_CTM * center;
vec1 = isecPnt1 - center;
vec2 = isecPnt2 - center;
vec1.normalize();
vec2.normalize();
crossVec = cross( vec1, vec2 );
dotA = dot( vec1, vec2 );
angle = -atan2( 1, dotA );
shape->m_CTM_rotate = rot_mat(origin, crossVec, angle) * shape->m_CTM_rotate;
shape->updateCTM();
return 1;
}
SNodePrimitive *ISectTracer::ShootRay( int x, int y, int width, int height,
Intersection *isec, Ray *ray )
{
NodePosition pos;
Ray filmRay, worldRay, objectRay;
IAMatrix filmToWorld = m_scene->camera()->filmToWorld();
Intersection iStack[MAX_INTERSECT_PER_RAY], *iStackP, *iStackP2, *bestISec;
int numIntersect, isectTotal;
NodeSequenceInfo *gData = m_scene->m_geometryList;
Idouble tbest;
SNodePrimitive *primData;
Shape *rayShape;
filmRay.d[X] = ((double)(2*x)/(double)width) - 1;
filmRay.d[Y] = 1-((double)(2*y)/(double)height);
filmRay.d[Z] = -1; filmRay.d[W] = 1;
filmRay.P = IAPoint();
worldRay.d = filmToWorld * filmRay.d;
worldRay.P = filmToWorld * filmRay.P;
normalize( worldRay.d );
iStackP = iStack;
isectTotal = 0;
bestISec = NULL;
// calculate intersections for all shapes
for (pos = gData->first(); pos != NULL; pos = gData->after(pos) ) {
primData = (SNodePrimitive *)pos->element(); // get entry from geometry list
rayShape = primData->m_shape;
objectRay.d = primData->m_inv_CTM * worldRay.d; // transform ray to object space
objectRay.P = primData->m_inv_CTM * worldRay.P;
if (!rayShape->IntersectTest( &objectRay )) {
if (filmRay.d[X] != 0) continue;
}
numIntersect = rayShape->Intersect( &objectRay, iStackP, primData ); // calculate intersection
iStackP += numIntersect;
isectTotal += numIntersect;
}
// find best t for the pixel
if (iStackP > iStack) {
tbest = MAX_FLOAT;
for (int i = 0; i < isectTotal; i++) {
if (iStack[i].m_t < tbest) {
tbest = iStack[i].m_t;
bestISec = &iStack[i];
}
}
}
if (bestISec) {
// copy the relevant data
if (ray) {
ray->P = worldRay.P;
ray->d = worldRay.d;
}
if (isec) bestISec->copy( isec );
return bestISec->m_shape;
}
else {
return NULL;
}
}
int ISectTracer::ISectRayWithSphere( IAMatrix &object, IAPoint *isec,
int x, int y, int width, int height)
{
Ray filmRay, worldRay, objectRay;
IAMatrix filmToWorld = m_scene->camera()->filmToWorld();
filmRay.d[X] = ((double)(2*x)/(double)width) - 1;
filmRay.d[Y] = 1-((double)(2*y)/(double)height);
filmRay.d[Z] = -1; filmRay.d[W] = 1;
filmRay.P = IAPoint();
worldRay.d = filmToWorld * filmRay.d;
worldRay.P = filmToWorld * filmRay.P;
normalize( worldRay.d );
objectRay.d = object * worldRay.d;
objectRay.P = object * worldRay.P;
IAVector d = objectRay.d;
IAPoint P = objectRay.P;
double a = d[Z]*d[Z] + d[X]*d[X] + d[Y]*d[Y];
double b = 2*(P[X]*d[X] + P[Z]*d[Z] + P[Y]*d[Y]);
double c = P[X]*P[X] + P[Y]*P[Y] + P[Z]*P[Z] - 0.25;
double t, det = b*b-4*a*c;
if (det > 0) {
t = (-b+det)/a;
*isec = worldRay.P + worldRay.d * t;
return 1;
}
else return 0;
}
int CubeShape::Intersect( Ray *ray, Intersection *iStack, SNodePrimitive *data )
{
double t, det, u, v;
IAVector d = ray->d;
IAPoint P = ray->P;
Intersection *iStackP = iStack;
// test intersection with z up face
if (d[Z] != 0) {
t = -((P[Z]+0.5) / d[Z]);
u = P[X] + d[X]*t;
v = P[Y] + d[Y]*t;
if ((u > -0.5) && (u < 0.5) && (v > -0.5) && (v < 0.5)) {
iStackP->m_t = t;
iStackP->m_shape = data;
iStackP->m_faceID = FACE_ZPOS;
iStackP++;
}
}
// test intersection with z down face
if (d[Z] != 0) {
t = -((-P[Z]+0.5) / -d[Z]);
u = P[X] + d[X]*t;
v = P[Y] + d[Y]*t;
if ((u > -0.5) && (u < 0.5) && (v > -0.5) && (v < 0.5)) {
iStackP->m_t = t;
iStackP->m_shape = data;
iStackP->m_faceID = FACE_ZNEG;
iStackP++;
}
}
// test intersection with y up face
if (d[Y] != 0) {
t = -((P[Y]+0.5) / d[Y]);
u = P[X] + d[X]*t;
v = P[Z] + d[Z]*t;
if ((u > -0.5) && (u < 0.5) && (v > -0.5) && (v < 0.5)) {
iStackP->m_t = t;
iStackP->m_shape = data;
iStackP->m_faceID = FACE_YPOS;
iStackP++;
}
}
// test intersection with y down face
if (d[Y] != 0) {
t = -((-P[Y]+0.5) / -d[Y]);
u = P[X] + d[X]*t;
v = P[Z] + d[Z]*t;
if ((u > -0.5) && (u < 0.5) && (v > -0.5) && (v < 0.5)) {
iStackP->m_t = t;
iStackP->m_faceID = FACE_YNEG;
iStackP->m_shape = data;
iStackP++;
}
}
// test intersection with x up face
if (d[X] != 0) {
t = -((P[X]+0.5) / d[X]);
u = P[Z] + d[Z]*t;
v = P[Y] + d[Y]*t;
if ((u > -0.5) && (u < 0.5) && (v > -0.5) && (v < 0.5)) {
iStackP->m_t = t;
iStackP->m_faceID = FACE_XPOS;
iStackP->m_shape = data;
iStackP++;
}
}
// test intersection with x down face
if (d[X] != 0) {
t = -((-P[X]+0.5) / -d[X]);
u = P[Z] + d[Z]*t;
v = P[Y] + d[Y]*t;
if ((u > -0.5) && (u < 0.5) && (v > -0.5) && (v < 0.5)) {
iStackP->m_t = t;
iStackP->m_shape = data;
iStackP->m_faceID = FACE_XNEG;
iStackP++;
}
}
return (int)(iStackP-iStack);
}
*/

433
g2export.cpp Executable file
View File

@ -0,0 +1,433 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.h" // stuff needed for caller program, standar headers etc
#include "oddbits.h"
//
#include "matrix4.h"
#include "mdx_format.h"
#include "matcomp.h"
//
#include "g2export.h"
#define BASEDIRNAME "base"
extern char qdir[];//1024];
extern char gamedir[];//1024]; // q:\quake\baseef
extern LPCSTR Filename_QUAKEBASEONLY(LPCSTR psFullPathedName);
extern LPCSTR G2Exporter_Surface_GetName (int iSurfaceIndex);
extern LPCSTR G2Exporter_Surface_GetShaderName(int iSurfaceIndex);
extern int G2Exporter_Surface_GetNumVerts (int iSurfaceIndex, int iLOD);
extern int G2Exporter_Surface_GetNumTris (int iSurfaceIndex, int iLOD);
extern int G2Exporter_Surface_GetTriIndex (int iSurfaceIndex, int iTriangleIndex, int iTriVert, int iLOD);
extern vec3_t* G2Exporter_Surface_GetVertNormal(int iSurfaceIndex, int iVertIndex, int iLOD);
extern vec3_t* G2Exporter_Surface_GetVertCoords(int iSurfaceIndex, int iVertIndex, int iLOD);
extern vec2_t* G2Exporter_Surface_GetTexCoords (int iSurfaceIndex, int iVertIndex, int iLOD);
static LPCSTR Filename_StripQuakeBase(LPCSTR psFullPathedName)
{
static char sTemp[1024];
strcpy(sTemp,Filename_QUAKEBASEONLY(psFullPathedName));
int iQuakeLen = strlen(sTemp);
strcpy(sTemp,&psFullPathedName[iQuakeLen]);
return &sTemp[0];
}
static void ForwardSlash(char *psLocalName)
{
while (*psLocalName)
{
if (*psLocalName == '\\')
*psLocalName = '/';
psLocalName++;
}
}
// saves clogging the param stack...
//
int giNumLODs;
int giNumSurfaces;
int giNumTags;
static char *ExportGhoul2FromMD3_Main(FILE *fhGLM, /*FILE *fhGLA,*/ LPCSTR psFullPathedNameGLM)
{
char *psErrMess = NULL;
const int iMallocSize = 1024*1024*20; // 20MB should be enough for one model... :-)
byte *pbBuffer = (byte *) malloc(iMallocSize);
if (pbBuffer)
{
// filename used in both files...
//
char sLocalNameGLA[MAX_PATH];
strcpy( sLocalNameGLA,Filename_WithoutExt(Filename_StripQuakeBase(psFullPathedNameGLM)));
ForwardSlash(sLocalNameGLA);
// start writing...
//
byte *at = pbBuffer;
// write GLM Header...
//
mdxmHeader_t *pMDXMHeader = (mdxmHeader_t *) at;
at += sizeof(mdxmHeader_t);
{// GLM brace-match for skipping...
pMDXMHeader->ident = MDXM_IDENT;
pMDXMHeader->version = MDXM_VERSION;
strcpy( pMDXMHeader->name,Filename_StripQuakeBase(psFullPathedNameGLM));
ForwardSlash(pMDXMHeader->name);
strcpy( pMDXMHeader->animName,sDEFAULT_GLA_NAME);//sLocalNameGLA);
pMDXMHeader->animIndex = 0; // ingame use only
pMDXMHeader->numBones = 1; // ... and a fake one at that.
pMDXMHeader->numLODs = giNumLODs;
// pMDXMHeader->ofsLODs = ?????????????????????????????????????????????
pMDXMHeader->numSurfaces = giNumSurfaces + giNumTags;
// pMDXMHeader->ofsSurfHierarchy= ?????????????????????????????????????????????
// pMDXMHeader->ofsEnd = ?????????????????????????????????????????????
// for hierarchiy purposes, I'm going to just write out the first surface as the parent,
// then make every other surface a child of that one...
//
// G2 surfaces come from MD3 meshes first, then the MD3 tags (since G2 uses tag surfaces)
//
mdxmHierarchyOffsets_t *pHierarchyOffsets = (mdxmHierarchyOffsets_t *) at;
at += sizeof(mdxmHierarchyOffsets_t) * pMDXMHeader->numSurfaces;
pMDXMHeader->ofsSurfHierarchy = at - (byte *) pMDXMHeader;
for (int iSurfaceIndex = 0; iSurfaceIndex < pMDXMHeader->numSurfaces; iSurfaceIndex++)
{
// Note: bool bSurfaceIsTag == (iSurfaceIndex < giNumSurfaces)
//
mdxmSurfHierarchy_t *pSurfHierarchy = (mdxmSurfHierarchy_t *) at;
//
// store this offset...
//
pHierarchyOffsets->offsets[iSurfaceIndex] = (byte *)pSurfHierarchy - (byte *)pHierarchyOffsets;
// fill in surf hierarchy struct...
//
strcpy( pSurfHierarchy->name, G2Exporter_Surface_GetName(iSurfaceIndex));
pSurfHierarchy->flags = 0;
if ( iSurfaceIndex >= giNumSurfaces)
{
pSurfHierarchy->flags |= G2SURFACEFLAG_ISBOLT;
}
if (!strnicmp(&pSurfHierarchy->name[strlen(pSurfHierarchy->name)-4],"_off",4))
{
pSurfHierarchy->flags |= G2SURFACEFLAG_OFF;
}
strlwr(pSurfHierarchy->name);
strcpy( pSurfHierarchy->shader, G2Exporter_Surface_GetShaderName(iSurfaceIndex));
pSurfHierarchy->shaderIndex = 0; // ingame use only
pSurfHierarchy->parentIndex = iSurfaceIndex?0:-1;
pSurfHierarchy->numChildren = iSurfaceIndex?0:pMDXMHeader->numSurfaces-1;
if (!iSurfaceIndex)
{
for (int i=0; i<pSurfHierarchy->numChildren; i++)
{
pSurfHierarchy->childIndexes[i] = i+1;
}
}
int iThisHierarchySize = (int)( &((mdxmSurfHierarchy_t *)0)->childIndexes[ pSurfHierarchy->numChildren ] );
at += iThisHierarchySize;
}
// write out LODs...
//
pMDXMHeader->ofsLODs = at - (byte *) pMDXMHeader;
for (int iLODIndex = 0; iLODIndex < pMDXMHeader->numLODs; iLODIndex++)
{
mdxmLOD_t *pLOD = (mdxmLOD_t *) at;
at += sizeof(mdxmLOD_t);
mdxmLODSurfOffset_t *pLODSurfOffsets = (mdxmLODSurfOffset_t *) at;
at += sizeof(mdxmLODSurfOffset_t) * pMDXMHeader->numSurfaces;
for (int iSurfaceIndex = 0; iSurfaceIndex < pMDXMHeader->numSurfaces; iSurfaceIndex++)
{
mdxmSurface_t *pSurface = (mdxmSurface_t *) at;
at += sizeof(mdxmSurface_t);
//
// store this offset...
//
pLODSurfOffsets->offsets[iSurfaceIndex] = (byte *)pSurface - (byte *) pLODSurfOffsets;
//
// fill in this surface struct...
//
pSurface->ident = 0; // ingame-use only, defaulted to 0 here
pSurface->thisSurfaceIndex = iSurfaceIndex;
pSurface->ofsHeader = (byte *)pMDXMHeader - (byte *)pSurface; // offset back to main header
pSurface->numVerts = G2Exporter_Surface_GetNumVerts(iSurfaceIndex, iLODIndex);
pSurface->numTriangles = G2Exporter_Surface_GetNumTris(iSurfaceIndex, iLODIndex);
// pSurface->maxVertBoneWeights= 1; // easy, eh? :-)
//
// write out triangles...
//
pSurface->ofsTriangles = at - (byte *)pSurface;
for (int iTriangleIndex = 0; iTriangleIndex < pSurface->numTriangles; iTriangleIndex++)
{
mdxmTriangle_t *pTriangle = (mdxmTriangle_t *) at;
at += sizeof(mdxmTriangle_t);
for (int i=0; i<3; i++)
{
pTriangle->indexes[i] = G2Exporter_Surface_GetTriIndex(iSurfaceIndex,iTriangleIndex,i,iLODIndex);
}
}
//
// write out verts...(when exporting from MD3 these are all weighted to only 1 bone)
//
pSurface->ofsVerts = at - (byte *)pSurface;
mdxmVertex_t *pVerts = (mdxmVertex_t *) at;
mdxmVertexTexCoord_t *pVertTexCoords = (mdxmVertexTexCoord_t *) &pVerts[pSurface->numVerts];
at = (unsigned char *) &pVertTexCoords[pSurface->numVerts]; // skip over all this vert-writing...
for (int iVertIndex = 0; iVertIndex < pSurface->numVerts; iVertIndex++)
{
mdxmVertex_t *pVert = &pVerts[iVertIndex];
memcpy(pVert->normal,G2Exporter_Surface_GetVertNormal(iSurfaceIndex,iVertIndex,iLODIndex),sizeof(vec3_t));
memcpy(pVert->vertCoords,G2Exporter_Surface_GetVertCoords(iSurfaceIndex,iVertIndex,iLODIndex),sizeof(vec3_t));
// memcpy(pVert->texCoords,G2Exporter_Surface_GetTexCoords (iSurfaceIndex,iVertIndex,iLODIndex),sizeof(vec2_t));
memcpy(pVertTexCoords[iVertIndex].texCoords,G2Exporter_Surface_GetTexCoords (iSurfaceIndex,iVertIndex,iLODIndex),sizeof(vec2_t));
memset(pVert->BoneWeightings,0,sizeof(pVert->BoneWeightings));
int iNumWeights = 1;
pVert->uiNmWeightsAndBoneIndexes = (iNumWeights-1)<<30;
int iWeight = 1023; // highest weighting currently allowed (1.000f as 10 bit fixed point)
pVert->BoneWeightings[0] = iWeight&0xFF; // float->byte
// the 2-bit pairs at 20,22,24,26 are the top 2 bits of each weighting (leaving bits 28&29 free)...
//
pVert->uiNmWeightsAndBoneIndexes |= (iWeight>>8)<<((0*2)+20);
pVert->BoneWeightings[0] = 255; // 1.0f weighting
// int iWeightTest = G2_GetVertWeights( pVert );
// int iBoneIndex = G2_GetVertBoneIndex( pVert, 0 );
// float fBoneWeight = G2_GetVertBoneWeight( pVert, 0 );
}
// remaining surface struct fields...
//
pSurface->numBoneReferences = 1;
pSurface->ofsBoneReferences = at - (byte *) pSurface;
int *piBonesUsed = (int *) at;
at += pSurface->numBoneReferences * sizeof(int);
piBonesUsed[0] = 0; // the one and only bone ref
pSurface->ofsEnd = at - (byte *) pSurface;
}
pLOD->ofsEnd = at - (byte *) pLOD;
}
pMDXMHeader->ofsEnd = at - (byte *) pMDXMHeader;
}
/*
// now create GLA file...
//
mdxaHeader_t *pMDXAHeader = (mdxaHeader_t *) at;
at += sizeof(mdxaHeader_t);
{// for brace-skipping...
pMDXAHeader->ident = MDXA_IDENT;
pMDXAHeader->version = MDXA_VERSION;
strncpy(pMDXAHeader->name,sLocalNameGLA,sizeof(pMDXAHeader->name));
pMDXAHeader->name[sizeof(pMDXAHeader->name)-1]='\0';
pMDXAHeader->fScale = 1.0f;
pMDXAHeader->numFrames = 1; // inherently, when doing MD3 to G2 files
// pMDXAHeader->ofsFrames = ??????????????????
pMDXAHeader->numBones = 1; // inherently, when doing MD3 to G2 files
// pMDXAHeader->ofsCompBonePool= ??????????????????
// pMDXAHeader->ofsSkel = ??????????????????
// pMDXAHeader->ofsEnd = ??????????????????
// write out bone hierarchy...
//
mdxaSkelOffsets_t * pSkelOffsets = (mdxaSkelOffsets_t *) at;
at += (int)( &((mdxaSkelOffsets_t *)0)->offsets[ pMDXAHeader->numBones ] );
pMDXAHeader->ofsSkel = at - (byte *) pMDXAHeader;
for (int iSkelIndex = 0; iSkelIndex < pMDXAHeader->numBones; iSkelIndex++)
{
mdxaSkel_t *pSkel = (mdxaSkel_t *) at;
pSkelOffsets->offsets[iSkelIndex] = (byte *) pSkel - (byte *) pSkelOffsets;
// setup flags...
//
pSkel->flags = 0;
strcpy( pSkel->name, "Generated by MD3View"); // doesn't matter what this is called I believe.
pSkel->parent= -1; // index of bone that is parent to this one, -1 = NULL/root
Matrix4 BasePose;
BasePose.Identity();
BasePose.To3x4(pSkel->BasePoseMat.matrix);
Matrix4 BasePoseInverse;
BasePoseInverse.Inverse(BasePose);
BasePoseInverse.To3x4(pSkel->BasePoseMatInv.matrix);
pSkel->numChildren = 0; // inherently, when doing MD3 to G2 files
int iThisSkelSize = (int)( &((mdxaSkel_t *)0)->children[ pSkel->numChildren ] );
at += iThisSkelSize;
}
// write out frames...
//
pMDXAHeader->ofsFrames = at - (byte *) pMDXAHeader;
int iFrameSize = (int)( &((mdxaFrame_t *)0)->boneIndexes[ pMDXAHeader->numBones ] );
for (int i=0; i<pMDXAHeader->numFrames; i++)
{
mdxaFrame_t *pFrame = (mdxaFrame_t *) at;
at += iFrameSize; // variable sized struct
pFrame->boneIndexes[0] = 0; // inherently, when doing MD3 to G2 files
}
// now write out compressed bone pool...
//
pMDXAHeader->ofsCompBonePool = at - (byte *) pMDXAHeader;
for (int iCompBoneIndex = 0; iCompBoneIndex < 1; iCompBoneIndex++)
{
mdxaCompBone_t *pCompBone = (mdxaCompBone_t *) at;
at += sizeof(mdxaCompBone_t);
float matThis[3][4];
Matrix4 Bone;
Bone.Identity();
Bone.To3x4(matThis);
byte Comp[sizeof(mdxaCompBone_t)];
MC_Compress(matThis,Comp);
memcpy(pCompBone->Comp,Comp,sizeof(Comp));
}
// int iPoolBytesUsed = (CompressedBones.size()*MC_COMP_BYTES) + (iStats_NumBoneRefs*sizeof(int));
// printf("( Compressed bone bytes: %d, using pool = %d. Saving = %d bytes )\n",iOldBoneSize,iPoolBytesUsed, iOldBoneSize - iPoolBytesUsed);
// done...
//
pMDXAHeader->ofsEnd = at - (byte *) pMDXAHeader;
}
*/
// write 'em out to disk...
//
// int iGLMSize = fwrite(pMDXMHeader,1,(byte *)pMDXAHeader - (byte *)pMDXMHeader, fhGLM);
int iGLMSize = fwrite(pMDXMHeader,1,pMDXMHeader->ofsEnd, fhGLM);
assert(iGLMSize == pMDXMHeader->ofsEnd);
// int iGLASize = fwrite(pMDXAHeader,1,at - (byte *)pMDXAHeader, fhGLA);
// assert(iGLASize == pMDXAHeader->ofsEnd);
// and finally...
//
free(pbBuffer);
}
else
{
psErrMess = va("Error! Unable to allocate %d bytes for workspace!\n",iMallocSize);
}
return psErrMess;
}
// assumes 'psFullPathedFilename' is full-pathed filenam with ".glm" on the end,
// ppsFullPathedNameGLA is optional feedback param if you want to know what the GLA name was.
//
// return = NULL for no error, else string of error for caller to display...
//
char *ExportGhoul2FromMD3(LPCSTR psFullPathedFilename, int iNumLODs, int iNumSurfaces, int iNumTags,
LPCSTR *ppsFullPathedNameGLA /* = NULL */
)
{
char *psErrorMess = NULL;
giNumLODs = iNumLODs;
giNumSurfaces = iNumSurfaces;
giNumTags = iNumTags;
FILE *fhGLM = fopen(psFullPathedFilename,"wb");
if ( fhGLM)
{
static char sNameGLA[MAX_PATH];
// strcpy(sNameGLA, Filename_WithoutExt(psFullPathedFilename) );
// strcat(sNameGLA, ".gla");
strcpy(sNameGLA,sDEFAULT_GLA_NAME);
// FILE *fhGLA = fopen(sNameGLA,"wb");
// if (fhGLA)
{
if ( ppsFullPathedNameGLA)
{
*ppsFullPathedNameGLA = &sNameGLA[0];
}
psErrorMess = ExportGhoul2FromMD3_Main(fhGLM, /*fhGLA,*/ psFullPathedFilename);
// fclose(fhGLA);
}
// else
// {
// psErrorMess = va("Error: Unable to open file '%s'!\n");
// }
fclose(fhGLM);
}
else
{
psErrorMess = va("Error: Unable to open file '%s'!\n");
}
return psErrorMess;
}
/////////////////// eof ////////////////////

35
g2export.h Executable file
View File

@ -0,0 +1,35 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef G2EXPORT_H
#define G2EXPORT_H
char *ExportGhoul2FromMD3(LPCSTR psFullPathedFilename, int iNumLODs, int iNumSurfaces, int iNumTags,
LPCSTR *ppsFullPathedNameGLA = NULL
);
#endif // #ifndef G2EXPORT_H
//////////////// eof ///////////////

94
jpeg6/jcomapi.c Executable file
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;
}

41
jpeg6/jconfig.h Executable file
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 */

398
jpeg6/jdapimin.c Executable file
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;
}

275
jpeg6/jdapistd.c Executable file
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 */

205
jpeg6/jdatasrc.c Executable file
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 */
}

725
jpeg6/jdcoefct.c Executable file
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 */
}
}

367
jpeg6/jdcolor.c Executable file
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
jpeg6/jdct.h Executable 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

270
jpeg6/jddctmgr.c Executable file
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;
}
}

574
jpeg6/jdhuff.c Executable file
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;
}
}

202
jpeg6/jdhuff.h Executable file
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));

381
jpeg6/jdinput.c Executable file
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;
}

512
jpeg6/jdmainct.c Executable file
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));
}
}

1052
jpeg6/jdmarker.c Executable file

File diff suppressed because it is too large Load Diff

557
jpeg6/jdmaster.c Executable file
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);
}

290
jpeg6/jdpostct.c Executable file
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);
}
}
}

478
jpeg6/jdsample.c Executable file
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);
}
}
}

122
jpeg6/jdtrans.c Executable file
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;
}
}

240
jpeg6/jerror.c Executable file
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;
}

273
jpeg6/jerror.h Executable file
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 */

241
jpeg6/jidctflt.c Executable file
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 */

105
jpeg6/jinclude.h Executable file
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

1115
jpeg6/jmemmgr.c Executable file

File diff suppressed because it is too large Load Diff

123
jpeg6/jmemnobs.c Executable file
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 */
}

182
jpeg6/jmemsys.h Executable file
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));

352
jpeg6/jmorecfg.h Executable file
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 */

388
jpeg6/jpegint.h Executable file
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 */

1082
jpeg6/jpeglib.h Executable file

File diff suppressed because it is too large Load Diff

175
jpeg6/jutils.c Executable file
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
}

14
jpeg6/jversion.h Executable file
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"

231
jpeg_interface.cpp Executable file
View File

@ -0,0 +1,231 @@
#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;
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);
// ri.FS_ReadFile ( ( char * ) filename, (void **)&fbuffer);
if (!fbuffer)
return;
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 ////////////

55
jpeg_interface.h Executable file
View File

@ -0,0 +1,55 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TR_JPEG_INTERFACE_H
#define TR_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 TR_JPEG_INTERFACE_H
////////////////// eof //////////////////

242
matcomp.c Executable file
View File

@ -0,0 +1,242 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef MODVIEW
#include "stdafx.h"
#endif
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <memory.h> // for memcpy
//
#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;
}

58
matcomp.h Executable file
View File

@ -0,0 +1,58 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MATCOMP__
#define __MATCOMP__
#ifdef __cplusplus
extern "C"
{
#endif
#if (defined _MODVIEW || defined _CARCASS)
#include "special_defines.h"
#endif
#pragma optimize( "p", on ) // improve floating-point consistancy (makes release do bone-pooling as good as debug)
#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)
// pre-quat version
//#define MC_COMP_BYTES (((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*9)+7)/8)
//
// quat version, this is gay to do this but hard to change
#define MC_COMP_BYTES 14
void MC_Compress(const float mat[3][4],unsigned char * comp);
void MC_UnCompress(float mat[3][4],const unsigned char * comp);
#ifdef __cplusplus
}
#endif
#endif

1342
matrix4.cpp Executable file

File diff suppressed because it is too large Load Diff

101
matrix4.h Executable file
View File

@ -0,0 +1,101 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(MATRIX4_INC)
#define MATRIX4_INC
#include "vect3.h"
#include <math.h>
#include <memory.h>
#pragma warning( disable : 4244)
#pragma optimize( "p", on ) // improve floating-point consistancy (makes release do bone-pooling as good as debug)
extern const float Pi;
extern const float Half_Pi;
#define MATFLAG_IDENTITY (1)
class Matrix4
{
float m[4][4];
int flags;
public:
Matrix4() {flags=0;}
Matrix4(const Matrix4 &o);
float* operator[](int i) {return m[i];flags=0;}
const float* operator[](int i) const {return m[i];}
void SetElem(int r,int c,float v) {m[r][c]=v;flags=0;}
const float &Elem(int r,int c) const {return m[r][c];}
void SetFromMem(const float *mem) {memcpy(m,mem,sizeof(float)*16);CalcFlags();}
void GetFromMem(float *mem) const {memcpy(mem,m,sizeof(float)*16);}
void Identity();
void Zero();
bool IsRotationIdentity(void) const;
bool IsRotationIdentityMoreTolerance(void) const;
int CalcFlags();
int GetFlags() const {return flags;}
bool IntegrityCheck() const;
void Translate(const float tx,const float ty,const float tz);
void Translate(const Vect3 &t);
void Rotate(int axis,const float theta);
void Rotate(const float rx,const float ry,const float rz);
void Rotate(const Vect3 v);
void Scale(const float sx,const float sy,const float sz);
void Scale(const float sx);
void Concat(const Matrix4 &m1,const Matrix4 &m2);
void Interp(const Matrix4 &m1,float s1,const Matrix4 &m2,float s2);
void Interp(const Matrix4 &m1,const Matrix4 &m2,float s1);
void XFormPoint(Vect3 &dest,const Vect3 &src) const;
float HXFormPoint(Vect3 &dest,const Vect3 &src) const;
void HXFormPointND(float *dest,const float *src) const;
void XFormVect(Vect3 &dest,const Vect3 &src) const;
void XFormVectTranspose(Vect3 &dest,const Vect3 &src) const;
void SetRow(int i,const Vect3 &t);
void SetColumn(int i,const Vect3 &t);
void SetRow(int i);
void SetColumn(int i);
void SetFromDouble(double *d);
void MultiplyColumn(int i,float f);
float GetColumnLen(int i);
void Inverse(const Matrix4 &old);
void OrthoNormalInverse(const Matrix4 &old);
void FindFromPoints(const Vect3 base1[4],const Vect3 base2[4]);
void MakeEquiscalar();
float Det();
float MaxAbsElement();
void GetRow(int r,Vect3 &v) const {v.x()=m[r][0];v.y()=m[r][1];v.z()=m[r][2];}
void GetColumn(int r,Vect3 &v) const {v.x()=m[0][r];v.y()=m[1][r];v.z()=m[2][r];}
void Transpose();
bool operator== (const Matrix4& t) const;
void From3x4(const float mat[3][4]);
void To3x4(float mat[3][4]) const;
void ClampPrecision(float fNumDecimals);
};
int GetTextureSystem(
const Vect3 &p0,const Vect3 &uv0, //vertex 0
const Vect3 &p1,const Vect3 &uv1, //vertex 1
const Vect3 &p2,const Vect3 &uv2, //vertex 2
const Vect3 &n, // normal vector for triangle
Vect3 &M, // returned gradient wrt u
Vect3 &N, // returned gradient wrt v
Vect3 &P); // returned location in world space where u=v=0
#endif

2204
md3IO.cpp Executable file

File diff suppressed because it is too large Load Diff

1878
md3gl.cpp Executable file

File diff suppressed because it is too large Load Diff

211
md3gl.h Executable file
View File

@ -0,0 +1,211 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MD3_GL_H_
#define _MD3_GL_H_
#include "mdr.h"
typedef struct
{
unsigned char *Data; // actual texture bitmap
unsigned int Width, Height; // size of TextureData
GLenum _Type; // type of texture ie. (not actually used)
GLuint Bind; // id the texture is bound to
char *File; // allocated string storing path name
int numUsed;
} TextureGL;
typedef struct
{
GLuint *textureBinds; // array of texture binds, one for each mesh
int topTextureBind;
Vec3 *iterVerts; // arrays of vertices for interpolation, one for each mesh
NodeDictionary textureRes; // map of texture names to TextureGL data, stores texture resources
} MD3GL;
typedef struct
{
Vec3 *pVerts;
short *pNormalIndexes;
} FMeshFrame;
/*
run time model data structure
*/
struct gl_mesh
{
char sName[64];
unsigned int iNumVertices; // number of vertices in model
unsigned int iNumTriangles; // number of triangles in gl_model
unsigned int iNumMeshFrames; // same as global frame but convenient
TriVec *triangles; // array of triangle vertex indices of size iNumTriangles
TexVec *textureCoord; // array of float s/t texture coordinates of size iNumVertices
FMeshFrame *meshFrames; // 2d array of size of [iNumFrames][vertexNum] stores mesh frame vertices
Vec3 *iterMesh; // buffer mesh frame used to store interpolated mesh of size vertexNum
unsigned int iNumSkins; // number of skins this model has
GLuint *bindings; // array of texture bindings of size skinNum;
char sTextureName[MAX_QPATH]; // only bother storing first one
};
struct gl_model;
struct gl_model
{
// common to any model format:
//
modelType_t modelType;
unsigned int iNumFrames; // number of frames in gl_model
unsigned int iNumTags; // number of tags in gl_model
unsigned int currentFrame; // current frame being displayed
// tag info is duplicated here, even for MDR types, so rest of code works ok
TagFrame *tags; // 2d array of tags size [iNumFrames][iNumTags]
gl_model **linkedModels; // array of links of size iNumTags, each link corresponds to a tag
gl_model *parent;
// some stuff for dealing with MD3 LODs (which are actually seperate models)...
//
gl_model *pModel_LOD0; // for the LOD0 (default) model, this will be NULL, for other LODs, this will point at original LOD0 model)
gl_model *pModel_LOD1;
gl_model *pModel_LOD2;
// other stuff...
//
unsigned int iNumMeshes; // number of meshes in whole model
NodePosition modelListPosition; // link to its mdview.modelList
float CTM_matrix[16]; // object transformation matrix for manipulating mesh
gl_mesh *pMeshes; // array of meshes of size meshNum
md3BoundFrame_t *pMD3BoundFrames; // array of boundary frames size [iNumFrames]
// this requires more work once the script parser is done
bool isBlended;
GLenum blendParam1, blendParam2;
int iRenderedTris;
int iRenderedVerts;
char sHeadSkinName[32]; // should be enough
char sMD3BaseName[1024];
char sMDXFullPathname[1024];
model_t Q3ModelStuff;
};
#define NEAR_GL_PLANE 0.1
#define FAR_GL_PLANE 512
void initialize_glstate();
bool loadmd3gl( MD3GL &data );
void rendermd3gl( MD3GL &mdl );
void freemd3gl( MD3GL &data );
void renderFrame();
bool bIsWireFrame(void);
bool bIsTextured(void);
void oglStateFlatTextured();
void oglStateShadedTexturedAndWireFrame();
void oglStateShadedTextured();
void oglStateShadedFlat();
void oglStateWireframe();
/*
damn smart and efficient texture loader,
first searches for an existing teature name is parent directories
then checks if texture has already been loaded,
otherwise it loads it up, enters in textureRes manager and returns the new binding
*/
extern bool gbIgnoreTextureLoad;
GLuint loadTexture( LPCSTR texturepath );
/*
frees a texture resource, called whenever a mesh is being freed. a texture is freed only if nothing is using it anymore
*/
void freeTexture( GLuint bind );
/*
deletes the entire texture resource manager with all its textures, usually called at the end of the program
or when a whole new model is loaded
*/
void freeTextureRes();
/*
reloads all texture resources from disk
*/
void refreshTextureRes();
/*
chooses the specific filter to be applied based on current mode
*/
void setTextureToFilter();
/*
sets texture parameters to the current texMode
*/
void setTextureFilter();
/*
renders the current frame
*/
void draw_view();
void draw_viewSkeleton();
typedef unsigned int glIndex_t;
typedef struct shaderCommands_s
{
glIndex_t indexes[SHADER_MAX_INDEXES];
vec4_t xyz[SHADER_MAX_VERTEXES];
vec4_t normal[SHADER_MAX_VERTEXES];
vec2_t texCoords[SHADER_MAX_VERTEXES][2];
/* color4ub_t vertexColors[SHADER_MAX_VERTEXES];
int vertexDlightBits[SHADER_MAX_VERTEXES];
stageVars_t svars;
color4ub_t constantColor255[SHADER_MAX_VERTEXES];
shader_t *shader;
int fogNum;
int dlightBits; // or together of all vertexDlightBits
*/
int numIndexes;
int numVertexes;
/*
// info extracted from current shader
int numPasses;
void (*currentStageIteratorFunc)( void );
shaderStage_t **xstages;
*/
} shaderCommands_t;
LPCSTR SkinName_FromPathedModelName(LPCSTR psModelPathName);
bool Model_ApplySkin(gl_model* model, LPCSTR psSkinFilename);
bool ApplyNewSkin(LPCSTR psSkinFullPathName);
gl_model* R_FindModel( gl_model* model, LPCSTR psModelBaseName);
shaderCommands_t* Freeze_Surface( md4Surface_t *surface, int iFrame );
#endif

985
md3view.cpp Executable file
View File

@ -0,0 +1,985 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.h"
#include "ndictionary.h"
#include "md3gl.h"
#include "md3view.h"
#include "animation.h"
#include "text.h"
#include "oddbits.h"
MDViewState mdview;
void draw_stats();
/*
renders the view which so far is just a model frame
*/
void render_mdview()
{
//draw_view();
draw_viewSkeleton();
draw_stats();
}
void reset_viewpos(void)
{
mdview.xPos = mdview.yPos = 0.0f;
mdview.zPos = -2.f;
mdview.rotAngleX = mdview.rotAngleY = 0;
mdview.rotAngleZ = -90.0f;
}
/*
initializes the viewer global state data
*/
void init_mdview(const char* lpcommandline)
{
mdview.dFOV = 90.0f;
mdview.iLODLevel = 0;
mdview.iSkinNumber = 0;
mdview.bAxisView = false;
reset_viewpos();
mdview.animSpeed = 0.1; // so 1/this = 10 = 10FPS
mdview.timeStamp1 = getDoubleTime();
mdview.texMode = TEX_FILTERED;
mdview.faceSide = GL_CCW;
mdview.animate = false;
mdview.interpolate = true;
mdview.bUseAlpha = false; // default this to OFF since artists keep making 32 bit textures with no alpha, then complain about pieces missing!!!!
mdview.bBBox = false;
mdview._R = mdview._G = mdview._B = 256/5; // dark grey
mdview.bAnimCFGLoaded = false;
mdview.bAnimIsMultiPlayerFormat = false;
// allocate texture resource manager
mdview.textureRes = new NodeDictionaryInfo( new StrKeyComparatorInfo() );
mdview.topTextureBind = 0;
// allocate model list
mdview.modelList = new NodeSequenceInfo();
// strcpy( mdview.basepath, "/");
if ( lpcommandline != NULL && lpcommandline[0] != '\0' ) { //got an initial dir
char szDirName[256]={0};
strcpy (szDirName, lpcommandline );
char *p = strrchr(szDirName,'\\'); //back up off the filename.
if (p) {
*p=0;
}
SetCurrentDirectory( szDirName); //this will make future open dialogs in the same dir as the command line file
strcpy( mdview.basepath, szDirName);
} else {
#if 1
strcpy( mdview.basepath, "w:\\game\\base\\models\\"); // this is just to default the 1st use of OpenFileDialog, and doesn't affect anything else once the app gets going
SetCurrentDirectory( mdview.basepath );
#else
char szDirName[256]={0};
GetModuleFileName(NULL, szDirName, 256);
char *p = strrchr(szDirName,'\\'); //back up off the filename.
if (p) {
*p=0;
}
SetCurrentDirectory( szDirName );
strcpy( mdview.basepath, szDirName);
#endif
}
}
void delete_gl_model( gl_model *model );
bool loadmdx(gl_model& newModel, char* filename);
/* ------------------------------------------------ loading code -------------------------------------------------- */
/*
loads up md3 data
*/
int giTagMenuSubtractValue_Torso;
int giTagMenuSubtractValue_Head;
int giTagMenuSubtractValue_Weapon; // this shit gets worse by the minute...
int giTagMenuSubtractValue_Barrel;
int giTagMenuSubtractValue_Barrel2;
int giTagMenuSubtractValue_Barrel3;
int giTagMenuSubtractValue_Barrel4;
gl_model* pLastLoadedModel;
// if psLOD0Filename != NULL, then we're loading an MD3 LOD model, and psLOD0Filename is a pointer to original name
//
bool loadmdl_original( char *filename, LPCSTR psLOD0Filename, gl_model* pLOD1, gl_model* pLOD2 )
{
gl_model* model = new gl_model; memset( model, 0, sizeof(gl_model) );
if (pLOD1)
{
model->pModel_LOD1 = pLOD1;
pLOD1->pModel_LOD0 = model;
}
if (pLOD2)
{
model->pModel_LOD2 = pLOD2;
pLOD2->pModel_LOD0 = model;
}
// if there's a default skin for this model, don't try and load the internal shaders, this is just so
// we don't get bugged by loads of file-missing errors if the model is only designed to use skin files...
//
bool bDefaultSkinExists = file_exists(SkinName_FromPathedModelName(filename));
if (bDefaultSkinExists)
{
gbIgnoreTextureLoad = true;
}
if (!loadmdx( *model, filename ))
{
gbIgnoreTextureLoad = false;
delete_gl_model( model );model = NULL;
return false;
}
gbIgnoreTextureLoad = false;
pLastLoadedModel = model;
strcpy( model->sHeadSkinName,"default");
strcpy( model->sMDXFullPathname, filename);
strcpy( model->sMD3BaseName,Filename_WithoutPath(
// Filename_WithoutExt(
filename
// )
)
);
if (psLOD0Filename)
return true; // don't bother with the rest of this stuff now...
giTagMenuSubtractValue_Torso =
giTagMenuSubtractValue_Head =
giTagMenuSubtractValue_Weapon =
giTagMenuSubtractValue_Barrel =
giTagMenuSubtractValue_Barrel2=
giTagMenuSubtractValue_Barrel3=
giTagMenuSubtractValue_Barrel4= -1;
Model_ApplySkin(model, SkinName_FromPathedModelName(model->sMDXFullPathname));
model->modelListPosition = mdview.modelList->insertLast( model );
mdview.baseModel = (gl_model *)mdview.modelList->first()->element();
tagMenu_seperatorAppend( filename );
for (unsigned int i=0 ; i<model->iNumTags ; i++)
{
tagMenu_append( model->tags[0][i].Name, (GLMODEL_DBLPTR)&model->linkedModels[i] );
if (!stricmp(model->tags[0][i].Name,"tag_torso"))
{
giTagMenuSubtractValue_Torso = i;
}
else
if (!stricmp(model->tags[0][i].Name,"tag_head"))
{
giTagMenuSubtractValue_Head = i;
}
else
if (!stricmp(model->tags[0][i].Name,"tag_weapon"))
{
giTagMenuSubtractValue_Weapon = i;
}
else
if (!stricmp(model->tags[0][i].Name,"tag_barrel"))
{
giTagMenuSubtractValue_Barrel = i;
}
else
if (!stricmp(model->tags[0][i].Name,"tag_barrel2"))
{
giTagMenuSubtractValue_Barrel2 = i;
}
else
if (!stricmp(model->tags[0][i].Name,"tag_barrel3"))
{
giTagMenuSubtractValue_Barrel3 = i;
}
else
if (!stricmp(model->tags[0][i].Name,"tag_barrel4"))
{
giTagMenuSubtractValue_Barrel4 = i;
}
}
// arrrghhh!!!!...
//
giTagMenuSubtractValue_Torso = model->iNumTags - giTagMenuSubtractValue_Torso;
giTagMenuSubtractValue_Head = model->iNumTags - giTagMenuSubtractValue_Head;
giTagMenuSubtractValue_Weapon = (giTagMenuSubtractValue_Weapon ==-1)?-1:model->iNumTags - giTagMenuSubtractValue_Weapon;
giTagMenuSubtractValue_Barrel = (giTagMenuSubtractValue_Barrel ==-1)?-1:model->iNumTags - giTagMenuSubtractValue_Barrel;
giTagMenuSubtractValue_Barrel2 = (giTagMenuSubtractValue_Barrel2==-1)?-1:model->iNumTags - giTagMenuSubtractValue_Barrel2;
giTagMenuSubtractValue_Barrel3 = (giTagMenuSubtractValue_Barrel3==-1)?-1:model->iNumTags - giTagMenuSubtractValue_Barrel3;
giTagMenuSubtractValue_Barrel4 = (giTagMenuSubtractValue_Barrel4==-1)?-1:model->iNumTags - giTagMenuSubtractValue_Barrel4;
//
// this value is now the value (if NZ) to sub from the menu count (then add ID_TAG_START) to reach "tag_torso"ID of the menu item
//
SetFaceSkin(0); // safety to always do this
return true;
}
// this now auto-loads LOD models for MD3s...
//
bool loadmdl( char *filename )
{
gl_model* pModel_LOD1 = NULL;
gl_model* pModel_LOD2 = NULL;
// new stuff, if it's an MD3, try loading in LOD versions of it as well, but do them first, so that
// all the goofy shit to do with tagmenu stuff is still left in valid state...
//
LPCSTR psMD3EXT = strstr(String_ToLower(filename),".md3");
if (psMD3EXT)
{
char sNewFilename[MAX_PATH];
strcpy(sNewFilename,Filename_WithoutExt(filename));
strcat(sNewFilename,"_1.md3");
if (loadmdl_original(sNewFilename, filename, NULL, NULL))
pModel_LOD1 = pLastLoadedModel;
strcpy(sNewFilename,Filename_WithoutExt(filename));
strcat(sNewFilename,"_2.md3");
if (loadmdl_original(sNewFilename, filename, NULL, NULL))
pModel_LOD2 = pLastLoadedModel;
}
// finally, load the model we were originally asking for...
//
return loadmdl_original(filename, NULL, pModel_LOD1, pModel_LOD2);
}
/*
loads a model into the slot pointed to by dblptr
*/
void loadmdl_totag( char *fullName, GLMODEL_DBLPTR dblptr )
{
gl_model **m_dblptr = (gl_model **)dblptr;
gl_model *newmodel;
NodePosition pos;
if (loadmdl( fullName )) {
pos = mdview.modelList->last();
newmodel = (gl_model *)pos->element();
*m_dblptr = newmodel;
}
}
/*
loads a new skin
*/
void importNewSkin( char *fullName )
{
/*
GLuint newTexBind = loadTexture( fullName );
NodePosition pos;
gl_model *model;
gl_mesh *mesh;
int iNumMeshes,i;
unsigned int j;
for (pos=mdview.modelList->first() ; pos!=NULL ; pos=mdview.modelList->after(pos)) {
model = (gl_model *)pos->element();
iNumMeshes = model->iNumMeshes;
for (i=0 ; i<iNumMeshes ; i++) {
mesh = &model->meshes[i];
for (j=0 ; j<mesh->skinNum ; j++) {
mesh->bindings[j] = newTexBind;
}
}
}
*/
ApplyNewSkin(fullName);
}
bool ParseSequenceLockFile(LPCSTR psFilename)
{
#define UL_BAD 0
#define UL_UPPER 1
#define UL_LOWER 2
int iUpperOrLower = UL_BAD;
FILE *fHandle = fopen(psFilename,"rt");
if (fHandle)
{
// file is text file,
// first line is "upper" or "lower" (ignore case), then sequence lock names till empty line or EOF
static char sLineBuffer[2048];
int iMembers = 0;
MultiSequenceLock_t MultiSequenceLock;
MultiSequenceLock.clear();
while (1)
{
ZEROMEM(sLineBuffer);
if (!fgets(sLineBuffer,sizeof(sLineBuffer),fHandle))
{
if (ferror(fHandle))
{
ErrorBox(va("Error while reading \"%s\"!",psFilename));
iUpperOrLower = UL_BAD;
}
break; // whether error or EOF
}
// zap any comments...
//
char *p = strstr(sLineBuffer,"//");
if (p)
*p=0;
strcpy(sLineBuffer,String_ToUpper(String_LoseWhitespace(sLineBuffer)));
if (strlen(sLineBuffer))
{
// analyse this line...
//
if (!iMembers)
{
if (strnicmp(sLineBuffer,"upper",5)==0)
{
iUpperOrLower = UL_UPPER;
}
else
if (strnicmp(sLineBuffer,"lower",5)==0)
{
iUpperOrLower = UL_LOWER;
}
else
{
ErrorBox("First line of file must be \"upper\" or \"lower\"!");
iUpperOrLower = UL_BAD;
break;
}
}
else
{
// is this string a valid sequence for upper/lower?...
//
int iCount = (iUpperOrLower == UL_UPPER)?Animation_GetNumUpperSequences():Animation_GetNumLowerSequences();
int iScanIndex;
for (iScanIndex=0; iScanIndex<iCount; iScanIndex++)
{
Sequence_t* pSeq = (iUpperOrLower == UL_UPPER)?Animation_GetUpperSequence(iScanIndex):Animation_GetLowerSequence(iScanIndex);
if (strcmp(pSeq->sName.c_str(),sLineBuffer)==0)
{
// found this line, it's valid, so keep it...
//
MultiSequenceLock.push_back(iScanIndex);
break;
}
}
if (iScanIndex==iCount)
{
ErrorBox(va("Couldn't find specified sequence \"%s\" for model \"%s\"",sLineBuffer,(iUpperOrLower == UL_UPPER)?"UPPER":"LOWER"));
iUpperOrLower = UL_BAD;
break;
}
}
iMembers++;
}
}
if (iUpperOrLower != UL_BAD // avoid giving an error because of an existing error
&& iMembers == 1) // ie seq file only contains "upper" or "lower"
{
ErrorBox("No enum entries found in file");
iUpperOrLower = UL_BAD;
}
switch (iUpperOrLower)
{
case UL_BAD:
// do nothing
//
break;
case UL_UPPER:
MultiSequenceLock_Upper.clear();
MultiSequenceLock_Upper = MultiSequenceLock;
iAnimLockNumber_Upper = -1;
break;
case UL_LOWER:
MultiSequenceLock_Lower.clear();
MultiSequenceLock_Lower = MultiSequenceLock;
iAnimLockNumber_Lower = -1;
break;
default: // I must have forgotten some new type
assert(0);
break;
}
fclose(fHandle);
}
else
{
ErrorBox(va("Error opening file \"%s\"",psFilename));
}
return (iUpperOrLower != UL_BAD);
}
/* ------------------------------------------ delete code ------------------------------------------------------- */
/*
frees all mdviewdata, and effectively resets the data state back to init
*/
void free_mdviewdata()
{
NodePosition pos;
gl_model *model;
/*
for(pos = mdview.modelList->first() ; pos!=NULL ; pos=next) {
model = (gl_model *)pos->element();
// takes care of removing model from the list and everything, so assume pos is invalid
delete_gl_model( model );
// get next after cuz the list might have been changed by delete_gl_model
next = mdview.modelList->after(pos);
}
*/
if (!mdview.modelList->isEmpty()) {
do {
pos = mdview.modelList->first();
model = (gl_model *)pos->element();
delete_gl_model( model ); // this removes its own position from the list
} while (mdview.modelList->first()!=NULL);
}
// if there is anything else left in texture res remove,
// though deleting all gl_models in list should make it empty
freeTextureRes();
ClearAnimationCFG();
}
/*
frees a model that has been loaded before by loadmdl_totag into the modelptr slot
*/
void freemdl_fromtag( GLMODEL_DBLPTR modelptr )
{
gl_model **m_dblptr = (gl_model **)modelptr;
gl_model *model = *m_dblptr;
if (!model) return;
delete_gl_model( model );
*m_dblptr = NULL;
}
/*
frees data as for shutdown, call this only as the last thing before exiting or bad thigns will happen
*/
void shutdown_mdviewdata()
{
free_mdviewdata();
delete mdview.modelList; mdview.modelList = NULL;
delete mdview.textureRes; mdview.textureRes = NULL;
}
int iTextX;
int iTextY;
int giTotVerts;
int giTotTris;
int giModelsStatted;
void stat_gl_model( gl_model *__model, char *psAttachedVia )
{
#define ARB_NAME_PADDING 26
#define ARB_LOD_PADDING 9
#define ARB_ATTACHNAME_PADDING 24
#define ARB_VERTINFO_PADDING 15
gl_model* model = __model;
if (model)
{
giModelsStatted++;
if (model->modelType == MODTYPE_MD3)
{
switch (mdview.iLODLevel)
{
case 0: break;
case 1: model = model->pModel_LOD1; break;
case 2: model = model->pModel_LOD2; break;
}
if (!model)
{
Text_DisplayFlat( va("%s", String_EnsureMinLength("( LOD model missing )",ARB_NAME_PADDING)),
iTextX, iTextY,
0, 255,0, // RGB
false
);
iTextY += TEXT_DEPTH;
return;
}
}
}
int iNextX = 0;
if (model)
{
iNextX =
Text_DisplayFlat( va("%s Frame %4d/%4d",
String_EnsureMinLength(va("\"%s\"",model->sMD3BaseName),ARB_NAME_PADDING),
model->currentFrame, model->iNumFrames),
iTextX, iTextY,
0, 255,0, // RGB
false
);
}
else
{
iTextY += TEXT_DEPTH; // seperate totals a bit
iNextX =
// va("%s Frame 1234/1234"
Text_DisplayFlat( va("%s ", String_EnsureMinLength("( totals )",ARB_NAME_PADDING)),
iTextX, iTextY,
0, 255,0, // RGB
false
);
}
if (model)
{
// LODs info...
//
if (model->modelType == MODTYPE_MDR)
{
md4LOD_t *pLOD = (md4LOD_t *) ((byte *)model->Q3ModelStuff.md4 + model->Q3ModelStuff.md4->ofsLODs);
int iWhichLod = mdview.iLODLevel;
if (iWhichLod >= model->Q3ModelStuff.md4->numLODs)
iWhichLod = model->Q3ModelStuff.md4->numLODs-1;
iNextX = Text_DisplayFlat( String_EnsureMinLength(va("(LOD %1d/%1d)",iWhichLod+1,model->Q3ModelStuff.md4->numLODs),ARB_LOD_PADDING),
iNextX+(2*TEXT_WIDTH), iTextY,
255/2,255,255/2, // RGB
false
);
}
else
{
iNextX = Text_DisplayFlat( String_EnsureMinLength(va("(LOD %1d)",mdview.iLODLevel+1),ARB_LOD_PADDING),
iNextX+(2*TEXT_WIDTH), iTextY,
255/2,255,255/2, // RGB
false
);
}
}
else
{
iNextX = Text_DisplayFlat( String_EnsureMinLength("",ARB_LOD_PADDING),
iNextX+(2*TEXT_WIDTH), iTextY,
255/2,255,255/2, // RGB
false
);
}
if (model)
{
// Verts/tris info...
//
iNextX =
Text_DisplayFlat( String_EnsureMinLength(
va("(V:%4d T:%4d)",model->iRenderedVerts,model->iRenderedTris),
ARB_VERTINFO_PADDING
),
iNextX+(2*TEXT_WIDTH), iTextY,
255, 255/2, 255/2, // RGB (pink)
false
);
giTotVerts+= model->iRenderedVerts;
giTotTris += model->iRenderedTris;
}
else
{
// Verts/tris info...
//
iNextX =
Text_DisplayFlat( String_EnsureMinLength(
va("(V:%4d T:%4d)",giTotVerts,giTotTris),
ARB_VERTINFO_PADDING
),
iNextX+(2*TEXT_WIDTH), iTextY,
255, 255/2, 255/2, // RGB (pink)
false
);
}
if (model)
{
// attached-via info...
//
iNextX =
Text_DisplayFlat( String_EnsureMinLength(
va("%s", psAttachedVia?va("(attached: \"%s\")",psAttachedVia):""),
ARB_ATTACHNAME_PADDING
),
iNextX+(2*TEXT_WIDTH), iTextY,
0, 255/2,0, // RGB
false
);
// print either the locked local frame number in red (if anim locking is on), or just the anim sequence name
// if there's one corresponding to this...
//
Sequence_t* pSeq = NULL;
bool bIsUpper = false;
if ((model == pModel_Upper || model->pModel_LOD0 == pModel_Upper ) && iAnimLockNumber_Upper)
{
pSeq = Animation_GetUpperSequence( iAnimLockNumber_Upper-1 );
bIsUpper = true;
}
if ((model == pModel_Lower || model->pModel_LOD0 == pModel_Lower ) && iAnimLockNumber_Lower)
{
pSeq = Animation_GetLowerSequence( iAnimLockNumber_Lower-1 );
bIsUpper = false;
}
if (pSeq)
{
bool bWasMulti = false;
if (pSeq->bMultiSeq)
{
pSeq = GetMultiLockedSequenceFromFrame(model->currentFrame, bIsUpper );
bWasMulti = true;
}
if (pSeq)
{
iNextX = Text_DisplayFlat( va("%d/%d",model->currentFrame-pSeq->iTargetFrame,pSeq->iFrameCount),
iNextX+(2*TEXT_WIDTH), iTextY,
255, // R
0, // G
bWasMulti?255:0, // B // multi displays as purple
false
);
}
}
//else
if (!pSeq)
{
if ((model == pModel_Upper || model->pModel_LOD0 == pModel_Upper ) && !iAnimLockNumber_Upper)
{
pSeq = Animation_FromUpperFrame( model->currentFrame );
}
if ((model == pModel_Lower || model->pModel_LOD0 == pModel_Lower ) && !iAnimLockNumber_Lower)
{
pSeq = Animation_FromLowerFrame( model->currentFrame );
}
if (pSeq)
{
iNextX = Text_DisplayFlat( va("%s",pSeq->sName.c_str()), iNextX + (2*TEXT_WIDTH), iTextY, 0,200,200, true); // dim cyan
}
}
}
iTextY += TEXT_DEPTH;
}
void stat_skeleton( gl_model *model, char *psAttachedVia )
{
if (psAttachedVia == NULL)
{
// first time, so zap totals...
//
giTotVerts = 0;
giTotTris = 0;
giModelsStatted = 0;
}
stat_gl_model( model, psAttachedVia );
unsigned int sf=model->currentFrame, ef=model->currentFrame+1;
// draw all the attached child models
for (UINT j=0; j<model->iNumTags ; j++)
{
gl_model *child = model->linkedModels[j];
if (child)
{
Tag *tag = &model->tags[sf][j];
stat_skeleton( child, tag->Name );
}
}
if (psAttachedVia == NULL)
{
// done, print totals...
//
if (giModelsStatted>1) // no point if only 1 printed
stat_gl_model( NULL, NULL );
}
}
void draw_stats()
{
if (mdview.baseModel)
{
iTextX = 2*TEXT_WIDTH; // arb start pos 2 in from both edges
iTextY = 4*TEXT_DEPTH; // ... or 4... :-)
// // Displays text at a 2d screen coord. 0,0 is top left corner, add TEXT_DEPTH per Y to go down a line
//
// Text_DisplayFlat("testing testing HELLO!!", 100,100, 0, 255,0, true);
//
// Vec3 v={0,0,0};
// Text_Display("testing testing HELLO!!", v, 255,0,0);
//
//
gl_model *model = mdview.baseModel;
stat_skeleton( model, NULL );
// anim locks on the whole model?, if so display 'em...
//
char sString[1024];
for (int i=0; i<2; i++)
{
// display anim locks at bottom of screen...
//
Sequence_t* pSeq=NULL;
bool bIsUpper = false;
if (i==0 && iAnimLockNumber_Upper )
{
pSeq = Animation_GetUpperSequence( iAnimLockNumber_Upper-1 );
bIsUpper = true;
}
if (i==1 && iAnimLockNumber_Lower )
{
pSeq = Animation_GetLowerSequence( iAnimLockNumber_Lower-1 );
bIsUpper = false;
}
if (pSeq)
{
int iYpos = g_iScreenHeight-((!i?4:3)*TEXT_DEPTH);
// cheat, do this next bit here just to get the X coord, then overwrite later
sprintf(sString,"%s anim lock: %s Frames: %4d...%4d%s",!i?"Upper":"Lower",String_EnsureMinLength(pSeq->sName.c_str(),iAnimLockLongestString),pSeq->iTargetFrame,(pSeq->iTargetFrame+pSeq->iFrameCount)-1,String_EnsureMinLength((pSeq->iLoopFrame==-1)?"":va(" loop: %3d(%3d)",pSeq->iLoopFrame,pSeq->iTargetFrame+pSeq->iLoopFrame),25));
int iXpos = (g_iScreenWidth/2)-( (strlen(sString)/2)*TEXT_WIDTH);
if (pSeq->bMultiSeq)
{
Sequence_t *pCurrentMultiSeq = GetMultiLockedSequenceFromFrame(bIsUpper?pModel_Upper->currentFrame:pModel_Lower->currentFrame, bIsUpper );
int iStrlenAtCurrentSeqPoint = 0;
sprintf(sString,"%s anim lock: ",bIsUpper?"Upper":"Lower");
MultiSequenceLock_t* pMultiLock = (bIsUpper)?&MultiSequenceLock_Upper:&MultiSequenceLock_Lower;
MultiSequenceLock_t::iterator it;
for (it = pMultiLock->begin(); it != pMultiLock->end(); ++it)
{
int iSeqIndex = *it;
pSeq = (bIsUpper)?Animation_GetUpperSequence(iSeqIndex):Animation_GetLowerSequence(iSeqIndex);
assert(pSeq);
if (pSeq)
{
if (pSeq == pCurrentMultiSeq)
iStrlenAtCurrentSeqPoint = strlen(sString);
strcat(sString,va("%s ",pSeq->sName.c_str()));
}
}
// int iXpos = (g_iScreenWidth/2)-( (strlen(sString)/2)*TEXT_WIDTH);
Text_DisplayFlat(sString, iXpos, iYpos, 255,0,0, true);
// now overlay the highlighted one for current...
//
if (pCurrentMultiSeq)
{
iXpos += iStrlenAtCurrentSeqPoint*TEXT_WIDTH;
Text_DisplayFlat(pCurrentMultiSeq->sName.c_str(), iXpos, iYpos, 255,0,255, true);
}
}
else
{
sprintf(sString,"%s anim lock: %s Frames: %4d...%4d%s",!i?"Upper":"Lower",String_EnsureMinLength(pSeq->sName.c_str(),iAnimLockLongestString),pSeq->iTargetFrame,(pSeq->iTargetFrame+pSeq->iFrameCount)-1,String_EnsureMinLength((pSeq->iLoopFrame==-1)?"":va(" loop: %3d(%3d)",pSeq->iLoopFrame,pSeq->iTargetFrame+pSeq->iLoopFrame),25));
// int iXpos = (g_iScreenWidth/2)-( (strlen(sString)/2)*TEXT_WIDTH);
Text_DisplayFlat(sString, iXpos, iYpos, 255,0,0, true);
}
}
if (RunningNT() == 4) // only needed on NT4, NT 2000 and W95/98 are ok
{
pSeq = NULL;
if (i==0 && iAnimDisplayNumber_Upper)
pSeq = Animation_GetUpperSequence( iAnimDisplayNumber_Upper-1);
if (i==1 && iAnimDisplayNumber_Lower)
pSeq = Animation_GetLowerSequence( iAnimDisplayNumber_Lower-1);
if (pSeq)
{
if (pSeq->bMultiSeq)
{
assert(0); // should never be able to get here in the animlock display-cycler
}
else
{
sprintf(sString,"( %s anim : %s Frames: %4d...%4d%s )",!i?"Upper":"Lower",String_EnsureMinLength(pSeq->sName.c_str(),iAnimLockLongestString),pSeq->iTargetFrame,(pSeq->iTargetFrame+pSeq->iFrameCount)-1,String_EnsureMinLength((pSeq->iLoopFrame==-1)?"":va(" loop: %3d(%3d)",pSeq->iLoopFrame,pSeq->iTargetFrame+pSeq->iLoopFrame),25));
int iXpos = (g_iScreenWidth/2)-( ((strlen(sString)/2)/*+2*/)*TEXT_WIDTH); // 2 chars back from LOCk string, because of bracket+space at start
int iYpos = g_iScreenHeight-((!i?7:6)*TEXT_DEPTH);
Text_DisplayFlat(sString, iXpos, iYpos, 0,200,200, true); // dim yellow
}
}
}
}
// display current FPS and interp state...
//
sprintf(sString,"FPS: %2.2f %s",1/(mdview.animSpeed),mdview.animate?"(Playing)":"(Stopped)");
iTextX =
Text_DisplayFlat(sString, (g_iScreenWidth/2)-( (strlen(sString)/2)*TEXT_WIDTH),
1*TEXT_DEPTH,
255,255,255,
false
);
if (mdview.interpolate)
{
iTextX = Text_DisplayFlat("(Interpolated)", iTextX+(2*TEXT_WIDTH),1*TEXT_DEPTH, 255/2,255/2,255/2,false);
}
iTextX = Text_DisplayFlat(va("(LOD: %d)",mdview.iLODLevel+1), iTextX+(2*TEXT_WIDTH), 1*TEXT_DEPTH, 255/2,255,255/2,false);
/* Text_DisplayFlat(sString, g_iScreenWidth-((strlen(sString)+2)*TEXT_WIDTH),
2 *TEXT_DEPTH,
255,255,255,
false
);*/
iTextX = Text_DisplayFlat(va("( FOV: %g )",mdview.dFOV), iTextX+(2*TEXT_WIDTH),1*TEXT_DEPTH, 255, 255, 255, false);
if (mdview.bUseAlpha)
{
Text_DisplayFlat("( Alpha )", iTextX+(2*TEXT_WIDTH),1*TEXT_DEPTH, 128, 128, 128, false);
}
// display head skin numbers in top left...
//
gl_model* pModel = R_FindModel( mdview.baseModel, "head");
if (pModel)
{
sprintf(sString,"Head skin: %s", va("\"%s%s\"",model->sHeadSkinName,!mdview.iSkinNumber?"":va("-%1d",mdview.iSkinNumber)));
Text_DisplayFlat(sString, 2*TEXT_WIDTH,//(g_iScreenWidth/2)-( (strlen(sString)/2)*TEXT_WIDTH),
1*TEXT_DEPTH,
200,200,200,
false
);
}
// display which format anim table this is using (if any)...
//
if (mdview.bAnimCFGLoaded)
{
if (mdview.bAnimIsMultiPlayerFormat)
sprintf(sString,"( MultiPlayer ) ");
else
sprintf(sString,"( SinglePlayer ) ");
int iYpos = g_iScreenHeight-(2*TEXT_DEPTH);
int iXpos = g_iScreenWidth -(strlen(sString)*TEXT_WIDTH);
Text_DisplayFlat(sString, iXpos, iYpos, 128,128,128, true); // grey
}
// display current picmip state...
//
{
extern int TextureList_GetMip(void);
int iYpos = g_iScreenHeight-(2*TEXT_DEPTH);
int iXpos = 1*TEXT_WIDTH;
sprintf(sString,"( PICMIP: %d )",TextureList_GetMip());
Text_DisplayFlat(sString,
iXpos, iYpos,
100,100,100,
false
);
}
}
}

221
md3view.h Executable file
View File

@ -0,0 +1,221 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
md3view.h - the header file holding the platform independent viewer interface.
the structure MD3ViewState holds all of the runtime global data needed by the viewer
holds most viewer interaction constants and mode enumerations.
this should be the only file included by system dependent code, but that rule is flexible.
*/
#ifndef _MD3_VIEW_H_
#define _MD3_VIEW_H_
//this is the caption name & the name in the about box
#define FILENAME "MD3View v1.6"
/*!
enumeration of various display modes that the ogl rendering engine supports. line refers
to wire frame, fill to flat shaded polygons, and textured is self explanatory.
*/
enum DrawMode {
DRAW_LINE,
DRAW_FILL,
DRAW_TEXTURE
};
/*!
texture modes supported by the engine, translates loosely to TEX_FAST being GL_NEAREST texture
fileter with fastest perspective correction. used mostly but he software driver. unfiltered is GL_NEAREST
with full perspective correction and filtered uses bilinear filetering.
*/
enum TextureMode {
TEX_FAST,
TEX_UNFILTERED,
TEX_FILTERED
};
/*!
MD3ViewState - main global structure that holds all the global variables need by the viewer at runtime.
is used for everythign and everwhere.
*/
typedef struct
{
float xPos, yPos;
float zPos;
float rotAngleX, rotAngleY;
float rotAngleZ;
double animSpeed;
double timeStamp1;
float frameFrac;
bool hasAnimation;
bool interpolate;
bool done;
bool animate;
bool bUseAlpha;
bool bBBox;
/* MD3GL * glmdl;
MD3 * model;
unsigned int* frames;
*/
NodeDictionary textureRes; // map of texture names to TextureGL data, stores texture resources
unsigned int topTextureBind; // simple index to keep track of texture bindings
NodeSequence modelList; // list of gl_meshes loaded
gl_model *baseModel; // base model of a tag hierarchy
DrawMode drawMode;
TextureMode texMode;
GLenum faceSide;
char basepath[128];
#ifdef WIN32
HWND hwnd;
HDC hdc;
HGLRC glrc;
#endif
int iLODLevel;
int iSkinNumber;
bool bAxisView;
byte _R,_G,_B; // clear colours
// these 2 just for printing stats info...
//
bool bAnimCFGLoaded;
bool bAnimIsMultiPlayerFormat;
double dFOV;
} MDViewState;
const double ANIM_SLOWER = 1.3;
const double ANIM_FASTER = 0.9;
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;
extern MDViewState mdview;
#ifdef WIN32
#include <windows.h>
/*!
platform independent key enumeration to drag functions
*/
enum mkey_enum {
KEY_LBUTTON = MK_LBUTTON,
KEY_RBUTTON = MK_RBUTTON,
KEY_MBUTTON = MK_MBUTTON
};
#endif
/*! initializes the mdview structures, should be called at startup before the gui is created */
void init_mdview(const char*);
/*! initializes the gl structures should be called immiedietly after opengl context has been created */
bool init_mdview_gl();
/*! called when window is resized to update gl matrices, actually defined in md3gl.cpp */
void set_windowSize( int x, int y );
/*! called to render the main viewer screen */
void render_mdview();
/*! commands to handle mouse dragging, uses key_flags defines above */
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 );
/*!
loads a model into the file, called by a file open dialog box
*/
bool loadmdl( char *filename );
/*
writes the current mesh frame to a raw file
*/
void write_baseModelToRaw( char *fname );
/*
frees data for shutdown, call this only as the last thing before exiting or bad thigns will happen
*/
void shutdown_mdviewdata();
/*
frees all mdviewdata, and effectively resets the data state back to init
*/
void free_mdviewdata();
/*! rewinds the animation, called by menu or key callbacks */
void rewindAnim();
void FrameAdvanceAnim(int iStep); // frame up or down (I generally call this for the '<' & '>' keys)
void SetLODLevel(int iLOD);
void SetFaceSkin(int iSkin);
void animation_loop();
/*
frees a model that has been loaded before by loadmdl_totag into the modelptr slot
*/
void freemdl_fromtag( GLMODEL_DBLPTR modelptr );
/*
loads a model into the slot pointed to by dblptr
*/
void loadmdl_totag( char *fullName, GLMODEL_DBLPTR dblptr );
/*
loads a new costum skin and sets all the models to it
*/
void importNewSkin( char *fullName );
bool ParseSequenceLockFile(LPCSTR psFilename);
#define sRAVEN "\n\n(This version heavily customised by Ste Cork @/4 Raven Software)"
#define ABOUT_TEXT "\n\n " FILENAME "\t\n\n" \
"A q3test model viewer\t\n\n" \
"started by Sander 'FireStorm' van Rossen\t\n" \
"& Matthew 'pagan' Baranowski\t\n\n" \
"a Mental Vortex production\t\n\n" \
"For more information go to: \t\n" \
"mvwebsite.hypermart.net\t\n\n" \
"SOURCE CODE IS FREELY AVAILABLE!!!\n\n" \
sRAVEN
extern int giTagMenuSubtractValue_Torso;
extern int giTagMenuSubtractValue_Head;
extern int giTagMenuSubtractValue_Weapon;
extern int giTagMenuSubtractValue_Barrel;
extern int giTagMenuSubtractValue_Barrel2;
extern int giTagMenuSubtractValue_Barrel3;
extern int giTagMenuSubtractValue_Barrel4;
extern gl_model* pLastLoadedModel;
#endif

277
md3view.rc Executable file
View File

@ -0,0 +1,277 @@
//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
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_MENU1 MENU DISCARDABLE
BEGIN
POPUP "File"
BEGIN
MENUITEM "Open..\tCtrl-O", ID_FILE_OPEN
MENUITEM "Export as MD3", ID_FILE_SAVE_MD3
MENUITEM "Export as GLM (Ghoul 2)", ID_FILE_SAVE_G2
MENUITEM "Export as GLM (Ghoul 2) *without* 90-degree skewing ( added for JKA )",
ID_FILE_SAVE_G2_PERFECT
MENUITEM "Export to Raw...", ID_FILE_EXPORTTORAW, GRAYED
MENUITEM "Import skin..", ID_FILE_IMPORTSKIN
MENUITEM "Import Sequence file", ID_FILE_IMPORTMULTISEQ
MENUITEM "E&xit\tCtrl-X", ID_FILE_EXIT
END
POPUP "View"
BEGIN
MENUITEM "&Wire Frame\tW", ID_VIEW_WIREFRAME
MENUITEM "&Flat Shaded\tF", ID_VIEW_FLATSHADED
MENUITEM "&Textured\tT", ID_VIEW_TEXTURED
MENUITEM "Textured &Shaded\tS", ID_VIEW_TEXTUREDSHADED
MENUITEM "Textured && WireFrame\tCTRL-W", ID_VIEW_TEXTUREDWIREFRAME
MENUITEM SEPARATOR
MENUITEM "Reset &Viewpos\tSHIFT-V", ID_VIEWPOS_RESET
MENUITEM SEPARATOR
MENUITEM "Refresh Texture\tAlt-R", ID_VIEW_REFRESHTEXTURE
MENUITEM SEPARATOR
MENUITEM "F&ast Texture\tA", ID_VIEW_NEAREST
MENUITEM "&Unfiltered Texture\tU", ID_VIEW_UNFILTEREDTEXTURE
MENUITEM "F&iltered Texture\tI", ID_VIEW_FILTEREDTEXTURE
MENUITEM SEPARATOR
MENUITEM "View Loaded-Models info", ID_VIEW_LOADEDSTUFF
MENUITEM "View Origin ( model axis and tags )\tALT-O", ID_VIEWAXIS
MENUITEM SEPARATOR
MENUITEM "Toggle Alpha Blending\tSHIFT-A", ID_VIEWALPHA
MENUITEM SEPARATOR
MENUITEM "ScreenShot To Clipboard\tCTRL-C", ID_SCREENSHOT_CLIPBOARD
MENUITEM "ScreenShot To File\tSHIFT-C", ID_SCREENSHOT_FILE
MENUITEM SEPARATOR
MENUITEM "Background Colour Picker\tALT-C", ID_VIEW_COLOURPICKER
MENUITEM SEPARATOR
MENUITEM "Toggle FOV 80/90/10\tCTRL-F", ID_VIEW_FOVTOGGLE
MENUITEM "Toggle &Bounding-box\tCTRL-B", ID_VIEW_BOUNDSTOGGLE
MENUITEM SEPARATOR
MENUITEM "LOD1\tF1", ID_LOD0
MENUITEM "LOD2\tF2", ID_LOD1
MENUITEM "LOD3\tF3", ID_LOD2
MENUITEM SEPARATOR
MENUITEM "Picmip 0\tCTRL-F1", ID_PICMIP0
MENUITEM "Picmip 1\tCTRL-F2", ID_PICMIP1
MENUITEM "Picmip 2 (..7)\tCTRL-F3..F8", ID_PICMIP2
END
POPUP "Animation"
BEGIN
MENUITEM "&Slower\tLeftArrow", ID_ANIMATION_SLOWER
MENUITEM "&Faster\tRightArrow", ID_ANIMATION_FASTER
MENUITEM "S&top\tSpace", ID_ANIMATION_STOP
MENUITEM "St&art\tUpArrow", ID_ANIMATION_START
MENUITEM "&Rewind\tDownArrow", ID_ANIMATION_REWIND
MENUITEM "&Interpolate\tN", ID_ANIMATION_INTERPOLATE
MENUITEM "Increase face anim\tF4", ID_FACE_INCANIM
MENUITEM "Decrease face anim\tCTRL-SHIFT F4", ID_FACE_DECANIM
MENUITEM "Reset face anim\tShift-F4", ID_FACE_RESANIM
END
POPUP "Tags"
BEGIN
MENUITEM SEPARATOR
END
MENUITEM "About", ID_ABOUT
END
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APP ICON DISCARDABLE "ID_APP.ico"
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
ID_FILE_EXPORTTORAW "This is pretty pointless really"
ID_VIEW_LOADEDSTUFF "Shows stuff like tags, TGA filenames etc..."
ID_LOD0 "Change LOD level"
ID_LOD1 "View using LOD2 (if defined)"
ID_LOD2 "View using LOD3 (if defined)"
ID_FACE_INCANIM "(Only works if a head model is loaded)"
ID_FACE_DECANIM "(Only works if a head model is loaded)"
ID_FACE_RESANIM "(Only works if a head model is loaded)"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_FILE_SAVE_MD3 "(Export model as MD3 format)"
ID_FILE_IMPORTMULTISEQ "Used fr importing a multi-sequence lock file"
ID_VIEWALPHA "Have a guess..."
ID_SCREENSHOT_CLIPBOARD "Takes a screenshot (without text onscreen)"
ID_SCREENSHOT_FILE "Saves screenshot to a disk file (without onscreen text)"
ID_VIEW_COLOURPICKER "Pick a different background colour"
ID_VIEW_FOVTOGGLE "Toggles FOV between 80 (E.F.) 90 (Qu*ke) and 10 (for better screenshots)"
ID_FILE_SAVE_G2 "(Export model as Ghoul2)"
ID_PICMIP0 "Change all textures to use picmip 0"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_PICMIP1 "Re-upload all textures at picmip 1"
ID_PICMIP2 "reload all textures to picmip 2"
ID_VIEWPOS_RESET "Reset viewpos to default, useful if you've scrolled offscreen and lost the model"
ID_VIEW_TEXTUREDWIREFRAME
"View as both textured and with wireframe lines on"
ID_VIEW_BOUNDSTOGGLE "Toggles the drawing of bounding boxes"
ID_FILE_SAVE_G2_PERFECT "(Export model as Ghoul2, but WITHOUT the 90-degree skewing)"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Dutch (Netherlands) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NLD)
#ifdef _WIN32
LANGUAGE LANG_DUTCH, SUBLANG_DUTCH
#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
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE
BEGIN
",", ID_FRAME_DW, ASCII, NOINVERT
".", ID_FRAME_UP, ASCII, NOINVERT
"A", ID_VIEW_NEAREST, VIRTKEY, NOINVERT
"A", ID_ABOUT, VIRTKEY, CONTROL, NOINVERT
"A", ID_VIEWALPHA, VIRTKEY, SHIFT, NOINVERT
"B", ID_VIEW_BOUNDSTOGGLE, VIRTKEY, CONTROL, NOINVERT
"C", ID_SCREENSHOT_CLIPBOARD, VIRTKEY, CONTROL, NOINVERT
"C", ID_VIEW_COLOURPICKER, VIRTKEY, ALT, NOINVERT
"C", ID_SCREENSHOT_FILE, VIRTKEY, SHIFT, NOINVERT
"F", ID_VIEW_FLATSHADED, VIRTKEY, NOINVERT
"F", ID_VIEW_FOVTOGGLE, VIRTKEY, CONTROL, NOINVERT
"I", ID_VIEW_FILTEREDTEXTURE, VIRTKEY, NOINVERT
"L", ID_VIEWLOWERANIM_DEC, VIRTKEY, CONTROL, NOINVERT
"L", ID_VIEWLOWERANIM_LOCK, VIRTKEY, ALT, NOINVERT
"L", ID_VIEWLOWERANIM_INC, VIRTKEY, SHIFT, NOINVERT
"N", ID_ANIMATION_INTERPOLATE, VIRTKEY, NOINVERT
"O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
"O", ID_VIEWAXIS, VIRTKEY, ALT, NOINVERT
"R", ID_VIEW_REFRESHTEXTURE, VIRTKEY, ALT, NOINVERT
"S", ID_VIEW_TEXTUREDSHADED, VIRTKEY, NOINVERT
"T", ID_VIEW_TEXTURED, VIRTKEY, NOINVERT
"U", ID_VIEW_UNFILTEREDTEXTURE, VIRTKEY, NOINVERT
"U", ID_VIEWUPPERANIM_DEC, VIRTKEY, CONTROL, NOINVERT
"U", ID_VIEWUPPERANIM_LOCK, VIRTKEY, ALT, NOINVERT
"U", ID_VIEWUPPERANIM_INC, VIRTKEY, SHIFT, NOINVERT
"V", ID_VIEWPOS_RESET, VIRTKEY, SHIFT, NOINVERT
VK_DOWN, ID_ANIMATION_REWIND, VIRTKEY, NOINVERT
VK_ESCAPE, ID_FILE_EXIT, VIRTKEY, NOINVERT
VK_F1, ID_LOD0, VIRTKEY, NOINVERT
VK_F1, ID_PICMIP0, VIRTKEY, CONTROL, NOINVERT
VK_F2, ID_LOD1, VIRTKEY, NOINVERT
VK_F2, ID_PICMIP1, VIRTKEY, CONTROL, NOINVERT
VK_F3, ID_LOD2, VIRTKEY, NOINVERT
VK_F3, ID_PICMIP2, VIRTKEY, CONTROL, NOINVERT
VK_F4, ID_FACE_INCANIM, VIRTKEY, NOINVERT
VK_F4, ID_PICMIP3, VIRTKEY, CONTROL, NOINVERT
VK_F4, ID_FACE_RESANIM, VIRTKEY, SHIFT, NOINVERT
VK_F4, ID_FACE_DECANIM, VIRTKEY, SHIFT, CONTROL,
NOINVERT
VK_F5, ID_PICMIP4, VIRTKEY, CONTROL, NOINVERT
VK_F6, ID_PICMIP5, VIRTKEY, CONTROL, NOINVERT
VK_F7, ID_PICMIP6, VIRTKEY, CONTROL, NOINVERT
VK_F8, ID_PICMIP7, VIRTKEY, CONTROL, NOINVERT
VK_LEFT, ID_ANIMATION_SLOWER, VIRTKEY, NOINVERT
VK_RIGHT, ID_ANIMATION_FASTER, VIRTKEY, NOINVERT
VK_SPACE, ID_ANIMATION_STOP, VIRTKEY, NOINVERT
VK_UP, ID_ANIMATION_START, VIRTKEY, NOINVERT
"W", ID_VIEW_WIREFRAME, VIRTKEY, NOINVERT
"W", ID_VIEW_TEXTUREDWIREFRAME, VIRTKEY, CONTROL, NOINVERT
"X", ID_FILE_EXIT, VIRTKEY, CONTROL, NOINVERT
END
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDS_FILESTRING "Model files (*.MDR)(*.MD3)|*.md?|"
IDS_RAWFILEFILTER ".raw files (*.raw)|*.raw|"
IDS_SKINFILEFILTER "Skin files (*.skin)|*.skin|"
IDS_MD3FILEFILTER "MD3 files (*.MD3)|*.md3|"
IDS_SEQFILTER "Multi-Sequence lock files (*.SEQ)|*.SEQ|"
END
#endif // Dutch (Netherlands) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

195
mdr.h Executable file
View File

@ -0,0 +1,195 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MDR_H
#define MDR_H
// a whole bunch of crap to make a big cut/paste from Trek work...
typedef int qboolean;
#define qfalse 0
#define qtrue 1
#define MAX_QPATH 64
// surface geometry should not exceed these limits
#define SHADER_MAX_VERTEXES 1000
#define SHADER_MAX_INDEXES (6*SHADER_MAX_VERTEXES)
#define MD4_IDENT (('5'<<24)+('M'<<16)+('D'<<8)+'R')
#define MD4_VERSION 2
#define MD4_MAX_BONES 128
typedef float vec_t;
typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
typedef vec_t vec5_t[5];
#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0)
#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2])
#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2])
#define VectorScale(v, s, o) ((o)[0]=(v)[0]*((vec_t)s),(o)[1]=(v)[1]*((vec_t)s),(o)[2]=(v)[2]*((vec_t)s))
#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))
typedef enum {
MODTYPE_BAD,
MODTYPE_MD3,
MODTYPE_MDR,
} modelType_t;
typedef enum {
SF_BAD,
SF_SKIP, // ignore
SF_FACE,
SF_GRID,
SF_TRIANGLES,
SF_POLY,
SF_MD3,
SF_MD4,
SF_FLARE,
SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
SF_DISPLAY_LIST,
SF_NUM_SURFACE_TYPES,
SF_MAX = 0xffffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
} surfaceType_t;
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 {
unsigned char Comp[24]; // MC_COMP_BYTES is in MatComp.h, but don't want to couple
} md4CompBone_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
md4CompBone_t bones[1]; // [numBones]
} md4CompFrame_t;
typedef struct {
int numSurfaces;
int ofsSurfaces; // first surface, others follow
int ofsEnd; // next lod follows
} md4LOD_t;
typedef struct {
int boneIndex;
char name[32];
} md4Tag_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] // this will be -ve for compressed models
// each level of detail has completely separate sets of surfaces
int numLODs;
int ofsLODs;
int numTags;
int ofsTags;
int ofsEnd; // end of file
} md4Header_t;
typedef struct model_s {
char name[MAX_QPATH];
modelType_t modelType;
int index; // model = tr.models[model->index]
int dataSize; // just for listing purposes
// bmodel_t *bmodel; // only if type == MOD_BRUSH
// md3Header_t *md3[MD3_MAX_LODS]; // only if type == MOD_MESH
md4Header_t *md4; // only if type == MOD_MD4
int numLods;
} model_t;
#define LittleFloat(l) l
#define LittleLong(l) l
#define LL(x) x=LittleLong(x)
#endif // #ifndef MDR_H

439
mdx_format.h Executable file
View File

@ -0,0 +1,439 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//
// 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 ///////////////////////

109
ndictionary.h Executable file
View File

@ -0,0 +1,109 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NPDICTIONARY_H_
#define _NPDICTIONARY_H_
#include "nsequence.h"
typedef class NodeLocatorInfo * NodeLocator;
typedef class NodeDictionaryInfo * NodeDictionary;
typedef class KeyComparatorInfo * KeyComparator;
typedef class StrKeyComparatorInfo * StrKeyComparator;
typedef class IntKeyComparatorInfo * IntKeyComparator;
/********************************************************************
* CLASS NAME: KeyComparator
* abstract class defining the interface for KeyComparators
********************************************************************/
#ifndef BOOL
#define BOOL int
#endif
class KeyComparatorInfo
{
public:
virtual BOOL equal( Object key1, Object key2 )=0;
virtual char *printKey( Object key )=0;
};
/* integer comparator */
class IntKeyComparatorInfo: public KeyComparatorInfo
{
public:
virtual BOOL equal( Object key1, Object key2 ) { return ((int)key1 == (int)key2); }
virtual char *printKey( Object key ) { return NULL; }
};
/* string comparator */
class StrKeyComparatorInfo: public KeyComparatorInfo
{
public:
virtual BOOL equal( Object key1, Object key2 );
virtual char *printKey( Object key ) { return (char*)key; }
};
/********************************************************************
* CLASS NAME: NodeLocator
* extends NodePosition class to include a key for indexing
********************************************************************/
class NodeLocatorInfo: public NodePositionInfo {
private:
Object m_key;
public:
NodeLocatorInfo( NodeSequence container, Object element, Object key ):
NodePositionInfo( container, element)
{ m_key = key; };
void setKey( Object key ) { m_key = key; }
Object key() { return m_key; }
};
/********************************************************************
* CLASS NAME: NodeDictionary
* stores a series of locators that are acessed using their keys,
* a key comparator class defines how keys are used
********************************************************************/
class NodeDictionaryInfo: public NodeSequenceInfo {
private:
KeyComparator m_keyComp;
public:
NodeDictionaryInfo( KeyComparator kC ): NodeSequenceInfo() { m_keyComp = kC; };
/* appends the key, element pair to the end of the list */
void insert( Object element, Object key );
/* if the key already exists, replaces the returned element, otherwise inserts new pair */
Object insertReplace( Object element, Object key );
/* returns an object mapped to the key */
Object find( Object key );
/* removes the key, element pair and returns the element */
Object remove( Object key );
/* replaces the element mapped to the key */
Object replace( Object element, Object key );
/* debugging dump */
void dumpDictionary();
};
#endif

100
nodedictionary.cpp Executable file
View File

@ -0,0 +1,100 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ndictionary.h"
#include <iostream>
using namespace std;
void NodeDictionaryInfo::insert( Object element, Object key )
{
NodeLocator nL = new NodeLocatorInfo( this, element, key );
insertLast( nL );
};
Object NodeDictionaryInfo::insertReplace( Object element, Object key )
{
Object toReturn;
NodeLocator nL;
for (nL = (NodeLocator)first(); nL != NULL; nL = (NodeLocator)after(nL))
{
if (m_keyComp->equal( nL->key(), key )) {
toReturn = nL->element();
nL->setElement( element );
return toReturn;
}
}
// found nothing so append
nL = new NodeLocatorInfo( this, element, key );
insertLast( nL );
return NULL;
};
Object NodeDictionaryInfo::find(Object key)
{
for (NodeLocator nL = (NodeLocator)first(); nL != NULL; nL = (NodeLocator)after(nL))
{
if (m_keyComp->equal( nL->key(), key )) {
return nL->element();
}
}
return NULL; // found nothing
}
Object NodeDictionaryInfo::remove( Object key )
{
for (NodeLocator nL = (NodeLocator)first(); nL != NULL; nL = (NodeLocator)after(nL))
{
if (m_keyComp->equal( nL->key(), key )) {
return remove( nL );
}
}
return NULL; // found nothing
}
Object NodeDictionaryInfo::replace( Object element, Object key )
{
Object toReturn;
for (NodeLocator nL = (NodeLocator)first(); nL != NULL; nL = (NodeLocator)after(nL))
{
if (m_keyComp->equal( nL->key(), key )) {
toReturn = nL->element();
nL->setElement( element );
return toReturn;
}
}
return NULL; // found nothing
}
void NodeDictionaryInfo::dumpDictionary()
{
cout << "Dictionary Dump, size " << size() << endl;
for (NodeLocator nL = (NodeLocator)first(); nL != NULL; nL = (NodeLocator)after(nL))
{
cout << " Position " << nL;
cout << " next " << nL->getNextNode();
cout << " prev " << nL->getPrevNode();
cout << " element " << nL->element();
cout << " key " << (char *)nL->key() << endl;
}
}

274
nodesequence.cpp Executable file
View File

@ -0,0 +1,274 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ndictionary.h"
#include <string.h>
#include <iostream>
using namespace std;
//void DebugToFile (char *msg, ...);
BOOL StrKeyComparatorInfo::equal( Object key1, Object key2 )
{
return (!strcmp( (char*)key1, (char*)key2 ));
}
/*
=======
destructor removes sequence positions, however does nothing for the object pointers
use this if _only_ if don't need to delete position elements
=======
*/
NodeSequenceInfo::~NodeSequenceInfo()
{
NodePosition pos, next;
if (!isEmpty()) {
for(pos=first(); pos!=NULL ; pos=next) {
next = after(pos);
remove(pos);
}
}
}
Object NodeSequenceInfo::replace(NodePosition position, Object newElement )
{
NodePosition nodePosition = (NodePosition)position;
Object toReturn = nodePosition->element();
nodePosition->setElement( newElement );
return toReturn;
};
void NodeSequenceInfo::dumpSequence()
{
cout << "Sequence Dump, size " << size() << endl;
for (NodePosition pos = first(); pos != NULL; pos = after(pos) ) {
cout << " Position " << pos;
cout << " next " << pos->getNextNode();
cout << " prev " << pos->getPrevNode();
cout << " element " << pos->element() << endl;
}
}
void NodeSequenceInfo::swap(NodePosition p1,NodePosition p2 )
{
NodePosition nP1 = (NodePosition)p1;
NodePosition nP2 = (NodePosition)p2;
Object element = nP1->element();
nP1->setElement( nP2->element() );
nP2->setElement( element );
};
NodePosition NodeSequenceInfo::before( NodePosition p )
{
NodePosition nodePosition = (NodePosition)p;
return nodePosition->getPrevNode();
};
NodePosition NodeSequenceInfo::after( NodePosition p )
{
NodePosition nodePosition = (NodePosition)p;
return nodePosition->getNextNode();
};
NodePosition NodeSequenceInfo::insertFirst( Object element )
{
NodePosition nP = new NodePositionInfo( this, element );
return insertFirst( nP );
}
NodePosition NodeSequenceInfo::insertFirst( NodePosition nP )
{
nP->setPrevNode( NULL );
nP->setNextNode( first_ );
if (first_) first_->setPrevNode( nP );
first_ = nP;
if (nP->getNextNode() == NULL) {
last_ = nP;
}
size_++;
return first_;
}
NodePosition NodeSequenceInfo::insertLast( Object element )
{
NodePosition nP = new NodePositionInfo( this, element );
return insertLast( nP );
};
NodePosition NodeSequenceInfo::insertLast( NodePosition nP )
{
nP->setPrevNode( last_ );
nP->setNextNode( NULL );
if (last_) last_->setNextNode( nP );
last_ = nP;
if (nP->getPrevNode() == NULL) {
first_ = nP;
}
size_++;
return last_;
};
NodePosition NodeSequenceInfo::insertAfter(NodePosition p, Object element )
{
NodePosition node = (NodePosition)p;
if (node->getNextNode() == NULL) {
NodePosition result = insertLast(element);
return result;
}
NodePosition nP = new NodePositionInfo( this, element );
nP->setPrevNode( node );
nP->setNextNode( node->getNextNode() );
node->getNextNode()->setPrevNode( nP );
node->setNextNode( nP );
size_++;
return nP;
};
NodePosition NodeSequenceInfo::insertBefore(NodePosition p, Object element )
{
NodePosition node = (NodePosition)p;
if (node->getPrevNode() == NULL) {
return insertFirst( element );
}
NodePosition nP = new NodePositionInfo( this, element );
nP->setNextNode( node );
nP->setPrevNode( node->getPrevNode() );
NodePosition prevNode = node->getPrevNode();
prevNode->setNextNode( nP );
node->setPrevNode( nP );
size_++;
return nP;
};
Object NodeSequenceInfo::remove(NodePosition p )
{
NodePosition nP = (NodePosition)p;
Object toReturn = nP->element();
NodePosition prevNode = nP->getPrevNode();
if (prevNode == NULL) {
Object result = removeFirst();
return result;
}
NodePosition nextNode = nP->getNextNode();
if (nextNode == NULL) {
Object result = removeLast();
return result;
}
prevNode->setNextNode( nextNode );
nextNode->setPrevNode( prevNode );
delete nP;
size_--;
return toReturn;
};
Object NodeSequenceInfo::removeAfter(NodePosition p )
{
NodePosition nP = (NodePosition)p;
if (nP->getNextNode() == NULL) {
return NULL;
}
nP = nP->getNextNode();
Object toReturn = nP->element();
NodePosition prevNode = nP->getPrevNode();
NodePosition nextNode = nP->getNextNode();
if (nextNode == NULL) {
return removeLast();
}
prevNode->setNextNode( nextNode );
nextNode->setPrevNode( prevNode );
delete nP;
size_--;
return toReturn;
};
Object NodeSequenceInfo::removeBefore(NodePosition p )
{
NodePosition nP = (NodePosition)p;
if (nP->getPrevNode() == NULL) {
return NULL;
}
nP = nP->getPrevNode();
Object toReturn = nP->element();
NodePosition prevNode = nP->getPrevNode();
if (prevNode == NULL) {
return removeFirst();
}
NodePosition nextNode = nP->getNextNode();
prevNode->setNextNode( nextNode );
nextNode->setPrevNode( prevNode );
delete nP;
size_--;
return toReturn;
};
Object NodeSequenceInfo::removeFirst()
{
NodePosition nP = (NodePosition)first_;
Object toReturn = nP->element();
NodePosition nextNode = nP->getNextNode();
if (nextNode) nextNode->setPrevNode( NULL );
first_ = nextNode;
if (!first_) last_ = NULL;
delete nP;
size_--;
return toReturn;
};
Object NodeSequenceInfo::removeLast()
{
NodePosition nP = (NodePosition)last_;
Object toReturn = nP->element();
NodePosition prevNode = nP->getPrevNode();
if (prevNode) prevNode->setNextNode( NULL );
last_ = prevNode;
if (!last_) first_ = NULL;
delete nP;
size_--;
return toReturn;
};

110
nsequence.h Executable file
View File

@ -0,0 +1,110 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
linked list implementation, by Matthew Baranowski
*/
#ifndef _NPSEQUENCE_H_
#define _NPSEQUENCE_H_
#define Object void *
#ifndef NULL
#define NULL 0
#endif
typedef class NodePositionInfo * NodePosition;
typedef class NodeSequenceInfo * NodeSequence;
/********************************************************************
* CLASS NAME: NodePosition
* double linked nodeNodePosition implementation
********************************************************************/
class NodePositionInfo {
private:
NodeSequence container_;
Object element_;
NodePosition nextNode_;
NodePosition prevNode_;
public:
NodePositionInfo( NodeSequence container, Object element )
{ container_ = container; element_ = element; };
void setNextNode( NodePosition nextNode ) { nextNode_ = nextNode; };
void setPrevNode( NodePosition prevNode ) { prevNode_ = prevNode; };
NodePosition getNextNode() { return nextNode_; };
NodePosition getPrevNode() { return prevNode_; };
void setElement( Object element ) { element_ = element; };
NodeSequence container() { return container_; };
Object element() { return element_; };
};
/********************************************************************
*
* CLASS NAME: NodeSequence
*
* double linked node sequence implementation
*
********************************************************************/
class NodeSequenceInfo {
private:
NodePosition first_;
NodePosition last_;
int size_;
public:
NodeSequenceInfo() { size_ = 0; first_ = last_ = NULL; };
~NodeSequenceInfo();
void clearSequence() { size_ = 0; first_ = last_ = NULL; };
NodeSequence newContainer() { return new NodeSequenceInfo(); };
int isEmpty() { if (size_ == 0) return 1; else return 0;};
int size() { return size_; };
Object replace(NodePosition, Object newElement );
void swap(NodePosition p1,NodePosition p2 );
NodePosition first() { return first_; };
NodePosition last() { return last_; };
NodePosition before(NodePosition p );
NodePosition after(NodePosition p );
NodePosition insertFirst( Object element );
NodePosition insertLast( Object element );
NodePosition insertFirst( NodePosition nP );
NodePosition insertLast( NodePosition nP );
NodePosition insertBefore(NodePosition p, Object element );
NodePosition insertAfter(NodePosition p, Object element );
Object remove(NodePosition p );
Object removeAfter(NodePosition p );
Object removeBefore(NodePosition p );
Object removeFirst();
Object removeLast();
void dumpSequence();
};
#endif

678
oddbits.cpp Executable file
View File

@ -0,0 +1,678 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.h"
#include "oddbits.h"
// at some stage I could do with adding the multi-call-protect code in this func to all the other char routines,
// but I'll just do it as and when I hit problems...
//
char *va(char *format, ...)
{
va_list argptr;
static char string[8][1024];
static int i=0;
i=(i+1)&7;
va_start (argptr, format);
vsprintf (string[i], format,argptr);
va_end (argptr);
return string[i];
}
// these MUST all be MB_TASKMODAL boxes now!!
//
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 );
}
bool FileExists (LPCSTR psFilename)
{
FILE *handle = fopen(psFilename, "r");
if (!handle)
{
return false;
}
fclose (handle);
return true;
}
// 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;
}// char *scGetTempPath(void)
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)
{
FILE *f;
int length;
void *buffer;
*bufferptr = 0; // some code checks this as a return instead
f = fopen(psPathedFilename,"rb");
if (f)
{
length = filesize(f);
buffer = malloc (length+1 + 4096); // keep this in sync with INPUT_BUF_SIZE, since the JPG loader is sloppy
((char *)buffer)[length] = 0;
int lread = fread (buffer,1,length, f);
fclose (f);
if (lread==length)
{
*bufferptr = buffer;
return length;
}
free(buffer);
}
ErrorBox(va("Error reading file %s!",psPathedFilename));
return -1;
}
/*
// takes (eg) "q:\quake\baseq3\textures\borg\name.tga"
//
// and produces "textures/borg/name.tga"
//
void Filename_RemoveBASEQ(CString &string)
{
string.Replace("\\","/");
int loc = string.Find("/baseq"); // 2,3, etc...
if (loc >= 0)
{
string = string.Right(string.GetLength() - (loc+7+1));
}
}
// takes (eg) "textures/borg/name.tga"
//
// and produces "textures/borg"
//
void Filename_RemoveFilename(CString &string)
{
string.Replace("\\","/");
int loc = string.ReverseFind('/');
if (loc >= 0)
{
string = string.Left(loc);
}
}
// takes (eg) "( longpath )/textures/borg/name.xxx" // N.B. I assume there's an extension on the input string
//
// and produces "name"
//
void Filename_BaseOnly(CString &string)
{
string.Replace("\\","/");
int loc = string.GetLength()-4;
if (string[loc] == '.')
{
string = string.Left(loc); // "( longpath )/textures/borg/name"
loc = string.ReverseFind('/');
if (loc >= 0)
{
string = string.Mid(loc+1);
}
}
}
void Filename_AccountForLOD(CString &string, int iLODLevel)
{
if (iLODLevel)
{
int loc = string.ReverseFind('.');
if (loc>0)
{
string.Insert( loc, va("_%d",iLODLevel));
}
}
}
*/
// returns actual filename only, no path
//
char *Filename_WithoutPath(LPCSTR psFilename)
{
static char sString[MAX_PATH];
LPCSTR p = strrchr(psFilename,'\\');
if (!p++)
p=psFilename;
strcpy(sString,p);
return sString;
}// char *Filename_WithoutPath(char *psFilename)
// 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,'\\');
// 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)))
*p=0;
return sString;
}// char *Filename_WithoutExt(char *psFilename)
// loses anything after the path (if any), (eg) "\dir\name.bmp" becomes "\dir"
//
char *Filename_PathOnly(LPCSTR psFilename)
{
static char sString[8][MAX_PATH];
static int iIndex =0;
iIndex = (++iIndex)&7;
strcpy(sString[iIndex],psFilename);
char *p= strrchr(sString[iIndex],'\\');
if (p)
*p=0;
return sString[iIndex];
}// char *Filename_WithoutExt(char *psFilename)
// returns filename's extension only, 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;
}// char *Filename_ExtOnly(char *psFilename);
// 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);
}// char *String_ToLower(char *psString)
// 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_ToUpper(char *psString)
// first letter uppercase, rest lower, purely cosmetic when printing certain strings
//
char *String_Neaten(LPCSTR psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
strlwr(sString);
int iCheckLen = strlen(sString);
for (int i=0; i<iCheckLen; i++)
{
if (isalpha(sString[i]))
{
sString[i] = toupper(sString[i]);
break;
}
}
return sString;
}// char *String_Neaten(char *psString)
// whole sentence lowercase, then upper-case first letter in every sequence (usually word starts)
//
char *String_NeatenEveryWord(LPCSTR psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
strlwr(sString);
int iCheckLen = strlen(sString);
BOOL bWaitingAlpha = TRUE;
for (int i=0; i<iCheckLen; i++)
{
if (bWaitingAlpha)
{
if (isalpha(sString[i]))
{
sString[i] = toupper(sString[i]);
bWaitingAlpha = !bWaitingAlpha;
}
}
else
{
if (!isalpha(sString[i]))
bWaitingAlpha = !bWaitingAlpha;
}
}// for (int i=0; i<iCheckLen; i++)
return sString;
}// char *String_NeatenEveryWord(char *psString)
// string replacer, useful to hacking path strings etc
//
// eg:- printf("%s\n", String_Replace("I like computers","like", "fucking hate", TRUE));
//
// would produce "I fucking hate computers"
//
char *String_Replace(char *psString, char *psFind, char *psReplace, BOOL bCaseInSensitive)
{
static char sString[MAX_PATH];
int iFoundOffset;
char *psFound;
if (bCaseInSensitive)
{
char sFind[MAX_PATH];
strcpy(sString,psString);
strcpy(sFind, psFind);
strlwr(sString);
strlwr(sFind);
psFound = strstr(sString,sFind);
iFoundOffset = psFound - sString;
}
else
{
psFound = strstr(psString,psFind);
iFoundOffset = psFound - psString;
}
if (psFound)
{
ZEROMEM(sString);
strncpy(sString,psString,iFoundOffset);
strcat (sString,psReplace);
strcat (sString,&psString[iFoundOffset+strlen(psFind)]);
}
else
{
strcpy(sString,psString);
}
return sString;
}// char *String_Replace(char *psString, char *psFind, char *psReplace, BOOL bCaseSensitive)
// returns a string of up to but not including the first comma (if any) of the supplied string, else NULL if blank string
//
char *String_GetField(char *psString)
{
static char sString[MAX_PATH];
strcpy(sString,String_LoseLeadingWhitespace(psString));
char *p = strchr(sString,',');
if (p)
*p=0;
if (!strlen(sString))
return NULL;
return sString;
}// char *String_GetField(char *psString)
// loses the first comma-delineated field from the supplied string, else NULL if no more fields after current
//
char *String_LoseField(char *psString)
{
static char sString[MAX_PATH];
char *p = strchr(psString,',');
if (p)
strcpy(sString,p+1);
else
strcpy(sString,"");
if (!strlen(String_LoseLeadingWhitespace(sString)))
return NULL;
return sString;
}// char *String_LoseField(char *psString)
char *String_LoseWhitespace(char *psString)
{
static char sString[MAX_PATH];
char *psSrc = psString;
char *psDest = sString;
char c;
do
{
while (isspace(*psSrc)) psSrc++;
*psDest++ = c = *psSrc++;
}
while (c);
return sString;
}// char *String_LoseWhitespace(char *psString)
char *String_LoseLeadingWhitespace(char *psString)
{
static char sString[MAX_PATH];
char *psSrc = psString;
char *psDest = sString;
while (isspace(*psSrc)) psSrc++;
while ((*psDest++ = *psSrc++)!=0);
return sString;
}// char *String_LoseLeadingWhitespace(char *psString)
char *String_LoseTrailingWhitespace(char *psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
if (strlen(sString))
{
char *p = &sString[strlen(sString)-1];
while (isspace(*p))
*p-- = 0;
}
return sString;
}// char *String_LoseTrailingWhitespace(char *psString)
// I know, i know, but it's helpful to keep things simple when using inline string filters...
//
char *String_EnsureTrailingChar(char *psString, char c)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
// no doubt this could be done really cleverly, but...
//
if (strlen(sString))
{
char *p = &sString[strlen(sString)-1];
if (*p!=c)
{
p++;
*p++=c;
*p++=0;
}
}
else
{
sString[0]=c;
sString[1]=0;
}
return sString;
}// char *String_EnsureTrailingChar(char *psString, char c)
// I know, i know, but it's helpful to keep things simple when using inline string filters...
//
char *String_LoseTrailingChar(char *psString, char c)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
if (strlen(sString))
{
char *p = &sString[strlen(sString)-1];
if (*p==c)
*p=0;
}
return sString;
}// char *String_LoseTrailingChar(char *psString, char c)
char *String_LoseComment(char *psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
char *psComment = strchr(sString,';');
if (psComment)
*psComment=0;
return sString;
}// char *String_LoseComment(char *psString)
char *String_LoseNewline(char *psString)
{
static char sString[MAX_PATH];
strcpy(sString,psString);
char *psNewLine = strchr(sString,'\n');
if (psNewLine)
*psNewLine=0;
return sString;
}// char *String_LoseNewline(char *psString)
// 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];
}// char *String_EnsureMinLength(char *psString, int iMinLength)
// returns either 0 for not NT, or 4 or 5 for versions (5=Windows 2000, which doesn't work properly)
//
int RunningNT(void)
{
return 4; // James wants the functions that check this to be available all the time, so...
/*
static bool bAnswered = false;
static int iAnswer = 0;
if (!bAnswered)
{
OSVERSIONINFO osid;
osid.dwOSVersionInfoSize = sizeof (osid);
GetVersionEx (&osid);
switch (osid.dwPlatformId)
{
// Window 3.x
case VER_PLATFORM_WIN32s:
break;
// Windows 95
case VER_PLATFORM_WIN32_WINDOWS:
break;
// Windows NT
case VER_PLATFORM_WIN32_NT:
{
if(osid.dwMajorVersion >= 4)
{
iAnswer = osid.dwMajorVersion;
}
break;
}
}
bAnswered = true;
}
return iAnswer;
*/
}
void SystemErrorBox(DWORD dwError)
{
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
);
ErrorBox( (LPCSTR) lpMsgBuf );
LocalFree( lpMsgBuf );
}
///////////////////// eof ///////////////////

86
oddbits.h Executable file
View File

@ -0,0 +1,86 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ODDBITS_H
#define ODDBITS_H
#include "assert.h"
#define SAFEFREE(arg) if (arg){free(arg);arg=0;}
#define ZEROMEM(arg) memset(arg, 0, sizeof(arg))
#define ASSERT assert
#ifdef _DEBUG
#define VERIFY(arg) ASSERT(arg)
#else
#define VERIFY(arg) arg
#endif
char *va(char *format, ...);
bool FileExists (LPCSTR psFilename);
void ErrorBox(const char *sString);
void InfoBox(const char *sString);
void WarningBox(const char *sString);
#define GetYesNo(psQuery) (!!(MessageBox(mdview.hwnd,psQuery,"Query",MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES))
char *scGetTempPath(void);
char *InputLoadFileName(char *psInitialLoadName, char *psCaption, const char *psInitialDir, char *psFilter);
long filesize(FILE *handle);
int LoadFile (LPCSTR psPathedFilename, void **bufferptr);
//void Filename_RemoveBASEQ(CString &string);
//void Filename_RemoveFilename(CString &string);
//void Filename_BaseOnly(CString &string);
//void Filename_AccountForLOD(CString &string, int iLODLevel);
char *Filename_WithoutPath(LPCSTR psFilename);
char *Filename_WithoutExt(LPCSTR psFilename);
char *Filename_PathOnly(LPCSTR psFilename);
char *Filename_ExtOnly(LPCSTR psFilename);
char *String_ToLower(LPCSTR psString);
char *String_ToUpper(LPCSTR psString);
char *String_Neaten(LPCSTR psString);
char *String_NeatenEveryWord(LPCSTR psString);
char *String_Replace(char *psString, char *psFind, char *psReplace, BOOL bCaseInSensitive);
char *String_GetField(char *psString);
char *String_LoseField(char *psString);
char *String_LoseWhitespace(char *psString);
char *String_LoseLeadingWhitespace(char *psString);
char *String_LoseTrailingWhitespace(char *psString);
char *String_EnsureTrailingChar(char *psString, char c);
char *String_LoseTrailingChar(char *psString, char c);
char *String_LoseComment(char *psString);
char *String_LoseNewline(char *psString);
char *String_EnsureMinLength(LPCSTR psString, int iMinLength);
int RunningNT(void);
#define StartWait() HCURSOR hcurSave = SetCursor(::LoadCursor(NULL, IDC_WAIT))
#define RestoreWait() SetCursor(::LoadCursor(NULL, IDC_WAIT))
#define EndWait() SetCursor(hcurSave)
#define STL_ITERATE_DECL(iter, dataname) for (dataname##_t::iterator iter = dataname.begin(); iter!=dataname.end(); ++iter)
#define STL_ITERATE(iter, dataname) for (iter = dataname.begin(); iter!=dataname.end(); ++iter)
void SystemErrorBox(DWORD dwError = GetLastError());
#endif // #ifndef ODDBITS_H
/////////////////// eof ////////////////////

846
png/png.cpp Executable file
View File

@ -0,0 +1,846 @@
// Generic PNG file loading code
#include "../system.h"
#include "../oddbits.h"
int LongSwap (int l)
{
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
#define BigLong(x) LongSwap(x)
// Generic PNG file loading code
//
//#include "../renderer/tr_local.h"
//
#include "png.h"
#include "../zlib/zlib.h"
// Error returns
#define PNG_ERROR_OK 0
#define PNG_ERROR_DECOMP 1
#define PNG_ERROR_COMP 2
#define PNG_ERROR_MEMORY 3
#define PNG_ERROR_NOSIG 4
#define PNG_ERROR_TOO_SMALL 5
#define PNG_ERROR_WNP2 6
#define PNG_ERROR_HNP2 7
#define PNG_ERROR_NOT_TC 8
#define PNG_ERROR_INV_FIL 9
#define PNG_ERROR_FAILED_CRC 10
#define PNG_ERROR_CREATE_FAIL 11
#define PNG_ERROR_WRITE 12
static int png_error = PNG_ERROR_OK;
static const byte png_signature[8] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
static const char png_copyright[] = "Copyright\0Raven Software Inc. 2000";
static const char *png_errors[] =
{
"OK.",
"Error decompressing image data.",
"Error compressing image data.",
"Error allocating memory.",
"PNG signature not found.",
"Image is too small to load.",
"Width is not a power of two.",
"Height is not a power of two.",
"Image is not 24 or 32 bit.",
"Invalid filter or compression type.",
"Failed CRC check.",
"Could not create file.",
"Error writing to file.",
};
// Gets the error string for a failed PNG operation
const char *PNG_GetError(void)
{
return(png_errors[png_error]);
}
// Create a header chunk
void PNG_CreateHeader(png_ihdr_t *header, png_image_t *image)
{
header->width = BigLong(image->width);
header->height = BigLong(image->height);
header->bitdepth = 8;
if(image->bytedepth == 3)
{
header->colortype = 2;
}
if(image->bytedepth == 4)
{
header->colortype = 6;
}
header->compression = 0;
header->filter = 0;
header->interlace = 0;
}
// Processes the header chunk and checks to see if all the data is valid
bool PNG_HandleIHDR(const byte *data, png_image_t *image)
{
png_ihdr_t *ihdr = (png_ihdr_t *)data;
image->width = BigLong(ihdr->width);
image->height = BigLong(ihdr->height);
// Make sure image is a reasonable size
if((image->width < 8) || (image->height < 8))
{
png_error = PNG_ERROR_TOO_SMALL;
return(false);
}
// Check for non power of two size
if(image->width & (image->width - 1))
{
png_error = PNG_ERROR_WNP2;
return(false);
}
if(image->height & (image->height - 1))
{
png_error = PNG_ERROR_HNP2;
return(false);
}
// Make sure we have a 24 or 32 bit image
if((ihdr->colortype != 2) && (ihdr->colortype != 6))
{
png_error = PNG_ERROR_NOT_TC;
return(false);
}
// Make sure we aren't using any wacky compression or filter algos
if(ihdr->compression || ihdr->filter)
{
png_error = PNG_ERROR_INV_FIL;
return(false);
}
// Extract the data we need
if(ihdr->colortype == 2)
{
image->bytedepth = 3;
}
if(ihdr->colortype == 6)
{
image->bytedepth = 4;
}
return(true);
}
// Filter a row of data
void PNG_Filter(byte *out, byte filter, const byte *in, const byte *lastline, ulong rowbytes, ulong bpp)
{
ulong i;
switch(filter)
{
case PNG_FILTER_VALUE_NONE:
memcpy(out, in, rowbytes);
break;
case PNG_FILTER_VALUE_SUB:
for(i = 0; i < bpp; i++)
{
*out++ = *in++;
}
for(i = bpp; i < rowbytes; i++)
{
*out++ = *in - *(in - bpp);
in++;
}
break;
case PNG_FILTER_VALUE_UP:
for(i = 0; i < rowbytes; i++)
{
if(lastline)
{
*out++ = *in++ - *lastline++;
}
else
{
*out++ = *in++;
}
}
break;
case PNG_FILTER_VALUE_AVG:
for(i = 0; i < bpp; i++)
{
if(lastline)
{
*out++ = *in++ - (*lastline++ >> 1);
}
else
{
*out++ = *in++;
}
}
for(i = bpp; i < rowbytes; i++)
{
if(lastline)
{
*out++ = *in - ((*lastline++ + *(in - bpp)) >> 1);
}
else
{
*out++ = *in - (*(in - bpp) >> 1);
}
in++;
}
break;
case PNG_FILTER_VALUE_PAETH:
int a, b, c;
int pa, pb, pc, p;
for(i = 0; i < bpp; i++)
{
if(lastline)
{
*out++ = *in++ - *lastline++;
}
else
{
*out++ = *in++;
}
}
for(i = bpp; i < rowbytes; i++)
{
a = *(in - bpp);
c = 0;
b = 0;
if(lastline)
{
c = *(lastline - bpp);
b = *lastline++;
}
p = b - c;
pc = a - c;
pa = p < 0 ? -p : p;
pb = pc < 0 ? -pc : pc;
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
*out++ = *in++ - p;
}
break;
}
}
// Unfilters a row of data
void PNG_Unfilter(byte *out, byte filter, const byte *lastline, ulong rowbytes, ulong bpp)
{
ulong i;
switch(filter)
{
case PNG_FILTER_VALUE_NONE:
break;
case PNG_FILTER_VALUE_SUB:
out += bpp;
for(i = bpp; i < rowbytes; i++)
{
*out += *(out - bpp);
out++;
}
break;
case PNG_FILTER_VALUE_UP:
for(i = 0; i < rowbytes; i++)
{
if(lastline)
{
*out += *lastline++;
}
out++;
}
break;
case PNG_FILTER_VALUE_AVG:
for(i = 0; i < bpp; i++)
{
if(lastline)
{
*out += *lastline++ >> 1;
}
out++;
}
for(i = bpp; i < rowbytes; i++)
{
if(lastline)
{
*out += (*lastline++ + *(out - bpp)) >> 1;
}
else
{
*out += *(out - bpp) >> 1;
}
out++;
}
break;
case PNG_FILTER_VALUE_PAETH:
int a, b, c;
int pa, pb, pc, p;
for(i = 0; i < bpp; i++)
{
if(lastline)
{
*out += *lastline++;
}
out++;
}
for(i = bpp; i < rowbytes; i++)
{
a = *(out - bpp);
c = 0;
b = 0;
if(lastline)
{
c = *(lastline - bpp);
b = *lastline++;
}
p = b - c;
pc = a - c;
pa = p < 0 ? -p : p;
pb = pc < 0 ? -pc : pc;
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
*out++ += p;
}
break;
default:
break;
}
}
// Pack up the image data line by line
bool PNG_Pack(byte *out, ulong *size, ulong maxsize, png_image_t *image)
{
z_stream zdata;
z_stream zfilter;
ulong min_out, min_index, rowbytes;
ulong y, i;
const byte *lastline, *source;
// Number of bytes per row
rowbytes = image->width * image->bytedepth;
memset(&zdata, 0, sizeof(z_stream));
if(deflateInit(&zdata, Z_DEFAULT_COMPRESSION) != Z_OK)
{
png_error = PNG_ERROR_COMP;
return(false);
}
zdata.next_out = out;
zdata.avail_out = maxsize;
// Storage for temp zipped data
byte *templine = new byte [(image->width * image->bytedepth) + 128];
// Storage for filter type and filtered row
byte *workline = new byte [(image->width * image->bytedepth) + 1];
lastline = NULL;
source = image->data;
for(y = 0; y < image->height; y++)
{
// Zip total_out field is cumulative
min_out = zdata.total_out + rowbytes + 128;
min_index = 0;
for(i = 0; i < PNG_FILTER_NUM; i++)
{
if(deflateCopy(&zfilter, &zdata) != Z_OK)
{
deflateEnd(&zdata);
delete [] templine;
delete [] workline;
png_error = PNG_ERROR_COMP;
return(false);
}
zfilter.next_out = templine;
zfilter.avail_out = rowbytes + 128;
// Create filtered row to compress
workline[0] = (byte)i;
PNG_Filter(workline + 1, (byte)i, source, lastline, rowbytes, image->bytedepth);
// Compress it all in one chunk
zfilter.next_in = workline;
zfilter.avail_in = rowbytes + 1;
if(deflate(&zfilter, Z_SYNC_FLUSH) != Z_OK)
{
deflateEnd(&zdata);
delete [] templine;
delete [] workline;
png_error = PNG_ERROR_COMP;
return(false);
}
if(zfilter.total_out < min_out)
{
min_out = zfilter.total_out;
min_index = i;
}
deflateEnd(&zfilter);
}
// Refilter using the most compressable filter algo
workline[0] = (byte)min_index;
PNG_Filter(workline + 1, (byte)min_index, source, lastline, rowbytes, image->bytedepth);
zdata.next_in = workline;
zdata.avail_in = rowbytes + 1;
if(deflate(&zdata, Z_SYNC_FLUSH) != Z_OK)
{
deflateEnd(&zdata);
delete [] templine;
delete [] workline;
png_error = PNG_ERROR_COMP;
return(false);
}
lastline = source;
source += rowbytes;
}
if(deflate(&zdata, Z_FINISH) != Z_STREAM_END)
{
delete [] templine;
delete [] workline;
png_error = PNG_ERROR_COMP;
return(false);
}
*size = zdata.total_out;
deflateEnd(&zdata);
delete [] templine;
delete [] workline;
return(true);
}
// Unpack the image data, line by line
bool PNG_Unpack(const byte *data, const ulong datasize, png_image_t *image)
{
ulong rowbytes, zerror, y;
byte filter;
z_stream zdata;
byte *lastline, *out;
memset(&zdata, 0, sizeof(z_stream));
if(inflateInit(&zdata) != Z_OK)
{
png_error = PNG_ERROR_DECOMP;
return(false);
}
zdata.next_in = (byte *)data;
zdata.avail_in = datasize;
rowbytes = image->width * image->bytedepth;
lastline = NULL;
out = image->data;
for(y = 0; y < image->height; y++)
{
// Inflate a row of data
zdata.next_out = &filter;
zdata.avail_out = 1;
if(inflate(&zdata, Z_SYNC_FLUSH) != Z_OK)
{
inflateEnd(&zdata);
png_error = PNG_ERROR_DECOMP;
return(false);
}
zdata.next_out = out;
zdata.avail_out = rowbytes;
zerror = inflate(&zdata, Z_SYNC_FLUSH);
if((zerror != Z_OK) && (zerror != Z_STREAM_END))
{
inflateEnd(&zdata);
png_error = PNG_ERROR_DECOMP;
return(false);
}
// Unfilter a row of data
PNG_Unfilter(out, filter, lastline, rowbytes, image->bytedepth);
lastline = out;
out += rowbytes;
}
inflateEnd(&zdata);
return(true);
}
// Scan through all chunks and process each one
bool PNG_Load(const byte *data, ulong datasize, png_image_t *image)
{
bool moredata;
const byte *next;
byte *workspace, *work;
ulong length, type, crc, totallength;
png_error = PNG_ERROR_OK;
if(memcmp(data, png_signature, sizeof(png_signature)))
{
png_error = PNG_ERROR_NOSIG;
return(false);
}
data += sizeof(png_signature);
workspace = (byte *)malloc(datasize);
work = workspace;
totallength = 0;
moredata = true;
while(moredata)
{
length = BigLong(*(ulong *)data);
data += sizeof(ulong);
type = BigLong(*(ulong *)data);
const byte *crcbase = data;
data += sizeof(ulong);
// CRC checksum location
next = data + length + sizeof(ulong);
// CRC checksum includes header field
crc = crc32(0, crcbase, length + sizeof(ulong));
if(crc != (unsigned)BigLong(*(ulong *)(next - 4)))
{
if(image->data)
{
free(image->data);
image->data = NULL;
}
free(workspace);
png_error = PNG_ERROR_FAILED_CRC;
return(false);
}
switch(type)
{
case PNG_IHDR:
if(!PNG_HandleIHDR(data, image))
{
free(workspace);
return(false);
}
image->data = (byte *)malloc(image->width * image->height * image->bytedepth);
if(!image->data)
{
free(workspace);
png_error = PNG_ERROR_MEMORY;
return(false);
}
break;
case PNG_IDAT:
// Need to copy all the various IDAT chunks into one big one
// Everything but 3dsmax has one IDAT chunk
memcpy(work, data, length);
work += length;
totallength += length;
break;
case PNG_IEND:
if(!PNG_Unpack(workspace, totallength, image))
{
free(workspace);
free(image->data);
image->data = NULL;
return(false);
}
moredata = false;
break;
default:
break;
}
data = next;
}
free(workspace);
return(true);
}
// Outputs a crc'd chunk of PNG data
bool PNG_OutputChunk(FILE *fp, ulong type, byte *data, ulong size)
{
ulong crc, little, outcount;
// Output a standard PNG chunk - length, type, data, crc
little = BigLong(size);
outcount = fwrite(&little, 1, sizeof(little), fp);
little = BigLong(type);
crc = crc32(0, (byte *)&little, sizeof(little));
outcount += fwrite(&little, 1, sizeof(little), fp);
if(size)
{
crc = crc32(crc, data, size);
outcount += fwrite(data, 1, size, fp);
}
little = BigLong(crc);
outcount += fwrite(&little, 1, sizeof(little), fp);
if(outcount != (size + 12))
{
png_error = PNG_ERROR_WRITE;
return(false);
}
return(true);
}
// Saves a PNG format compressed image
bool PNG_Save(const char *name, png_image_t *image)
{
byte *work;
FILE *fp;
int maxsize;
ulong size, outcount;
png_ihdr_t png_header;
png_error = PNG_ERROR_OK;
// Create the file
fp = fopen(name, "wb");
if(!fp)
{
png_error = PNG_ERROR_CREATE_FAIL;
return(false);
}
// Write out the PNG signature
outcount = fwrite(png_signature, 1, sizeof(png_signature), fp);
if(outcount != sizeof(png_signature))
{
fclose(fp);
png_error = PNG_ERROR_WRITE;
return(false);
}
// Create and output a valid header
PNG_CreateHeader(&png_header, image);
if(!PNG_OutputChunk(fp, PNG_IHDR, (byte *)&png_header, sizeof(png_header)))
{
fclose(fp);
return(false);
}
// Create and output the copyright info
if(!PNG_OutputChunk(fp, PNG_tEXt, (byte *)png_copyright, sizeof(png_copyright)))
{
fclose(fp);
return(false);
}
// Max size of compressed image (source size + 0.1% + 12)
maxsize = (image->width * image->height * image->bytedepth) + 4096;
work = (byte *)malloc(maxsize);
if(!work)
{
fclose(fp);
png_error = PNG_ERROR_MEMORY;
return(false);
}
// Pack up the image data
if(!PNG_Pack(work, &size, maxsize, image))
{
free(work);
fclose(fp);
return(false);
}
// Write out the compressed image data
if(!PNG_OutputChunk(fp, PNG_IDAT, (byte *)work, size))
{
free(work);
fclose(fp);
return(false);
}
free(work);
// Output terminating chunk
if(!PNG_OutputChunk(fp, PNG_IEND, NULL, 0))
{
fclose(fp);
return(false);
}
fclose(fp);
return(true);
}
// Prints out the relevant info regarding a PNG file
bool PNG_Info(const byte *data, ulong datasize, png_image_t *image)
{
bool moredata;
const byte *next;
ulong length, type, crc;
png_error = PNG_ERROR_OK;
printf("Checking signature.....");
if(memcmp(data, png_signature, sizeof(png_signature)))
{
printf("failed\n");
return(false);
}
data += sizeof(png_signature);
printf("OK\n\n");
moredata = true;
while(moredata)
{
printf("Chunk: ");
length = BigLong(*(ulong *)data) + sizeof(ulong);
data += sizeof(ulong);
type = BigLong(*(ulong *)data);
const byte *crcbase = data;
data += sizeof(ulong);
printf("%c%c%c%c ", type >> 24, type >> 16, type >> 8, type);
printf("Length: %8d ", length - sizeof(ulong));
// CRC checksum location
next = data + length;
// CRC checksum includes header field
crc = crc32(0, crcbase, length);
printf("CRC 0x%x ", crc);
if(crc != (unsigned)BigLong(*(ulong *)(next - 4)))
{
printf("failed\n");
png_error = PNG_ERROR_FAILED_CRC;
return(false);
}
printf("passed\n");
switch(type)
{
case PNG_IHDR:
if(!PNG_HandleIHDR(data, image))
{
return(false);
}
break;
case PNG_IDAT:
break;
case PNG_IEND:
moredata = false;
break;
default:
break;
}
data = next;
}
printf("\nDimensions: %d x %d x %d\n", image->width, image->height, image->bytedepth * 8);
printf("\nAll chunks processed OK.\n\n");
return(true);
}
/*
=============
PNG_ConvertTo32
=============
*/
void PNG_ConvertTo32(png_image_t *image)
{
byte *temp;
byte *old, *old2;
ulong i;
temp = (byte *)malloc(image->width * image->height * 4);
old = image->data;
old2 = old;
image->data = temp;
image->bytedepth = 4;
for(i = 0; i < image->width * image->height; i++)
{
*temp++ = *old++;
*temp++ = *old++;
*temp++ = *old++;
*temp++ = 0xff;
}
free(old2);
}
/*
=============
LoadPNG32
=============
*/
bool LoadPNG32 (const char *name, byte **pixels, int *width, int *height, int *bytedepth)
{
byte *buffer;
byte **bufferptr = &buffer;
int nLen;
png_image_t png_image;
if(!pixels)
{
bufferptr = NULL;
}
//nLen = ri.FS_ReadFile ( ( char * ) name, (void **)bufferptr);
nLen = LoadFile (name, (void **)bufferptr);
if (nLen == -1)
{
ErrorBox(va("Couldn't read %s\n", name));
if(pixels)
{
*pixels = NULL;
}
return(false);
}
if(!pixels)
{
return(true);
}
*pixels = NULL;
if(!PNG_Load(buffer, nLen, &png_image))
{
ErrorBox(va("Error parsing %s: %s\n", name, PNG_GetError()));
return(false);
}
if(png_image.bytedepth != 4)
{
PNG_ConvertTo32(&png_image);
}
*pixels = png_image.data;
if(width)
{
*width = png_image.width;
}
if(height)
{
*height = png_image.height;
}
if(bytedepth)
{
*bytedepth = png_image.bytedepth;
}
//ri.FS_FreeFile(buffer);
free(buffer);
return(true);
}
// end

67
png/png.h Executable file
View File

@ -0,0 +1,67 @@
// Known chunk types
#define PNG_IHDR 'IHDR'
#define PNG_IDAT 'IDAT'
#define PNG_IEND 'IEND'
#define PNG_tEXt 'tEXt'
#define PNG_PLTE 'PLTE'
#define PNG_bKGD 'bKGD'
#define PNG_cHRM 'cHRM'
#define PNG_gAMA 'gAMA'
#define PNG_hIST 'hIST'
#define PNG_iCCP 'iCCP'
#define PNG_iTXt 'iTXt'
#define PNG_oFFs 'oFFs'
#define PNG_pCAL 'pCAL'
#define PNG_sCAL 'sCAL'
#define PNG_pHYs 'pHYs'
#define PNG_sBIT 'sBIT'
#define PNG_sPLT 'sPLT'
#define PNG_sRGB 'sRGB'
#define PNG_tIME 'tIME'
#define PNG_tRNS 'tRNS'
#define PNG_zTXt 'zTXt'
// Filter values
#define PNG_FILTER_VALUE_NONE 0
#define PNG_FILTER_VALUE_SUB 1
#define PNG_FILTER_VALUE_UP 2
#define PNG_FILTER_VALUE_AVG 3
#define PNG_FILTER_VALUE_PAETH 4
#define PNG_FILTER_NUM 5
// Common defines and typedefs
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long ulong;
#pragma pack(push)
#pragma pack(1)
typedef struct png_ihdr_s
{
ulong width;
ulong height;
byte bitdepth; // Bits per sample (not per pixel)
byte colortype; // bit 0 - palette; bit 1 - RGB; bit 2 - alpha channel
byte compression; // 0 for zip - error otherwise
byte filter; // 0 for adaptive with the 5 basic types - error otherwise
byte interlace; // 0 for no interlace - 1 for Adam7 interlace
} png_ihdr_t;
#pragma pack(pop)
typedef struct png_image_s
{
byte *data;
ulong width;
ulong height;
ulong bytedepth;
} png_image_t;
bool LoadPNG32 (const char *name, byte **pixels, int *width, int *height, int *bytedepth);
// end

85
resource.h Executable file
View File

@ -0,0 +1,85 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by MD3View.rc
//
#define IDS_FILESTRING 1
#define IDS_RAWFILEFILTER 2
#define TAG_MENU_ID 3
#define IDS_SKINFILEFILTER 3
#define IDS_UPPERANIM 4
#define IDS_MD3FILEFILTER 4
#define IDS_LOWERANIM 5
#define IDS_SEQFILTER 5
#define IDR_MENU1 101
#define IDI_APP 102
#define IDR_ACCELERATOR1 105
#define ID_FILE_EXIT 40002
#define ID_ABOUT 40003
#define ID_VIEW_WIREFRAME 40004
#define ID_VIEW_FLATSHADED 40005
#define ID_VIEW_TEXTURED 40006
#define ID_VIEW_TEXTUREDSHADED 40007
#define ID_VIEW_NEAREST 40008
#define ID_VIEW_UNFILTEREDTEXTURE 40010
#define ID_VIEW_FILTEREDTEXTURE 40011
#define ID_VIEW_FLIPFACESIDES 40012
#define ID_ANIMATION_SLOWER 40013
#define ID_ANIMATION_FASTER 40014
#define ID_ANIMATION_STOP 40015
#define ID_ANIMATION_START 40016
#define ID_ANIMATION_REWIND 40017
#define ID_ANIMATION_INTERPOLATE 40018
#define ID_FILE_EXPORTTORAW 40019
#define ID_FILE_IMPORTSKIN 40020
#define ID_VIEW_REFRESHTEXTURE 40021
#define ID_FRAME_UP 40022
#define ID_FRAME_DW 40023
#define ID_VIEW_LOADEDSTUFF 40024
#define ID_LOD0 40025
#define ID_LOD1 40026
#define ID_LOD2 40027
#define ID_FACE_INCANIM 40028
#define ID_FACE_DECANIM 40029
#define ID_FACE_RESANIM 40030
#define ID_VIEWAXIS 40031
#define ID_VIEWLOWERANIM_INC 40032
#define ID_VIEWLOWERANIM_DEC 40033
#define ID_VIEWLOWERANIM_LOCK 40034
#define ID_VIEWUPPERANIM_INC 40035
#define ID_VIEWUPPERANIM_DEC 40036
#define ID_VIEWUPPERANIM_LOCK 40037
#define ID_FILE_SAVE_MD3 40039
#define ID_FILE_IMPORTMULTISEQ 40040
#define ID_VIEWALPHA 40041
#define ID_SCREENSHOT_CLIPBOARD 40042
#define ID_SCREENSHOT_FILE 40043
#define ID_VIEW_COLOURPICKER 40044
#define ID_VIEW_FOVTOGGLE 40045
#define ID_FILE_SAVE_G2 40046
#define ID_PICMIP0 40047
#define ID_PICMIP1 40048
#define ID_PICMIP2 40049
#define ID_PICMIP3 40050
#define ID_PICMIP4 40051
#define ID_PICMIP5 40052
#define ID_PICMIP6 40053
#define ID_PICMIP7 40054
#define ID_VIEWPOS_RESET 40055
#define ID_VIEW_TEXTUREDWIREFRAME 40056
#define ID_VIEW_BOUNDSTOGGLE 40057
#define ID_FILE_SAVE_G2_PERFECT 40058
#define ID_TAG_START 50000
#define ID_MENUITEMS_UPPERANIMS 60000
#define ID_MENUITEMS_LOWERANIMS 61000
#define ID_MENUITEMS_NEXT 62000
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 106
#define _APS_NEXT_COMMAND_VALUE 40059
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

25
stdafx.h Executable file
View File

@ -0,0 +1,25 @@
// 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__2CCA5546_2AD3_11D3_82E0_0000C0366FF2__INCLUDED_)
#define AFX_STDAFX_H__2CCA5546_2AD3_11D3_82E0_0000C0366FF2__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 <afxdisp.h> // MFC Automation classes
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#include <afxcmn.h> // MFC support for Windows Common Controls
#include <afxcview.h>
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__2CCA5546_2AD3_11D3_82E0_0000C0366FF2__INCLUDED_)

77
system.h Executable file
View File

@ -0,0 +1,77 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SYSTEM_H_
#define _SYSTEM_H_
/*
system dependent function exported to the rest of the application
redefine these for each platform being ported
*/
#ifdef WIN32
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_WARNINGS
#include <windows.h>
#include <windowsx.h>
#endif
#include <GL\gl.h>
#include <GL\glu.h>
#include <iostream>
#include <memory.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
double getDoubleTime (void);
void repaint_main();
void set_cursor( int x, int y );
bool file_exists( LPCSTR fname );
char *getCmdLine();
void FreeCmdLine();
void swap_buffers();
typedef int GLMODEL_DBLPTR;
void tagMenu_append( char *name, GLMODEL_DBLPTR model );
void tagMenu_seperatorAppend( char *name );
void tagMenu_remove( GLMODEL_DBLPTR tagid );
#include "Error.h"
#include "Base.h"
#include "BaseMesh.h"
//
// I did it this way to avoid other modules having to know about HMENUs...
//
void Menu_UpperAnims_Clear(void);
void Menu_LowerAnims_Clear(void);
void Menu_UpperAnims_AddItem(LPCSTR psItem);
void Menu_LowerAnims_AddItem(LPCSTR psItem);
#ifndef g_iScreenWidth
#include "text.h"
#endif
bool ScreenShot(LPCSTR psFilename = NULL, LPCSTR psCopyrightMessage = NULL, int iWidth = g_iScreenWidth, int iHeight = g_iScreenHeight);
#endif

273
targa.cpp Executable file
View File

@ -0,0 +1,273 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.h"
#include "DiskIO.h"
#include "Targa.h"
#include "jpeg_interface.h"
typedef unsigned char byte;
struct TargaHeader {
unsigned char id_length, colormap_type, image_type;
unsigned short colormap_index, colormap_length;
unsigned char colormap_size;
unsigned short x_origin, y_origin, width, height;
unsigned char pixel_size, attributes;
};
void Error (char *error, ...);
void Debug (char *error, ...);
struct wordByte
{
unsigned char byte1;
unsigned char byte2;
};
union wordByteUnion
{
short word;
wordByte b;
};
/*
=======
accepts RGB format data in pixels and writes it uncompressed into file
=======
*/
void writeTGA( char *name, byte *pixels, int width, int height)
{
TargaHeader targa_header;
FILE *fin;
fin = fopen( name, "wb" );
if (!fin) {
Debug( "Coulnd't open file for writing" );
return;
}
memset( &targa_header, 0, sizeof( TargaHeader ) );
fputc( 0, fin ); //targa_header.id_length = 0;
fputc( 0, fin ); //targa_header.colormap_type = 0;
fputc( 2, fin ); //targa_header.image_type = 2;
put16( 0, fin ); //targa_header.colormap_index = 0;
put16( 0, fin ); //targa_header.colormap_length = 0;
fputc( 0, fin ); //targa_header.colormap_size = 0;
put16( 0,fin ); //targa_header.x_origin = 0;
put16( 0, fin ); //targa_header.y_origin = 0;
put16( width, fin );
put16( height,fin );
fputc( 24, fin ); //targa_header.pixel_size = 24 ;
fputc( 0, fin ); //targa_header.attributes = 0;
for (int i = 0; i < width*height*3; i+= 3)
{
fputc( (int)pixels[i+2], fin );
fputc( (int)pixels[i+1], fin );
fputc( (int)pixels[i], fin );
}
fclose(fin);
}
// now attempts to load a JPG if TGA load fails...
//
// (return value sent to "*format" param isn't actually used anywhere)
//
bool loadTGA (char *name, byte **pixels, unsigned int *width, unsigned int *height, unsigned int *format)
{
int columns, rows, numPixels;
byte *pixbuf;
int row, column;
FILE *fin;
byte *targa_rgba;
TargaHeader targa_header;
fin = fopen (name, "rb");
if (!fin) //Debug( "Couldn't read textures" );
{
char sLine[256];
strcpy(sLine,name);
strlwr(sLine);
char *p = strstr(sLine,".tga");
if (p)
{
strcpy(p,".jpg");
LoadJPG( sLine, pixels, (int*)width, (int*)height );
if (*pixels)
return true;
}
return false;
}
targa_header.id_length = fgetc(fin);
targa_header.colormap_type = fgetc(fin);
targa_header.image_type = fgetc(fin);
targa_header.colormap_index = get16(fin);
targa_header.colormap_length = get16(fin);
targa_header.colormap_size = fgetc(fin);
targa_header.x_origin = get16(fin);
targa_header.y_origin = get16(fin);
targa_header.width = get16(fin);
targa_header.height = get16(fin);
targa_header.pixel_size = fgetc(fin);
targa_header.attributes = fgetc(fin);
if (targa_header.image_type!=2
&& targa_header.image_type!=10)
Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
if (targa_header.colormap_type !=0
|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
*format = targa_header.pixel_size;
columns = targa_header.width;
rows = targa_header.height;
numPixels = columns * rows;
if (width)
*width = columns;
if (height)
*height = rows;
targa_rgba = new unsigned char[numPixels*4];
*pixels = targa_rgba;
if (targa_header.id_length != 0)
fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment
if (targa_header.image_type==2) { // Uncompressed, RGB images
for(row=rows-1; row>=0; row--) {
pixbuf = targa_rgba + row*columns*4;
for(column=0; column<columns; column++) {
unsigned char red,green,blue,alphabyte;
switch (targa_header.pixel_size) {
case 24:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
alphabyte = getc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
break;
}
}
}
}
else if (targa_header.image_type==10) { // Runlength encoded RGB images
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
for(row=rows-1; row>=0; row--) {
pixbuf = targa_rgba + row*columns*4;
for(column=0; column<columns; ) {
packetHeader=getc(fin);
packetSize = 1 + (packetHeader & 0x7f);
if (packetHeader & 0x80) { // run-length packet
switch (targa_header.pixel_size) {
case 24:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
alphabyte = 255;
break;
case 32:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
alphabyte = getc(fin);
break;
}
for(j=0;j<packetSize;j++) {
*pixbuf++=red;
*pixbuf++=green;
*pixbuf++=blue;
*pixbuf++=alphabyte;
column++;
if (column==columns) { // run spans across rows
column=0;
if (row>0)
row--;
else
goto breakOut;
pixbuf = targa_rgba + row*columns*4;
}
}
}
else { // non run-length packet
for(j=0;j<packetSize;j++) {
switch (targa_header.pixel_size) {
case 24:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = getc(fin);
green = getc(fin);
red = getc(fin);
alphabyte = getc(fin);
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
break;
}
column++;
if (column==columns) { // pixel packet run spans across rows
column=0;
if (row>0)
row--;
else
goto breakOut;
pixbuf = targa_rgba + row*columns*4;
}
}
}
}
breakOut:;
}
}
fclose(fin);
return true;
}

1114
texture_res.cpp Executable file

File diff suppressed because it is too large Load Diff

125
vect3.cpp Executable file
View File

@ -0,0 +1,125 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "vect3.h"
const Vect3 Vect3X(1.f,0.f,0.f);
const Vect3 Vect3Y(0.f,1.f,0.f);
const Vect3 Vect3Z(0.f,0.f,1.f);
const Vect3 Vect3negX(-1.f,0.f,0.f);
const Vect3 Vect3negY(0.f,-1.f,0.f);
const Vect3 Vect3negZ(0.f,0.f,-1.f);
const Vect3 Vect3Zero(0.f,0.f,0.f);
const Vect3 &Vect3::operator/= (const float d)
{
float inv=1.f/d;
return (*this)*=inv;
}
void Vect3::Cross(const Vect3& p)
{
Vect3 t=*this;
v[0]=t.v[1]*p.v[2]-t.v[2]*p.v[1];
v[1]=t.v[2]*p.v[0]-t.v[0]*p.v[2];
v[2]=t.v[0]*p.v[1]-t.v[1]*p.v[0];
}
void Vect3::NegCross(const Vect3& p)
{
Vect3 t=*this;
v[0]=p.v[1]*t.v[2]-p.v[2]*t.v[1];
v[1]=p.v[2]*t.v[0]-p.v[0]*t.v[2];
v[2]=p.v[0]*t.v[1]-p.v[1]*t.v[0];
}
float Vect3::Dist(const Vect3& p) const
{
Vect3 t=*this;
t-=p;
return t.Len();
}
float Vect3::Dist2(const Vect3& p) const
{
Vect3 t=*this;
t-=p;
return t^t;
}
void Vect3::Perp()
{
float rlen,tlen;
Vect3 r,t;
r=*this;
r.Cross(Vect3X);
rlen=r.Len();
t=*this;
t.Cross(Vect3Y);
tlen=t.Len();
if (tlen>rlen)
{
r=t;
rlen=tlen;
}
t=*this;
t.Cross(Vect3Z);
tlen=t.Len();
if (tlen>rlen)
{
r=t;
rlen=tlen;
}
*this=r;
}
void Vect3::Min(const Vect3& p)
{
if (p.v[0]<v[0])
v[0]=p.v[0];
if (p.v[1]<v[1])
v[1]=p.v[1];
if (p.v[2]<v[2])
v[2]=p.v[2];
}
void Vect3::Max(const Vect3& p)
{
if (p.v[0]>v[0])
v[0]=p.v[0];
if (p.v[1]>v[1])
v[1]=p.v[1];
if (p.v[2]>v[2])
v[2]=p.v[2];
}
float Vect3::MaxElement() const
{
return v[MaxElementIndex()];
}
int Vect3::MaxElementIndex() const
{
if (fabs(v[0])>fabs(v[1])&&fabs(v[0])>fabs(v[2]))
return 0;
if (fabs(v[1])>fabs(v[2]))
return 1;
return 2;
}

110
vect3.h Executable file
View File

@ -0,0 +1,110 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(VECT3_INC)
#define VECT3_INC
#include <math.h>
#include <assert.h>
class Vect3
{
float v[3];
public:
Vect3(const float val) {v[0]=val;v[1]=val;v[2]=val;}
Vect3() {}//never put anything in here! too slow}
Vect3(const float x,const float y,const float z) {v[0]=x;v[1]=y;v[2]=z;}
Vect3(const Vect3& t) {v[0]=t.v[0];v[1]=t.v[1];v[2]=t.v[2];}
Vect3(const float *t) {v[0]=t[0];v[1]=t[1];v[2]=t[2];}
float& operator[](int i) {return v[i];}
float& x() {return v[0];}
float& y() {return v[1];}
float& z() {return v[2];}
const float& operator[](int i) const {return v[i];}
const float& x() const {return v[0];}
const float& y() const {return v[1];}
const float& z() const {return v[2];}
void Set(const float x,const float y,const float z) {v[0]=x;v[1]=y;v[2]=z;}
float Len() const {return (float)sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);}
float Len2() const {return v[0]*v[0]+v[1]*v[1]+v[2]*v[2];}
void Norm() {(*this)/=this->Len();}
bool ZeroNorm() {float d=this->Len();if (d>1E-10) {(*this)/=d;return true;} (*this)=0.0f; return false;}
void SafeNorm() {assert(this->Len()>1E-10);(*this)/=this->Len();}
const Vect3 &operator= (const float d) {v[0]=d;v[1]=d;v[2]=d; return *this; }
const Vect3 &operator= (const Vect3& t) {v[0]=t.v[0];v[1]=t.v[1];v[2]=t.v[2]; return *this; }
const Vect3 &operator+= (const float d) {v[0]+=d;v[1]+=d;v[2]+=d; return *this; }
const Vect3 &operator+= (const Vect3& t) {v[0]+=t.v[0];v[1]+=t.v[1];v[2]+=t.v[2]; return *this; }
const Vect3 &operator-= (const float d) {v[0]-=d;v[1]-=d;v[2]-=d; return *this; }
const Vect3 &operator-= (const Vect3& t) {v[0]-=t.v[0];v[1]-=t.v[1];v[2]-=t.v[2]; return *this; }
const Vect3 &operator*= (const float d) {v[0]*=d;v[1]*=d;v[2]*=d; return *this; }
const Vect3 &operator*= (const Vect3& t) {v[0]*=t.v[0];v[1]*=t.v[1];v[2]*=t.v[2]; return *this; }
const Vect3 &operator/= (const float d);
const Vect3 &operator/= (const Vect3& t) {v[0]/=t.v[0];v[1]/=t.v[1];v[2]/=t.v[2]; return *this; }
float operator^ (const Vect3& t) const {return v[0]*t.v[0]+v[1]*t.v[1]+v[2]*t.v[2];}
float Dist(const Vect3&) const;
float Dist2(const Vect3&) const;
void Cross(const Vect3&);
void NegCross(const Vect3&);
void Perp();
void Min(const Vect3&);
void Max(const Vect3&);
float MaxElement() const;
int MaxElementIndex() const;
void Interp(const Vect3 &v1,const Vect3 &v2,float t) {*this=v1;*this-=v2;*this*=t;*this+=v2;}
// bool operator== (const Vect3& t) const {return v[0]==t.v[0]&&v[1]==t.v[1]&&v[2]==t.v[2];}
bool operator== (const Vect3& t) const {return fabs(v[0]-t.v[0])<.001f&&fabs(v[1]-t.v[1])<.001f&&fabs(v[2]-t.v[2])<.001f;}
bool operator< (const Vect3& t) const {assert(0);return false;}
bool operator!= (const Vect3& t) const {return !(v[0]==t.v[0]&&v[1]==t.v[1]&&v[2]==t.v[2]);}
bool operator> (const Vect3& t) const {assert(0);return false;}
inline Vect3 operator +(const Vect3 &rhs) const { return Vect3(v[0]+rhs.v[0], v[1]+rhs.v[1], v[2]+rhs.v[2]); }
inline Vect3 operator -(const Vect3 &rhs) const { return Vect3(v[0]-rhs.v[0], v[1]-rhs.v[1], v[2]-rhs.v[2]); }
inline Vect3 operator *(const Vect3 &rhs) const { return Vect3(v[0]*rhs.v[0], v[1]*rhs.v[1], v[2]*rhs.v[2]); }
inline Vect3 operator *(const float scalar) const { return Vect3(v[0]*scalar, v[1]*scalar, v[2]*scalar); }
inline friend Vect3 operator *(const float scalar, const Vect3 &rhs);
inline Vect3 operator /(const Vect3 &rhs) const { return Vect3(v[0]/rhs.v[0], v[1]/rhs.v[1], v[2]/rhs.v[2]); }
inline Vect3 operator /(const float scalar) const { return Vect3(v[0]/scalar, v[1]/scalar, v[2]/scalar); }
};
inline Vect3 operator *(const float scalar, const Vect3 &rhs)
{
return Vect3(scalar*rhs.v[0], scalar*rhs.v[1], scalar*rhs.v[2]);
}
extern const Vect3 Vect3X;
extern const Vect3 Vect3Y;
extern const Vect3 Vect3Z;
extern const Vect3 Vect3negX;
extern const Vect3 Vect3negY;
extern const Vect3 Vect3negZ;
extern const Vect3 Vect3Zero;
#endif

91
widgets.cpp Executable file
View File

@ -0,0 +1,91 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system.h"
#include "ndictionary.h"
#include "md3gl.h"
#include "md3view.h"
void setVertex( Vec3 v, float f1, float f2, float f3 )
{
v[0] = f1;
v[1] = f2;
v[2] = f3;
}
void widget_AxisFaces( Vec3 *v )
{
glBegin( GL_TRIANGLES );
glVertex3fv( v[0] ); glVertex3fv( v[2] ); glVertex3fv( v[3] );
glVertex3fv( v[3] ); glVertex3fv( v[1] ); glVertex3fv( v[0] );
glVertex3fv( v[4] ); glVertex3fv( v[5] ); glVertex3fv( v[7] );
glVertex3fv( v[7] ); glVertex3fv( v[6] ); glVertex3fv( v[4] );
glVertex3fv( v[0] ); glVertex3fv( v[1] ); glVertex3fv( v[5] );
glVertex3fv( v[5] ); glVertex3fv( v[4] ); glVertex3fv( v[0] );
glVertex3fv( v[1] ); glVertex3fv( v[3] ); glVertex3fv( v[7] );
glVertex3fv( v[7] ); glVertex3fv( v[5] ); glVertex3fv( v[1] );
glVertex3fv( v[3] ); glVertex3fv( v[2] ); glVertex3fv( v[6] );
glVertex3fv( v[6] ); glVertex3fv( v[7] ); glVertex3fv( v[3] );
glVertex3fv( v[2] ); glVertex3fv( v[0] ); glVertex3fv( v[4] );
glVertex3fv( v[4] ); glVertex3fv( v[6] ); glVertex3fv( v[2] );
glEnd();
}
void widget_Axis()
{
Vec3 v[8];
setVertex( v[0], -1.0000, 1.0000, 0.0000 );
setVertex( v[1], 1.0000, 1.0000, 0.0000 );
setVertex( v[2], -1.0000, 1.0000, 10.0000 );
setVertex( v[3], 1.0000, 1.0000, 10.0000 );
setVertex( v[4], -1.0000, -1.0000, 0.0000 );
setVertex( v[5], 1.0000, -1.0000, 0.0000 );
setVertex( v[6], -1.0000, -1.0000, 10.0000 );
setVertex( v[7], 1.0000, -1.0000, 10.0000 );
glColor3f( 0, 0, 1 );
widget_AxisFaces( v );
setVertex( v[0], -1.0000, 0.0000, 1.0000 );
setVertex( v[1], 1.0000, 0.0000, 1.0000 );
setVertex( v[2], -1.0000, 10.0000, 1.0000 );
setVertex( v[3], 1.0000, 10.0000, 1.0000 );
setVertex( v[4], -1.0000, 0.0000, -1.0000 );
setVertex( v[5], 1.0000, 0.0000, -1.0000 );
setVertex( v[6], -1.0000, 10.0000, -1.0000 );
setVertex( v[7], 1.0000, 10.0000, -1.0000 );
glColor3f( 0, 1, 0 );
widget_AxisFaces( v );
setVertex( v[0], 0.0000, -1.0000, 1.0000 );
setVertex( v[1], 0.0000, 1.0000, 1.0000 );
setVertex( v[2], 10.0000, -1.0000, 1.0000 );
setVertex( v[3], 10.0000, 1.0000, 1.0000 );
setVertex( v[4], 0.0000, -1.0000, -1.0000 );
setVertex( v[5], 0.0000, 1.0000, -1.0000 );
setVertex( v[6], 10.0000, -1.0000, -1.0000 );
setVertex( v[7], 10.0000, 1.0000, -1.0000 );
glColor3f( 1, 0, 0 );
widget_AxisFaces( v );
}

523
win32_driver.cpp Executable file
View File

@ -0,0 +1,523 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
win32 specific driver file:
this include the WinMain function and all the code to initialize the win32 gui
look for comments in md3view.h to see how the viewer system independent code needs to be
initialized and used in the framwork
*/
#ifdef WIN32
#include "system.h"
#include "ndictionary.h"
#include "md3gl.h"
#include "md3view.h"
#include "resource.h"
#include "AFXRES.H"
#include "oddbits.h"
#include "bmp.h"
HINSTANCE WinhInstance;
HWND mainhWnd;
char* CmdLine = NULL;
#define WINDOW_STYLE WS_OVERLAPPEDWINDOW
// system specific event handler functions
bool SysOnCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct);
int SysOnDestroy(HWND hWnd);
void SysOnMouseMove(HWND hwnd, int x, int y, UINT keyFlags);
void SysOnRButtonUp(HWND hwnd, int x, int y, UINT flags);
void SysOnLButtonUp(HWND hwnd, int x, int y, UINT flags);
void SysOnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
void SysOnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags);
void SysOnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
void SysOnKeyDown(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags);
void SysOnKeyUp(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags);
void SysOnPaint( HWND hwnd, bool bFlip = true );
void SysOnSize(HWND hwnd, UINT state, int cx, int cy);
void SysOnIdle();
NodeSequenceInfo tagMenuList;
/*
add a seperator
*/
void tagMenu_seperatorAppend( char *name )
{
char newname[512];
strcpy( newname, "...");
strcat( newname, name );
strcat( newname, "...");
char *n = new char[strlen(newname)+1];
strcpy( n, newname );
HMENU subMenu = GetSubMenu( GetMenu(mdview.hwnd), TAG_MENU_ID );
AppendMenu( subMenu, MF_DISABLED|MF_STRING, ID_TAG_START+tagMenuList.size(), n );
tagMenuList.insertLast( (Object)NULL );
}
/*
remove a tag entry from the menu
*/
void tagMenu_remove( GLMODEL_DBLPTR tagid )
{
NodePosition pos;
GLMODEL_DBLPTR dblptr;
int i=1;
bool remove=false;
// get the tag menu position
for (pos=tagMenuList.first() ; pos!=NULL ; pos=tagMenuList.after(pos)) {
dblptr = (GLMODEL_DBLPTR)pos->element();
if (dblptr == tagid) break;
i++;
}
// return if not found
if (!pos) return;
// remove the menu
HMENU subMenu = GetSubMenu( GetMenu(mdview.hwnd), TAG_MENU_ID );
DeleteMenu( subMenu, i, MF_BYPOSITION );
// see if this is the last tag entry in a block
// if so remove the seperator
NodePosition b = tagMenuList.before(pos);
NodePosition a = tagMenuList.after(pos);
if (b==0) {
if (a==0) remove = true;
else if (a->element() == 0) remove = true;
}
else if (b->element() == 0) {
if (a==0) remove = true;
else if (a->element() == 0) remove = true;
}
if (remove) {
DeleteMenu( subMenu, i-1, MF_BYPOSITION );
tagMenuList.remove( b );
}
// remove the pos from list
tagMenuList.remove( pos );
}
/*
add a tag to the menu
*/
void tagMenu_append( char *name, GLMODEL_DBLPTR model )
{
char *n = new char[strlen(name)+1];
strcpy( n, name );
HMENU subMenu = GetSubMenu( GetMenu(mdview.hwnd), TAG_MENU_ID );
AppendMenu( subMenu, MF_ENABLED|MF_STRING, ID_TAG_START+tagMenuList.size(), n );
tagMenuList.insertLast( (Object)model );
}
void swap_buffers()
{
SwapBuffers( mdview.hdc );
}
char *getCmdLine()
{
return CmdLine;
}
void FreeCmdLine()
{
if (CmdLine)
{
delete [] CmdLine;
CmdLine = NULL;
}
}
bool file_exists( LPCSTR fname )
{
if (!fname) return false;
FILE *f = fopen( fname, "r" );
if (f) {
fclose(f);
return true;
}
else {
return false;
}
}
void repaint_main()
{
InvalidateRect( mdview.hwnd, NULL, FALSE );
}
void set_cursor( int x, int y )
{
SetCursorPos( x, y );
}
/*
time measuring stuff
*/
double getDoubleTime (void)
{
return (double)clock() / (double)CLOCKS_PER_SEC;
}
/*
main event handler
*/
// event handler itself
LONG WINAPI WinProcInstance(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
HANDLE_MSG( hwnd, WM_DESTROY, SysOnDestroy );
HANDLE_MSG( hwnd, WM_CLOSE, SysOnDestroy );
HANDLE_MSG( hwnd, WM_CREATE, SysOnCreate );
HANDLE_MSG( hwnd, WM_PAINT, SysOnPaint );
HANDLE_MSG( hwnd, WM_SIZE, SysOnSize );
HANDLE_MSG( hwnd, WM_COMMAND, SysOnCommand );
HANDLE_MSG( hwnd, WM_LBUTTONDOWN, SysOnLButtonDown );
HANDLE_MSG( hwnd, WM_RBUTTONDOWN, SysOnRButtonDown );
HANDLE_MSG( hwnd, WM_LBUTTONUP, SysOnLButtonUp );
HANDLE_MSG( hwnd, WM_RBUTTONUP, SysOnRButtonUp );
HANDLE_MSG( hwnd, WM_KEYDOWN, SysOnKeyDown );
HANDLE_MSG( hwnd, WM_KEYUP, SysOnKeyUp );
case WM_MOUSEMOVE:
{
SysOnMouseMove(hwnd, (int)(short)LOWORD(lParam),(int)(short)HIWORD(lParam),(UINT)(wParam));
return 0L;
}
default:
return(DefWindowProc(hwnd, message, wParam, lParam));
}
}
HMENU hMainMenu = NULL;
HMENU hMenuUpperAnims = NULL;
HMENU hMenuLowerAnims = NULL;
// clears menu, then adds items "none" and seperator...
//
void Menu_Clear(HMENU hMenu, int iBaseID)
{
if ( hMenu )
{
int iCount = GetMenuItemCount( hMenu );
for (int i=iCount-1; i>=0; i--)
{
VERIFY(DeleteMenu( hMenu, i, MF_BYPOSITION));
}
DrawMenuBar(mainhWnd);
// add default "choose seq" and "choose multi-seq", then a seperator...
//
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_STRING, // UINT uFlags, // menu-item flags
iBaseID + 0, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
"** Choose Seq **" // LPCTSTR lpNewItem // menu-item content
);
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_STRING, // UINT uFlags, // menu-item flags
iBaseID + 1, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
"** Choose Multi-Seq **" // LPCTSTR lpNewItem // menu-item content
);
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_SEPARATOR, // UINT uFlags, // menu-item flags
NULL, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
NULL // LPCTSTR lpNewItem // menu-item content
);
// now add a default "none" and a seperator...
//
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_STRING, // UINT uFlags, // menu-item flags
iBaseID + 2, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
"(none)" // LPCTSTR lpNewItem // menu-item content
);
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_SEPARATOR, // UINT uFlags, // menu-item flags
NULL, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
NULL // LPCTSTR lpNewItem // menu-item content
);
DrawMenuBar(mainhWnd);
iCount = GetMenuItemCount( hMenu );
}
}
void Menu_AddItem(HMENU hMenu, int iBaseID, LPCSTR psItem)
{
if ( hMenu )
{
int iID = GetMenuItemCount( hMenu );
iID-= 2; // compensate for 2 seperators, now this is ID of next we're about to add
AppendMenu( hMenu, // HMENU hMenu, // handle to menu to be changed
MF_STRING, // UINT uFlags, // menu-item flags
iBaseID + iID, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
psItem // LPCTSTR lpNewItem // menu-item content
);
DrawMenuBar(mainhWnd);
}
}
void Menu_UpperAnims_Clear(void)
{
Menu_Clear( hMenuUpperAnims, ID_MENUITEMS_UPPERANIMS );
}
void Menu_LowerAnims_Clear(void)
{
Menu_Clear( hMenuLowerAnims, ID_MENUITEMS_LOWERANIMS );
}
void Menu_UpperAnims_AddItem(LPCSTR psItem)
{
Menu_AddItem( hMenuUpperAnims, ID_MENUITEMS_UPPERANIMS, psItem );
}
void Menu_LowerAnims_AddItem(LPCSTR psItem)
{
Menu_AddItem( hMenuLowerAnims, ID_MENUITEMS_LOWERANIMS, psItem );
}
/*
creates window
*/
void WindowSystemInit( HINSTANCE hInstance )
{
WNDCLASS wc;
memset (&wc, 0, sizeof(wc));
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)WinProcInstance;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "mainWindow";
RegisterClass(&wc);
mainhWnd = CreateWindow (
"mainWindow" ,
FILENAME,
WINDOW_STYLE,
0, 0,
1000, // unfortunately I can't just #ifdef these 2 lines because CreateWindow is also a macro and C can't nest 'em... <sigh>
600, //
0,
LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENU1)),
hInstance,
NULL);
ShowWindow ( mainhWnd, SW_SHOW );
UpdateWindow ( mainhWnd );
hMainMenu = GetMenu(mainhWnd);
hMenuUpperAnims = CreateMenu();
hMenuLowerAnims = CreateMenu();
AppendMenu( hMainMenu, // HMENU hMenu, // handle to menu to be changed
MF_POPUP|MF_STRING, // UINT uFlags, // menu-item flags
(UINT_PTR) hMenuUpperAnims, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
"(Upper Anim Sequences)" // LPCTSTR lpNewItem // menu-item content
);
AppendMenu( hMainMenu, // HMENU hMenu, // handle to menu to be changed
MF_POPUP|MF_STRING, // UINT uFlags, // menu-item flags
(UINT_PTR) hMenuLowerAnims, // UINT_PTR uIDNewItem, // menu-item identifier or handle to drop-down menu or submenu
"(Lower Anim Sequences)" // LPCTSTR lpNewItem // menu-item content
);
Menu_UpperAnims_Clear();
Menu_LowerAnims_Clear();
DrawMenuBar(mainhWnd);
if (getCmdLine() != NULL )
{
SysOnCommand(mainhWnd, ID_FILE_OPEN, 0, 0);
// if (!loadmdl( getCmdLine() )) {
// Debug( "could not load %s", getCmdLine() );
}
}
/*
initializes app
calls
*/
void Init( HINSTANCE hInstance )
{
WindowSystemInit( hInstance );
}
/*
main program entry point
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
if ( ( lpCmdLine != NULL ) &&
( lpCmdLine[0] != '\0' ) )
{
CmdLine = new char[strlen(lpCmdLine)+1];
strcpy(CmdLine,lpCmdLine);
// sometimes the OS puts quotes around the whole command line (duh!!!!), so get rid of them...
//
if (CmdLine[0]=='"' && CmdLine[strlen(CmdLine)-1]=='"')
{
strcpy(CmdLine,lpCmdLine+1);
CmdLine[strlen(CmdLine)-1]=0;
}
while (strchr(CmdLine,'/')) *strchr(CmdLine,'/')='\\';
}
WinhInstance = hInstance;
/* initilizes mdview data */
init_mdview(lpCmdLine);
Init( hInstance );
mdview.done = false;
// main message loop
while (!mdview.done)
{
SysOnIdle();
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage (&msg);
TranslateAccelerator( mainhWnd, LoadAccelerators( hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1)), &msg );
DispatchMessage (&msg);
}
}
shutdown_mdviewdata();
return 1;
}
// 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;
}
#endif

1649
win32_msg.cpp Executable file

File diff suppressed because it is too large Load Diff

58
win32_treeview.cpp Executable file
View File

@ -0,0 +1,58 @@
/*
Copyright (C) 2010 Matthew Baranowski, Sander van Rossen & Raven software.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef WIN32
#include <windows.h>
#endif
class Core
{
public:
Core( int argc, char **argv );
void exec();
private:
};
class Event;
class Window
{
public:
Window( Window *parent=NULL, int style=0, const char *label=NULL );
virtual ~Window();
void setGeometry( int x, int y, int w, int h );
virtual void repaint();
virtual void event( Event *evt );
private:
#ifdef WIN32
HWND g_hwnd;
HDC g_hdc;
#endif
};
class WindowTreeView
{
public:
private:
};

48
zlib/adler32.c Executable file
View File

@ -0,0 +1,48 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#include "../zlib/zlib.h"
#define BASE 65521L /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#define DO16(buf) DO8(buf,0); DO8(buf,8);
/* ========================================================================= */
uLong ZEXPORT adler32(adler, buf, len)
uLong adler;
const Bytef *buf;
uInt len;
{
unsigned long s1 = adler & 0xffff;
unsigned long s2 = (adler >> 16) & 0xffff;
int k;
if (buf == Z_NULL) return 1L;
while (len > 0) {
k = len < NMAX ? len : NMAX;
len -= k;
while (k >= 16) {
DO16(buf);
buf += 16;
k -= 16;
}
if (k != 0) do {
s1 += *buf++;
s2 += s1;
} while (--k);
s1 %= BASE;
s2 %= BASE;
}
return (s2 << 16) | s1;
}

98
zlib/crc32.cpp Executable file
View File

@ -0,0 +1,98 @@
/* crc32.c -- compute the CRC-32 of a data stream
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id: unzip.c,v 1.2 1999/09/07 20:51:25 zoid Exp $ */
/* ========================================================================
* Table of CRC-32's of all single-byte values (made by make_crc_table)
*/
#include "../zlib/zlib.h"
static const uLong crc_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
/* =========================================================================
* This function can be used by asm versions of crc32()
*/
const uLong * get_crc_table()
{
return (const uLong *)crc_table;
}
/* ========================================================================= */
#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
#define DO2(buf) DO1(buf); DO1(buf);
#define DO4(buf) DO2(buf); DO2(buf);
#define DO8(buf) DO4(buf); DO4(buf);
/* ========================================================================= */
uLong crc32(uLong crc, const Byte *buf, uInt len)
{
if (buf == Z_NULL) return 0L;
crc = crc ^ 0xffffffffL;
while (len >= 8)
{
DO8(buf);
len -= 8;
}
if (len) do {
DO1(buf);
} while (--len);
return crc ^ 0xffffffffL;
}
// end

1350
zlib/deflate.c Executable file

File diff suppressed because it is too large Load Diff

318
zlib/deflate.h Executable file
View File

@ -0,0 +1,318 @@
/* deflate.h -- internal compression state
* Copyright (C) 1995-1998 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
/* @(#) $Id$ */
#ifndef _DEFLATE_H
#define _DEFLATE_H
#include "zutil.h"
/* ===========================================================================
* Internal compression state.
*/
#define LENGTH_CODES 29
/* number of length codes, not counting the special END_BLOCK code */
#define LITERALS 256
/* number of literal bytes 0..255 */
#define L_CODES (LITERALS+1+LENGTH_CODES)
/* number of Literal or Length codes, including the END_BLOCK code */
#define D_CODES 30
/* number of distance codes */
#define BL_CODES 19
/* number of codes used to transfer the bit lengths */
#define HEAP_SIZE (2*L_CODES+1)
/* maximum heap size */
#define MAX_BITS 15
/* All codes must not exceed MAX_BITS bits */
#define INIT_STATE 42
#define BUSY_STATE 113
#define FINISH_STATE 666
/* Stream status */
/* Data structure describing a single value and its code string. */
typedef struct ct_data_s {
union {
ush freq; /* frequency count */
ush code; /* bit string */
} fc;
union {
ush dad; /* father node in Huffman tree */
ush len; /* length of bit string */
} dl;
} FAR ct_data;
#define Freq fc.freq
#define Code fc.code
#define Dad dl.dad
#define Len dl.len
typedef struct static_tree_desc_s static_tree_desc;
typedef struct tree_desc_s {
ct_data *dyn_tree; /* the dynamic tree */
int max_code; /* largest code with non zero frequency */
static_tree_desc *stat_desc; /* the corresponding static tree */
} FAR tree_desc;
typedef ush Pos;
typedef Pos FAR Posf;
typedef unsigned IPos;
/* A Pos is an index in the character window. We use short instead of int to
* save space in the various tables. IPos is used only for parameter passing.
*/
typedef struct internal_state {
z_streamp strm; /* pointer back to this zlib stream */
int status; /* as the name implies */
Bytef *pending_buf; /* output still pending */
ulg pending_buf_size; /* size of pending_buf */
Bytef *pending_out; /* next pending byte to output to the stream */
int pending; /* nb of bytes in the pending buffer */
int noheader; /* suppress zlib header and adler32 */
Byte data_type; /* UNKNOWN, BINARY or ASCII */
Byte method; /* STORED (for zip only) or DEFLATED */
int last_flush; /* value of flush param for previous deflate call */
/* used by deflate.c: */
uInt w_size; /* LZ77 window size (32K by default) */
uInt w_bits; /* log2(w_size) (8..16) */
uInt w_mask; /* w_size - 1 */
Bytef *window;
/* Sliding window. Input bytes are read into the second half of the window,
* and move to the first half later to keep a dictionary of at least wSize
* bytes. With this organization, matches are limited to a distance of
* wSize-MAX_MATCH bytes, but this ensures that IO is always
* performed with a length multiple of the block size. Also, it limits
* the window size to 64K, which is quite useful on MSDOS.
* To do: use the user input buffer as sliding window.
*/
ulg window_size;
/* Actual size of window: 2*wSize, except when the user input buffer
* is directly used as sliding window.
*/
Posf *prev;
/* Link to older string with same hash index. To limit the size of this
* array to 64K, this link is maintained only for the last 32K strings.
* An index in this array is thus a window index modulo 32K.
*/
Posf *head; /* Heads of the hash chains or NIL. */
uInt ins_h; /* hash index of string to be inserted */
uInt hash_size; /* number of elements in hash table */
uInt hash_bits; /* log2(hash_size) */
uInt hash_mask; /* hash_size-1 */
uInt hash_shift;
/* Number of bits by which ins_h must be shifted at each input
* step. It must be such that after MIN_MATCH steps, the oldest
* byte no longer takes part in the hash key, that is:
* hash_shift * MIN_MATCH >= hash_bits
*/
long block_start;
/* Window position at the beginning of the current output block. Gets
* negative when the window is moved backwards.
*/
uInt match_length; /* length of best match */
IPos prev_match; /* previous match */
int match_available; /* set if previous match exists */
uInt strstart; /* start of string to insert */
uInt match_start; /* start of matching string */
uInt lookahead; /* number of valid bytes ahead in window */
uInt prev_length;
/* Length of the best match at previous step. Matches not greater than this
* are discarded. This is used in the lazy match evaluation.
*/
uInt max_chain_length;
/* To speed up deflation, hash chains are never searched beyond this
* length. A higher limit improves compression ratio but degrades the
* speed.
*/
uInt max_lazy_match;
/* Attempt to find a better match only when the current match is strictly
* smaller than this value. This mechanism is used only for compression
* levels >= 4.
*/
# define max_insert_length max_lazy_match
/* Insert new strings in the hash table only if the match length is not
* greater than this length. This saves time but degrades compression.
* max_insert_length is used only for compression levels <= 3.
*/
int level; /* compression level (1..9) */
int strategy; /* favor or force Huffman coding*/
uInt good_match;
/* Use a faster search when the previous match is longer than this */
int nice_match; /* Stop searching when current match exceeds this */
/* used by trees.c: */
/* Didn't use ct_data typedef below to supress compiler warning */
struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
struct tree_desc_s l_desc; /* desc. for literal tree */
struct tree_desc_s d_desc; /* desc. for distance tree */
struct tree_desc_s bl_desc; /* desc. for bit length tree */
ush bl_count[MAX_BITS+1];
/* number of codes at each bit length for an optimal tree */
int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
int heap_len; /* number of elements in the heap */
int heap_max; /* element of largest frequency */
/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
* The same heap array is used to build all trees.
*/
uch depth[2*L_CODES+1];
/* Depth of each subtree used as tie breaker for trees of equal frequency
*/
uchf *l_buf; /* buffer for literals or lengths */
uInt lit_bufsize;
/* Size of match buffer for literals/lengths. There are 4 reasons for
* limiting lit_bufsize to 64K:
* - frequencies can be kept in 16 bit counters
* - if compression is not successful for the first block, all input
* data is still in the window so we can still emit a stored block even
* when input comes from standard input. (This can also be done for
* all blocks if lit_bufsize is not greater than 32K.)
* - if compression is not successful for a file smaller than 64K, we can
* even emit a stored file instead of a stored block (saving 5 bytes).
* This is applicable only for zip (not gzip or zlib).
* - creating new Huffman trees less frequently may not provide fast
* adaptation to changes in the input data statistics. (Take for
* example a binary file with poorly compressible code followed by
* a highly compressible string table.) Smaller buffer sizes give
* fast adaptation but have of course the overhead of transmitting
* trees more frequently.
* - I can't count above 4
*/
uInt last_lit; /* running index in l_buf */
ushf *d_buf;
/* Buffer for distances. To simplify the code, d_buf and l_buf have
* the same number of elements. To use different lengths, an extra flag
* array would be necessary.
*/
ulg opt_len; /* bit length of current block with optimal trees */
ulg static_len; /* bit length of current block with static trees */
uInt matches; /* number of string matches in current block */
int last_eob_len; /* bit length of EOB code for last block */
#ifdef DEBUG
ulg compressed_len; /* total bit length of compressed file mod 2^32 */
ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
#endif
ush bi_buf;
/* Output buffer. bits are inserted starting at the bottom (least
* significant bits).
*/
int bi_valid;
/* Number of valid bits in bi_buf. All bits above the last valid bit
* are always zero.
*/
} FAR deflate_state;
/* Output a byte on the stream.
* IN assertion: there is enough room in pending_buf.
*/
#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
/* Minimum amount of lookahead, except at the end of the input file.
* See deflate.c for comments about the MIN_MATCH+1.
*/
#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
/* In order to simplify the code, particularly on 16 bit machines, match
* distances are limited to MAX_DIST instead of WSIZE.
*/
/* in trees.c */
void _tr_init OF((deflate_state *s));
int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
int eof));
void _tr_align OF((deflate_state *s));
void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
int eof));
#define d_code(dist) \
((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
/* Mapping from a distance to a distance code. dist is the distance - 1 and
* must not have side effects. _dist_code[256] and _dist_code[257] are never
* used.
*/
#ifndef DEBUG
/* Inline versions of _tr_tally for speed: */
#if defined(GEN_TREES_H) || !defined(STDC)
extern uch _length_code[];
extern uch _dist_code[];
#else
extern const uch _length_code[];
extern const uch _dist_code[];
#endif
# define _tr_tally_lit(s, c, flush) \
{ uch cc = (c); \
s->d_buf[s->last_lit] = 0; \
s->l_buf[s->last_lit++] = cc; \
s->dyn_ltree[cc].Freq++; \
flush = (s->last_lit == s->lit_bufsize-1); \
}
# define _tr_tally_dist(s, distance, length, flush) \
{ uch len = (length); \
ush dist = (distance); \
s->d_buf[s->last_lit] = dist; \
s->l_buf[s->last_lit++] = len; \
dist--; \
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
s->dyn_dtree[d_code(dist)].Freq++; \
flush = (s->last_lit == s->lit_bufsize-1); \
}
#else
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
# define _tr_tally_dist(s, distance, length, flush) \
flush = _tr_tally(s, distance, length)
#endif
#endif

398
zlib/infblock.c Executable file
View File

@ -0,0 +1,398 @@
/* infblock.c -- interpret and process block types to last block
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zutil.h"
#include "infblock.h"
#include "inftrees.h"
#include "infcodes.h"
#include "infutil.h"
struct inflate_codes_state {int dummy;}; /* for buggy compilers */
/* simplify the use of the inflate_huft type with some defines */
#define exop word.what.Exop
#define bits word.what.Bits
/* Table for deflate from PKZIP's appnote.txt. */
local const uInt border[] = { /* Order of the bit length code lengths */
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
/*
Notes beyond the 1.93a appnote.txt:
1. Distance pointers never point before the beginning of the output
stream.
2. Distance pointers can point back across blocks, up to 32k away.
3. There is an implied maximum of 7 bits for the bit length table and
15 bits for the actual data.
4. If only one code exists, then it is encoded using one bit. (Zero
would be more efficient, but perhaps a little confusing.) If two
codes exist, they are coded using one bit each (0 and 1).
5. There is no way of sending zero distance codes--a dummy must be
sent if there are none. (History: a pre 2.0 version of PKZIP would
store blocks with no distance codes, but this was discovered to be
too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
zero distance codes, which is sent as one code of zero bits in
length.
6. There are up to 286 literal/length codes. Code 256 represents the
end-of-block. Note however that the static length tree defines
288 codes just to fill out the Huffman codes. Codes 286 and 287
cannot be used though, since there is no length base or extra bits
defined for them. Similarily, there are up to 30 distance codes.
However, static trees define 32 codes (all 5 bits) to fill out the
Huffman codes, but the last two had better not show up in the data.
7. Unzip can check dynamic Huffman blocks for complete code sets.
The exception is that a single code would not be complete (see #4).
8. The five bits following the block type is really the number of
literal codes sent minus 257.
9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
(1+6+6). Therefore, to output three times the length, you output
three codes (1+1+1), whereas to output four times the same length,
you only need two codes (1+3). Hmm.
10. In the tree reconstruction algorithm, Code = Code + Increment
only if BitLength(i) is not zero. (Pretty obvious.)
11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
12. Note: length code 284 can represent 227-258, but length code 285
really is 258. The last length deserves its own, short code
since it gets used a lot in very redundant files. The length
258 is special since 258 - 3 (the min match length) is 255.
13. The literal/length and distance code bit lengths are read as a
single stream of lengths. It is possible (and advantageous) for
a repeat code (16, 17, or 18) to go across the boundary between
the two sets of lengths.
*/
void inflate_blocks_reset(s, z, c)
inflate_blocks_statef *s;
z_streamp z;
uLongf *c;
{
if (c != Z_NULL)
*c = s->check;
if (s->mode == BTREE || s->mode == DTREE)
ZFREE(z, s->sub.trees.blens);
if (s->mode == CODES)
inflate_codes_free(s->sub.decode.codes, z);
s->mode = TYPE;
s->bitk = 0;
s->bitb = 0;
s->read = s->write = s->window;
if (s->checkfn != Z_NULL)
z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
Tracev((stderr, "inflate: blocks reset\n"));
}
inflate_blocks_statef *inflate_blocks_new(z, c, w)
z_streamp z;
check_func c;
uInt w;
{
inflate_blocks_statef *s;
if ((s = (inflate_blocks_statef *)ZALLOC
(z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
return s;
if ((s->hufts =
(inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
{
ZFREE(z, s);
return Z_NULL;
}
if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
{
ZFREE(z, s->hufts);
ZFREE(z, s);
return Z_NULL;
}
s->end = s->window + w;
s->checkfn = c;
s->mode = TYPE;
Tracev((stderr, "inflate: blocks allocated\n"));
inflate_blocks_reset(s, z, Z_NULL);
return s;
}
int inflate_blocks(s, z, r)
inflate_blocks_statef *s;
z_streamp z;
int r;
{
uInt t; /* temporary storage */
uLong b; /* bit buffer */
uInt k; /* bits in bit buffer */
Bytef *p; /* input data pointer */
uInt n; /* bytes available there */
Bytef *q; /* output window write pointer */
uInt m; /* bytes to end of window or read pointer */
/* copy input/output information to locals (UPDATE macro restores) */
LOAD
/* process input based on current state */
while (1) switch (s->mode)
{
case TYPE:
NEEDBITS(3)
t = (uInt)b & 7;
s->last = t & 1;
switch (t >> 1)
{
case 0: /* stored */
Tracev((stderr, "inflate: stored block%s\n",
s->last ? " (last)" : ""));
DUMPBITS(3)
t = k & 7; /* go to byte boundary */
DUMPBITS(t)
s->mode = LENS; /* get length of stored block */
break;
case 1: /* fixed */
Tracev((stderr, "inflate: fixed codes block%s\n",
s->last ? " (last)" : ""));
{
uInt bl, bd;
inflate_huft *tl, *td;
inflate_trees_fixed(&bl, &bd, &tl, &td, z);
s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
if (s->sub.decode.codes == Z_NULL)
{
r = Z_MEM_ERROR;
LEAVE
}
}
DUMPBITS(3)
s->mode = CODES;
break;
case 2: /* dynamic */
Tracev((stderr, "inflate: dynamic codes block%s\n",
s->last ? " (last)" : ""));
DUMPBITS(3)
s->mode = TABLE;
break;
case 3: /* illegal */
DUMPBITS(3)
s->mode = BAD;
z->msg = (char*)"invalid block type";
r = Z_DATA_ERROR;
LEAVE
}
break;
case LENS:
NEEDBITS(32)
if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
{
s->mode = BAD;
z->msg = (char*)"invalid stored block lengths";
r = Z_DATA_ERROR;
LEAVE
}
s->sub.left = (uInt)b & 0xffff;
b = k = 0; /* dump bits */
Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
break;
case STORED:
if (n == 0)
LEAVE
NEEDOUT
t = s->sub.left;
if (t > n) t = n;
if (t > m) t = m;
zmemcpy(q, p, t);
p += t; n -= t;
q += t; m -= t;
if ((s->sub.left -= t) != 0)
break;
Tracev((stderr, "inflate: stored end, %lu total out\n",
z->total_out + (q >= s->read ? q - s->read :
(s->end - s->read) + (q - s->window))));
s->mode = s->last ? DRY : TYPE;
break;
case TABLE:
NEEDBITS(14)
s->sub.trees.table = t = (uInt)b & 0x3fff;
#ifndef PKZIP_BUG_WORKAROUND
if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
{
s->mode = BAD;
z->msg = (char*)"too many length or distance symbols";
r = Z_DATA_ERROR;
LEAVE
}
#endif
t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
{
r = Z_MEM_ERROR;
LEAVE
}
DUMPBITS(14)
s->sub.trees.index = 0;
Tracev((stderr, "inflate: table sizes ok\n"));
s->mode = BTREE;
case BTREE:
while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
{
NEEDBITS(3)
s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
DUMPBITS(3)
}
while (s->sub.trees.index < 19)
s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
s->sub.trees.bb = 7;
t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
&s->sub.trees.tb, s->hufts, z);
if (t != Z_OK)
{
ZFREE(z, s->sub.trees.blens);
r = t;
if (r == Z_DATA_ERROR)
s->mode = BAD;
LEAVE
}
s->sub.trees.index = 0;
Tracev((stderr, "inflate: bits tree ok\n"));
s->mode = DTREE;
case DTREE:
while (t = s->sub.trees.table,
s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
{
inflate_huft *h;
uInt i, j, c;
t = s->sub.trees.bb;
NEEDBITS(t)
h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
t = h->bits;
c = h->base;
if (c < 16)
{
DUMPBITS(t)
s->sub.trees.blens[s->sub.trees.index++] = c;
}
else /* c == 16..18 */
{
i = c == 18 ? 7 : c - 14;
j = c == 18 ? 11 : 3;
NEEDBITS(t + i)
DUMPBITS(t)
j += (uInt)b & inflate_mask[i];
DUMPBITS(i)
i = s->sub.trees.index;
t = s->sub.trees.table;
if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
(c == 16 && i < 1))
{
ZFREE(z, s->sub.trees.blens);
s->mode = BAD;
z->msg = (char*)"invalid bit length repeat";
r = Z_DATA_ERROR;
LEAVE
}
c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
do {
s->sub.trees.blens[i++] = c;
} while (--j);
s->sub.trees.index = i;
}
}
s->sub.trees.tb = Z_NULL;
{
uInt bl, bd;
inflate_huft *tl, *td;
inflate_codes_statef *c;
bl = 9; /* must be <= 9 for lookahead assumptions */
bd = 6; /* must be <= 9 for lookahead assumptions */
t = s->sub.trees.table;
t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
s->sub.trees.blens, &bl, &bd, &tl, &td,
s->hufts, z);
ZFREE(z, s->sub.trees.blens);
if (t != Z_OK)
{
if (t == (uInt)Z_DATA_ERROR)
s->mode = BAD;
r = t;
LEAVE
}
Tracev((stderr, "inflate: trees ok\n"));
if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
{
r = Z_MEM_ERROR;
LEAVE
}
s->sub.decode.codes = c;
}
s->mode = CODES;
case CODES:
UPDATE
if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
return inflate_flush(s, z, r);
r = Z_OK;
inflate_codes_free(s->sub.decode.codes, z);
LOAD
Tracev((stderr, "inflate: codes end, %lu total out\n",
z->total_out + (q >= s->read ? q - s->read :
(s->end - s->read) + (q - s->window))));
if (!s->last)
{
s->mode = TYPE;
break;
}
s->mode = DRY;
case DRY:
FLUSH
if (s->read != s->write)
LEAVE
s->mode = DONE;
case DONE:
r = Z_STREAM_END;
LEAVE
case BAD:
r = Z_DATA_ERROR;
LEAVE
default:
r = Z_STREAM_ERROR;
LEAVE
}
}
int inflate_blocks_free(s, z)
inflate_blocks_statef *s;
z_streamp z;
{
inflate_blocks_reset(s, z, Z_NULL);
ZFREE(z, s->window);
ZFREE(z, s->hufts);
ZFREE(z, s);
Tracev((stderr, "inflate: blocks freed\n"));
return Z_OK;
}
void inflate_set_dictionary(s, d, n)
inflate_blocks_statef *s;
const Bytef *d;
uInt n;
{
zmemcpy(s->window, d, n);
s->read = s->write = s->window + n;
}
/* Returns true if inflate is currently at the end of a block generated
* by Z_SYNC_FLUSH or Z_FULL_FLUSH.
* IN assertion: s != Z_NULL
*/
int inflate_blocks_sync_point(s)
inflate_blocks_statef *s;
{
return s->mode == LENS;
}

39
zlib/infblock.h Executable file
View File

@ -0,0 +1,39 @@
/* infblock.h -- header to use infblock.c
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
struct inflate_blocks_state;
typedef struct inflate_blocks_state FAR inflate_blocks_statef;
extern inflate_blocks_statef * inflate_blocks_new OF((
z_streamp z,
check_func c, /* check function */
uInt w)); /* window size */
extern int inflate_blocks OF((
inflate_blocks_statef *,
z_streamp ,
int)); /* initial return code */
extern void inflate_blocks_reset OF((
inflate_blocks_statef *,
z_streamp ,
uLongf *)); /* check value on output */
extern int inflate_blocks_free OF((
inflate_blocks_statef *,
z_streamp));
extern void inflate_set_dictionary OF((
inflate_blocks_statef *s,
const Bytef *d, /* dictionary */
uInt n)); /* dictionary length */
extern int inflate_blocks_sync_point OF((
inflate_blocks_statef *s));

257
zlib/infcodes.c Executable file
View File

@ -0,0 +1,257 @@
/* infcodes.c -- process literals and length/distance pairs
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zutil.h"
#include "inftrees.h"
#include "infblock.h"
#include "infcodes.h"
#include "infutil.h"
#include "inffast.h"
/* simplify the use of the inflate_huft type with some defines */
#define exop word.what.Exop
#define bits word.what.Bits
typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
START, /* x: set up for LEN */
LEN, /* i: get length/literal/eob next */
LENEXT, /* i: getting length extra (have base) */
DIST, /* i: get distance next */
DISTEXT, /* i: getting distance extra */
COPY, /* o: copying bytes in window, waiting for space */
LIT, /* o: got literal, waiting for output space */
WASH, /* o: got eob, possibly still output waiting */
END, /* x: got eob and all data flushed */
BADCODE} /* x: got error */
inflate_codes_mode;
/* inflate codes private state */
struct inflate_codes_state {
/* mode */
inflate_codes_mode mode; /* current inflate_codes mode */
/* mode dependent information */
uInt len;
union {
struct {
inflate_huft *tree; /* pointer into tree */
uInt need; /* bits needed */
} code; /* if LEN or DIST, where in tree */
uInt lit; /* if LIT, literal */
struct {
uInt get; /* bits to get for extra */
uInt dist; /* distance back to copy from */
} copy; /* if EXT or COPY, where and how much */
} sub; /* submode */
/* mode independent information */
Byte lbits; /* ltree bits decoded per branch */
Byte dbits; /* dtree bits decoder per branch */
inflate_huft *ltree; /* literal/length/eob tree */
inflate_huft *dtree; /* distance tree */
};
inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
uInt bl, bd;
inflate_huft *tl;
inflate_huft *td; /* need separate declaration for Borland C++ */
z_streamp z;
{
inflate_codes_statef *c;
if ((c = (inflate_codes_statef *)
ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
{
c->mode = START;
c->lbits = (Byte)bl;
c->dbits = (Byte)bd;
c->ltree = tl;
c->dtree = td;
Tracev((stderr, "inflate: codes new\n"));
}
return c;
}
int inflate_codes(s, z, r)
inflate_blocks_statef *s;
z_streamp z;
int r;
{
uInt j; /* temporary storage */
inflate_huft *t; /* temporary pointer */
uInt e; /* extra bits or operation */
uLong b; /* bit buffer */
uInt k; /* bits in bit buffer */
Bytef *p; /* input data pointer */
uInt n; /* bytes available there */
Bytef *q; /* output window write pointer */
uInt m; /* bytes to end of window or read pointer */
Bytef *f; /* pointer to copy strings from */
inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
/* copy input/output information to locals (UPDATE macro restores) */
LOAD
/* process input and output based on current state */
while (1) switch (c->mode)
{ /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
case START: /* x: set up for LEN */
#ifndef SLOW
if (m >= 258 && n >= 10)
{
UPDATE
r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
LOAD
if (r != Z_OK)
{
c->mode = r == Z_STREAM_END ? WASH : BADCODE;
break;
}
}
#endif /* !SLOW */
c->sub.code.need = c->lbits;
c->sub.code.tree = c->ltree;
c->mode = LEN;
case LEN: /* i: get length/literal/eob next */
j = c->sub.code.need;
NEEDBITS(j)
t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
DUMPBITS(t->bits)
e = (uInt)(t->exop);
if (e == 0) /* literal */
{
c->sub.lit = t->base;
Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
"inflate: literal '%c'\n" :
"inflate: literal 0x%02x\n", t->base));
c->mode = LIT;
break;
}
if (e & 16) /* length */
{
c->sub.copy.get = e & 15;
c->len = t->base;
c->mode = LENEXT;
break;
}
if ((e & 64) == 0) /* next table */
{
c->sub.code.need = e;
c->sub.code.tree = t + t->base;
break;
}
if (e & 32) /* end of block */
{
Tracevv((stderr, "inflate: end of block\n"));
c->mode = WASH;
break;
}
c->mode = BADCODE; /* invalid code */
z->msg = (char*)"invalid literal/length code";
r = Z_DATA_ERROR;
LEAVE
case LENEXT: /* i: getting length extra (have base) */
j = c->sub.copy.get;
NEEDBITS(j)
c->len += (uInt)b & inflate_mask[j];
DUMPBITS(j)
c->sub.code.need = c->dbits;
c->sub.code.tree = c->dtree;
Tracevv((stderr, "inflate: length %u\n", c->len));
c->mode = DIST;
case DIST: /* i: get distance next */
j = c->sub.code.need;
NEEDBITS(j)
t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
DUMPBITS(t->bits)
e = (uInt)(t->exop);
if (e & 16) /* distance */
{
c->sub.copy.get = e & 15;
c->sub.copy.dist = t->base;
c->mode = DISTEXT;
break;
}
if ((e & 64) == 0) /* next table */
{
c->sub.code.need = e;
c->sub.code.tree = t + t->base;
break;
}
c->mode = BADCODE; /* invalid code */
z->msg = (char*)"invalid distance code";
r = Z_DATA_ERROR;
LEAVE
case DISTEXT: /* i: getting distance extra */
j = c->sub.copy.get;
NEEDBITS(j)
c->sub.copy.dist += (uInt)b & inflate_mask[j];
DUMPBITS(j)
Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
c->mode = COPY;
case COPY: /* o: copying bytes in window, waiting for space */
#ifndef __TURBOC__ /* Turbo C bug for following expression */
f = (uInt)(q - s->window) < c->sub.copy.dist ?
s->end - (c->sub.copy.dist - (q - s->window)) :
q - c->sub.copy.dist;
#else
f = q - c->sub.copy.dist;
if ((uInt)(q - s->window) < c->sub.copy.dist)
f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
#endif
while (c->len)
{
NEEDOUT
OUTBYTE(*f++)
if (f == s->end)
f = s->window;
c->len--;
}
c->mode = START;
break;
case LIT: /* o: got literal, waiting for output space */
NEEDOUT
OUTBYTE(c->sub.lit)
c->mode = START;
break;
case WASH: /* o: got eob, possibly more output */
if (k > 7) /* return unused byte, if any */
{
Assert(k < 16, "inflate_codes grabbed too many bytes")
k -= 8;
n++;
p--; /* can always return one */
}
FLUSH
if (s->read != s->write)
LEAVE
c->mode = END;
case END:
r = Z_STREAM_END;
LEAVE
case BADCODE: /* x: got error */
r = Z_DATA_ERROR;
LEAVE
default:
r = Z_STREAM_ERROR;
LEAVE
}
#ifdef NEED_DUMMY_RETURN
return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
#endif
}
void inflate_codes_free(c, z)
inflate_codes_statef *c;
z_streamp z;
{
ZFREE(z, c);
Tracev((stderr, "inflate: codes free\n"));
}

27
zlib/infcodes.h Executable file
View File

@ -0,0 +1,27 @@
/* infcodes.h -- header to use infcodes.c
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
struct inflate_codes_state;
typedef struct inflate_codes_state FAR inflate_codes_statef;
extern inflate_codes_statef *inflate_codes_new OF((
uInt, uInt,
inflate_huft *, inflate_huft *,
z_streamp ));
extern int inflate_codes OF((
inflate_blocks_statef *,
z_streamp ,
int));
extern void inflate_codes_free OF((
inflate_codes_statef *,
z_streamp ));

170
zlib/inffast.c Executable file
View File

@ -0,0 +1,170 @@
/* inffast.c -- process literals and length/distance pairs fast
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zutil.h"
#include "inftrees.h"
#include "infblock.h"
#include "infcodes.h"
#include "infutil.h"
#include "inffast.h"
struct inflate_codes_state {int dummy;}; /* for buggy compilers */
/* simplify the use of the inflate_huft type with some defines */
#define exop word.what.Exop
#define bits word.what.Bits
/* macros for bit input with no checking and for returning unused bytes */
#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
/* Called with number of bytes left to write in window at least 258
(the maximum string length) and number of input bytes available
at least ten. The ten bytes are six bytes for the longest length/
distance pair plus four bytes for overloading the bit buffer. */
int inflate_fast(bl, bd, tl, td, s, z)
uInt bl, bd;
inflate_huft *tl;
inflate_huft *td; /* need separate declaration for Borland C++ */
inflate_blocks_statef *s;
z_streamp z;
{
inflate_huft *t; /* temporary pointer */
uInt e; /* extra bits or operation */
uLong b; /* bit buffer */
uInt k; /* bits in bit buffer */
Bytef *p; /* input data pointer */
uInt n; /* bytes available there */
Bytef *q; /* output window write pointer */
uInt m; /* bytes to end of window or read pointer */
uInt ml; /* mask for literal/length tree */
uInt md; /* mask for distance tree */
uInt c; /* bytes to copy */
uInt d; /* distance back to copy from */
Bytef *r; /* copy source pointer */
/* load input, output, bit values */
LOAD
/* initialize masks */
ml = inflate_mask[bl];
md = inflate_mask[bd];
/* do until not enough input or output space for fast loop */
do { /* assume called with m >= 258 && n >= 10 */
/* get literal/length code */
GRABBITS(20) /* max bits for literal/length code */
if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
{
DUMPBITS(t->bits)
Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
"inflate: * literal '%c'\n" :
"inflate: * literal 0x%02x\n", t->base));
*q++ = (Byte)t->base;
m--;
continue;
}
do {
DUMPBITS(t->bits)
if (e & 16)
{
/* get extra bits for length */
e &= 15;
c = t->base + ((uInt)b & inflate_mask[e]);
DUMPBITS(e)
Tracevv((stderr, "inflate: * length %u\n", c));
/* decode distance base of block to copy */
GRABBITS(15); /* max bits for distance code */
e = (t = td + ((uInt)b & md))->exop;
do {
DUMPBITS(t->bits)
if (e & 16)
{
/* get extra bits to add to distance base */
e &= 15;
GRABBITS(e) /* get extra bits (up to 13) */
d = t->base + ((uInt)b & inflate_mask[e]);
DUMPBITS(e)
Tracevv((stderr, "inflate: * distance %u\n", d));
/* do the copy */
m -= c;
if ((uInt)(q - s->window) >= d) /* offset before dest */
{ /* just copy */
r = q - d;
*q++ = *r++; c--; /* minimum count is three, */
*q++ = *r++; c--; /* so unroll loop a little */
}
else /* else offset after destination */
{
e = d - (uInt)(q - s->window); /* bytes from offset to end */
r = s->end - e; /* pointer to offset */
if (c > e) /* if source crosses, */
{
c -= e; /* copy to end of window */
do {
*q++ = *r++;
} while (--e);
r = s->window; /* copy rest from start of window */
}
}
do { /* copy all or what's left */
*q++ = *r++;
} while (--c);
break;
}
else if ((e & 64) == 0)
{
t += t->base;
e = (t += ((uInt)b & inflate_mask[e]))->exop;
}
else
{
z->msg = (char*)"invalid distance code";
UNGRAB
UPDATE
return Z_DATA_ERROR;
}
} while (1);
break;
}
if ((e & 64) == 0)
{
t += t->base;
if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
{
DUMPBITS(t->bits)
Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
"inflate: * literal '%c'\n" :
"inflate: * literal 0x%02x\n", t->base));
*q++ = (Byte)t->base;
m--;
break;
}
}
else if (e & 32)
{
Tracevv((stderr, "inflate: * end of block\n"));
UNGRAB
UPDATE
return Z_STREAM_END;
}
else
{
z->msg = (char*)"invalid literal/length code";
UNGRAB
UPDATE
return Z_DATA_ERROR;
}
} while (1);
} while (m >= 258 && n >= 10);
/* not enough input or output--restore pointers and return */
UNGRAB
UPDATE
return Z_OK;
}

17
zlib/inffast.h Executable file
View File

@ -0,0 +1,17 @@
/* inffast.h -- header to use inffast.c
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
extern int inflate_fast OF((
uInt,
uInt,
inflate_huft *,
inflate_huft *,
inflate_blocks_statef *,
z_streamp ));

151
zlib/inffixed.h Executable file
View File

@ -0,0 +1,151 @@
/* inffixed.h -- table for decoding fixed codes
* Generated automatically by the maketree.c program
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
local uInt fixed_bl = 9;
local uInt fixed_bd = 5;
local inflate_huft fixed_tl[] = {
{{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
{{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
{{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
{{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
{{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
{{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
{{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
{{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
{{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
{{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
{{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
{{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
{{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
{{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
{{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
{{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
{{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
{{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
{{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
{{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
{{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
{{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
{{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
{{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
{{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
{{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
{{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
{{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
{{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
{{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
{{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
{{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
{{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
{{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
{{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
{{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
{{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
{{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
{{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
{{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
{{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
{{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
{{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
{{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
{{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
{{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
{{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
{{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
{{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
{{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
{{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
{{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
{{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
{{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
{{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
{{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
{{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
{{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
{{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
{{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
{{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
{{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
{{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
{{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
{{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
{{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
{{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
{{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
{{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
{{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
{{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
{{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
{{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
{{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
{{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
{{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
{{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
{{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
{{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
{{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
{{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
{{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
{{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
{{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
{{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
{{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
{{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
{{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
{{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
{{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
{{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
{{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
{{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
{{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
{{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
{{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
{{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
{{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
{{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
{{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
{{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
{{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
{{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
{{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
{{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
{{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
{{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
{{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
{{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
{{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
{{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
{{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
{{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
{{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
{{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
{{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
{{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
{{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
{{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
{{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
{{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
{{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
{{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
{{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
{{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
{{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
{{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
{{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
};
local inflate_huft fixed_td[] = {
{{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
{{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
{{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
{{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
{{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
{{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
{{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
{{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
};

366
zlib/inflate.c Executable file
View File

@ -0,0 +1,366 @@
/* inflate.c -- zlib interface to inflate modules
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zutil.h"
#include "infblock.h"
struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
typedef enum {
METHOD, /* waiting for method byte */
FLAG, /* waiting for flag byte */
DICT4, /* four dictionary check bytes to go */
DICT3, /* three dictionary check bytes to go */
DICT2, /* two dictionary check bytes to go */
DICT1, /* one dictionary check byte to go */
DICT0, /* waiting for inflateSetDictionary */
BLOCKS, /* decompressing blocks */
CHECK4, /* four check bytes to go */
CHECK3, /* three check bytes to go */
CHECK2, /* two check bytes to go */
CHECK1, /* one check byte to go */
DONE, /* finished check, done */
BAD} /* got an error--stay here */
inflate_mode;
/* inflate private state */
struct internal_state {
/* mode */
inflate_mode mode; /* current inflate mode */
/* mode dependent information */
union {
uInt method; /* if FLAGS, method byte */
struct {
uLong was; /* computed check value */
uLong need; /* stream check value */
} check; /* if CHECK, check values to compare */
uInt marker; /* if BAD, inflateSync's marker bytes count */
} sub; /* submode */
/* mode independent information */
int nowrap; /* flag for no wrapper */
uInt wbits; /* log2(window size) (8..15, defaults to 15) */
inflate_blocks_statef
*blocks; /* current inflate_blocks state */
};
int ZEXPORT inflateReset(z)
z_streamp z;
{
if (z == Z_NULL || z->state == Z_NULL)
return Z_STREAM_ERROR;
z->total_in = z->total_out = 0;
z->msg = Z_NULL;
z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
inflate_blocks_reset(z->state->blocks, z, Z_NULL);
Tracev((stderr, "inflate: reset\n"));
return Z_OK;
}
int ZEXPORT inflateEnd(z)
z_streamp z;
{
if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
return Z_STREAM_ERROR;
if (z->state->blocks != Z_NULL)
inflate_blocks_free(z->state->blocks, z);
ZFREE(z, z->state);
z->state = Z_NULL;
Tracev((stderr, "inflate: end\n"));
return Z_OK;
}
int ZEXPORT inflateInit2_(z, w, version, stream_size)
z_streamp z;
int w;
const char *version;
int stream_size;
{
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
stream_size != sizeof(z_stream))
return Z_VERSION_ERROR;
/* initialize state */
if (z == Z_NULL)
return Z_STREAM_ERROR;
z->msg = Z_NULL;
if (z->zalloc == Z_NULL)
{
z->zalloc = zcalloc;
z->opaque = (voidpf)0;
}
if (z->zfree == Z_NULL) z->zfree = zcfree;
if ((z->state = (struct internal_state FAR *)
ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
return Z_MEM_ERROR;
z->state->blocks = Z_NULL;
/* handle undocumented nowrap option (no zlib header or check) */
z->state->nowrap = 0;
if (w < 0)
{
w = - w;
z->state->nowrap = 1;
}
/* set window size */
if (w < 8 || w > 15)
{
inflateEnd(z);
return Z_STREAM_ERROR;
}
z->state->wbits = (uInt)w;
/* create inflate_blocks state */
if ((z->state->blocks =
inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
== Z_NULL)
{
inflateEnd(z);
return Z_MEM_ERROR;
}
Tracev((stderr, "inflate: allocated\n"));
/* reset state */
inflateReset(z);
return Z_OK;
}
int ZEXPORT inflateInit_(z, version, stream_size)
z_streamp z;
const char *version;
int stream_size;
{
return inflateInit2_(z, DEF_WBITS, version, stream_size);
}
#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
int ZEXPORT inflate(z, f)
z_streamp z;
int f;
{
int r;
uInt b;
if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
return Z_STREAM_ERROR;
f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
r = Z_BUF_ERROR;
while (1) switch (z->state->mode)
{
case METHOD:
NEEDBYTE
if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
{
z->state->mode = BAD;
z->msg = (char*)"unknown compression method";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
}
if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
{
z->state->mode = BAD;
z->msg = (char*)"invalid window size";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
}
z->state->mode = FLAG;
case FLAG:
NEEDBYTE
b = NEXTBYTE;
if (((z->state->sub.method << 8) + b) % 31)
{
z->state->mode = BAD;
z->msg = (char*)"incorrect header check";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
}
Tracev((stderr, "inflate: zlib header ok\n"));
if (!(b & PRESET_DICT))
{
z->state->mode = BLOCKS;
break;
}
z->state->mode = DICT4;
case DICT4:
NEEDBYTE
z->state->sub.check.need = (uLong)NEXTBYTE << 24;
z->state->mode = DICT3;
case DICT3:
NEEDBYTE
z->state->sub.check.need += (uLong)NEXTBYTE << 16;
z->state->mode = DICT2;
case DICT2:
NEEDBYTE
z->state->sub.check.need += (uLong)NEXTBYTE << 8;
z->state->mode = DICT1;
case DICT1:
NEEDBYTE
z->state->sub.check.need += (uLong)NEXTBYTE;
z->adler = z->state->sub.check.need;
z->state->mode = DICT0;
return Z_NEED_DICT;
case DICT0:
z->state->mode = BAD;
z->msg = (char*)"need dictionary";
z->state->sub.marker = 0; /* can try inflateSync */
return Z_STREAM_ERROR;
case BLOCKS:
r = inflate_blocks(z->state->blocks, z, r);
if (r == Z_DATA_ERROR)
{
z->state->mode = BAD;
z->state->sub.marker = 0; /* can try inflateSync */
break;
}
if (r == Z_OK)
r = f;
if (r != Z_STREAM_END)
return r;
r = f;
inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
if (z->state->nowrap)
{
z->state->mode = DONE;
break;
}
z->state->mode = CHECK4;
case CHECK4:
NEEDBYTE
z->state->sub.check.need = (uLong)NEXTBYTE << 24;
z->state->mode = CHECK3;
case CHECK3:
NEEDBYTE
z->state->sub.check.need += (uLong)NEXTBYTE << 16;
z->state->mode = CHECK2;
case CHECK2:
NEEDBYTE
z->state->sub.check.need += (uLong)NEXTBYTE << 8;
z->state->mode = CHECK1;
case CHECK1:
NEEDBYTE
z->state->sub.check.need += (uLong)NEXTBYTE;
if (z->state->sub.check.was != z->state->sub.check.need)
{
z->state->mode = BAD;
z->msg = (char*)"incorrect data check";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
}
Tracev((stderr, "inflate: zlib check ok\n"));
z->state->mode = DONE;
case DONE:
return Z_STREAM_END;
case BAD:
return Z_DATA_ERROR;
default:
return Z_STREAM_ERROR;
}
#ifdef NEED_DUMMY_RETURN
return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
#endif
}
int ZEXPORT inflateSetDictionary(z, dictionary, dictLength)
z_streamp z;
const Bytef *dictionary;
uInt dictLength;
{
uInt length = dictLength;
if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
return Z_STREAM_ERROR;
if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
z->adler = 1L;
if (length >= ((uInt)1<<z->state->wbits))
{
length = (1<<z->state->wbits)-1;
dictionary += dictLength - length;
}
inflate_set_dictionary(z->state->blocks, dictionary, length);
z->state->mode = BLOCKS;
return Z_OK;
}
int ZEXPORT inflateSync(z)
z_streamp z;
{
uInt n; /* number of bytes to look at */
Bytef *p; /* pointer to bytes */
uInt m; /* number of marker bytes found in a row */
uLong r, w; /* temporaries to save total_in and total_out */
/* set up */
if (z == Z_NULL || z->state == Z_NULL)
return Z_STREAM_ERROR;
if (z->state->mode != BAD)
{
z->state->mode = BAD;
z->state->sub.marker = 0;
}
if ((n = z->avail_in) == 0)
return Z_BUF_ERROR;
p = z->next_in;
m = z->state->sub.marker;
/* search */
while (n && m < 4)
{
static const Byte mark[4] = {0, 0, 0xff, 0xff};
if (*p == mark[m])
m++;
else if (*p)
m = 0;
else
m = 4 - m;
p++, n--;
}
/* restore */
z->total_in += p - z->next_in;
z->next_in = p;
z->avail_in = n;
z->state->sub.marker = m;
/* return no joy or set up to restart on a new block */
if (m != 4)
return Z_DATA_ERROR;
r = z->total_in; w = z->total_out;
inflateReset(z);
z->total_in = r; z->total_out = w;
z->state->mode = BLOCKS;
return Z_OK;
}
/* Returns true if inflate is currently at the end of a block generated
* by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
* implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
* but removes the length bytes of the resulting empty stored block. When
* decompressing, PPP checks that at the end of input packet, inflate is
* waiting for these length bytes.
*/
int ZEXPORT inflateSyncPoint(z)
z_streamp z;
{
if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
return Z_STREAM_ERROR;
return inflate_blocks_sync_point(z->state->blocks);
}

455
zlib/inftrees.c Executable file
View File

@ -0,0 +1,455 @@
/* inftrees.c -- generate Huffman trees for efficient decoding
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include "zutil.h"
#include "inftrees.h"
#if !defined(BUILDFIXED) && !defined(STDC)
# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */
#endif
const char inflate_copyright[] =
" inflate 1.1.3 Copyright 1995-1998 Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
include such an acknowledgment, I would appreciate that you keep this
copyright string in the executable of your product.
*/
struct internal_state {int dummy;}; /* for buggy compilers */
/* simplify the use of the inflate_huft type with some defines */
#define exop word.what.Exop
#define bits word.what.Bits
local int huft_build OF((
uIntf *, /* code lengths in bits */
uInt, /* number of codes */
uInt, /* number of "simple" codes */
const uIntf *, /* list of base values for non-simple codes */
const uIntf *, /* list of extra bits for non-simple codes */
inflate_huft * FAR*,/* result: starting table */
uIntf *, /* maximum lookup bits (returns actual) */
inflate_huft *, /* space for trees */
uInt *, /* hufts used in space */
uIntf * )); /* space for values */
/* Tables for deflate from PKZIP's appnote.txt. */
local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
/* see note #13 above about 258 */
local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577};
local const uInt cpdext[30] = { /* Extra bits for distance codes */
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13};
/*
Huffman code decoding is performed using a multi-level table lookup.
The fastest way to decode is to simply build a lookup table whose
size is determined by the longest code. However, the time it takes
to build this table can also be a factor if the data being decoded
is not very long. The most common codes are necessarily the
shortest codes, so those codes dominate the decoding time, and hence
the speed. The idea is you can have a shorter table that decodes the
shorter, more probable codes, and then point to subsidiary tables for
the longer codes. The time it costs to decode the longer codes is
then traded against the time it takes to make longer tables.
This results of this trade are in the variables lbits and dbits
below. lbits is the number of bits the first level table for literal/
length codes can decode in one step, and dbits is the same thing for
the distance codes. Subsequent tables are also less than or equal to
those sizes. These values may be adjusted either when all of the
codes are shorter than that, in which case the longest code length in
bits is used, or when the shortest code is *longer* than the requested
table size, in which case the length of the shortest code in bits is
used.
There are two different values for the two tables, since they code a
different number of possibilities each. The literal/length table
codes 286 possible values, or in a flat code, a little over eight
bits. The distance table codes 30 possible values, or a little less
than five bits, flat. The optimum values for speed end up being
about one bit more than those, so lbits is 8+1 and dbits is 5+1.
The optimum values may differ though from machine to machine, and
possibly even between compilers. Your mileage may vary.
*/
/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
#define BMAX 15 /* maximum bit length of any code */
local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
uInt n; /* number of codes (assumed <= 288) */
uInt s; /* number of simple-valued codes (0..s-1) */
const uIntf *d; /* list of base values for non-simple codes */
const uIntf *e; /* list of extra bits for non-simple codes */
inflate_huft * FAR *t; /* result: starting table */
uIntf *m; /* maximum lookup bits, returns actual */
inflate_huft *hp; /* space for trees */
uInt *hn; /* hufts used in space */
uIntf *v; /* working area: values in order of bit length */
/* Given a list of code lengths and a maximum table size, make a set of
tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
if the given code set is incomplete (the tables are still built in this
case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
lengths), or Z_MEM_ERROR if not enough memory. */
{
uInt a; /* counter for codes of length k */
uInt c[BMAX+1]; /* bit length count table */
uInt f; /* i repeats in table every f entries */
int g; /* maximum code length */
int h; /* table level */
register uInt i; /* counter, current code */
register uInt j; /* counter */
register int k; /* number of bits in current code */
int l; /* bits per table (returned in m) */
uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */
register uIntf *p; /* pointer into c[], b[], or v[] */
inflate_huft *q; /* points to current table */
struct inflate_huft_s r; /* table entry for structure assignment */
inflate_huft *u[BMAX]; /* table stack */
register int w; /* bits before this table == (l * h) */
uInt x[BMAX+1]; /* bit offsets, then code stack */
uIntf *xp; /* pointer into x */
int y; /* number of dummy codes added */
uInt z; /* number of entries in current table */
/* Generate counts for each bit length */
p = c;
#define C0 *p++ = 0;
#define C2 C0 C0 C0 C0
#define C4 C2 C2 C2 C2
C4 /* clear c[]--assume BMAX+1 is 16 */
p = b; i = n;
do {
c[*p++]++; /* assume all entries <= BMAX */
} while (--i);
if (c[0] == n) /* null input--all zero length codes */
{
*t = (inflate_huft *)Z_NULL;
*m = 0;
return Z_OK;
}
/* Find minimum and maximum length, bound *m by those */
l = *m;
for (j = 1; j <= BMAX; j++)
if (c[j])
break;
k = j; /* minimum code length */
if ((uInt)l < j)
l = j;
for (i = BMAX; i; i--)
if (c[i])
break;
g = i; /* maximum code length */
if ((uInt)l > i)
l = i;
*m = l;
/* Adjust last length count to fill out codes, if needed */
for (y = 1 << j; j < i; j++, y <<= 1)
if ((y -= c[j]) < 0)
return Z_DATA_ERROR;
if ((y -= c[i]) < 0)
return Z_DATA_ERROR;
c[i] += y;
/* Generate starting offsets into the value table for each length */
x[1] = j = 0;
p = c + 1; xp = x + 2;
while (--i) { /* note that i == g from above */
*xp++ = (j += *p++);
}
/* Make a table of values in order of bit lengths */
p = b; i = 0;
do {
if ((j = *p++) != 0)
v[x[j]++] = i;
} while (++i < n);
n = x[g]; /* set n to length of v */
/* Generate the Huffman codes and for each, make the table entries */
x[0] = i = 0; /* first Huffman code is zero */
p = v; /* grab values in bit order */
h = -1; /* no tables yet--level -1 */
w = -l; /* bits decoded == (l * h) */
u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
q = (inflate_huft *)Z_NULL; /* ditto */
z = 0; /* ditto */
/* go through the bit lengths (k already is bits in shortest code) */
for (; k <= g; k++)
{
a = c[k];
while (a--)
{
/* here i is the Huffman code of length k bits for value *p */
/* make tables up to required level */
while (k > w + l)
{
h++;
w += l; /* previous table always l bits */
/* compute minimum size table less than or equal to l bits */
z = g - w;
z = z > (uInt)l ? l : z; /* table size upper limit */
if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
{ /* too few codes for k-w bit table */
f -= a + 1; /* deduct codes from patterns left */
xp = c + k;
if (j < z)
while (++j < z) /* try smaller tables up to z bits */
{
if ((f <<= 1) <= *++xp)
break; /* enough codes to use up j bits */
f -= *xp; /* else deduct codes from patterns */
}
}
z = 1 << j; /* table entries for j-bit table */
/* allocate new table */
if (*hn + z > MANY) /* (note: doesn't matter for fixed) */
return Z_MEM_ERROR; /* not enough memory */
u[h] = q = hp + *hn;
*hn += z;
/* connect to last table, if there is one */
if (h)
{
x[h] = i; /* save pattern for backing up */
r.bits = (Byte)l; /* bits to dump before this table */
r.exop = (Byte)j; /* bits in this table */
j = i >> (w - l);
r.base = (uInt)(q - u[h-1] - j); /* offset to this table */
u[h-1][j] = r; /* connect to last table */
}
else
*t = q; /* first table is returned result */
}
/* set up table entry in r */
r.bits = (Byte)(k - w);
if (p >= v + n)
r.exop = 128 + 64; /* out of values--invalid code */
else if (*p < s)
{
r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
r.base = *p++; /* simple code is just the value */
}
else
{
r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
r.base = d[*p++ - s];
}
/* fill code-like entries with r */
f = 1 << (k - w);
for (j = i >> w; j < z; j += f)
q[j] = r;
/* backwards increment the k-bit code i */
for (j = 1 << (k - 1); i & j; j >>= 1)
i ^= j;
i ^= j;
/* backup over finished tables */
mask = (1 << w) - 1; /* needed on HP, cc -O bug */
while ((i & mask) != x[h])
{
h--; /* don't need to update q */
w -= l;
mask = (1 << w) - 1;
}
}
}
/* Return Z_BUF_ERROR if we were given an incomplete table */
return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
}
int inflate_trees_bits(c, bb, tb, hp, z)
uIntf *c; /* 19 code lengths */
uIntf *bb; /* bits tree desired/actual depth */
inflate_huft * FAR *tb; /* bits tree result */
inflate_huft *hp; /* space for trees */
z_streamp z; /* for messages */
{
int r;
uInt hn = 0; /* hufts used in space */
uIntf *v; /* work area for huft_build */
if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
return Z_MEM_ERROR;
r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
tb, bb, hp, &hn, v);
if (r == Z_DATA_ERROR)
z->msg = (char*)"oversubscribed dynamic bit lengths tree";
else if (r == Z_BUF_ERROR || *bb == 0)
{
z->msg = (char*)"incomplete dynamic bit lengths tree";
r = Z_DATA_ERROR;
}
ZFREE(z, v);
return r;
}
int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
uInt nl; /* number of literal/length codes */
uInt nd; /* number of distance codes */
uIntf *c; /* that many (total) code lengths */
uIntf *bl; /* literal desired/actual bit depth */
uIntf *bd; /* distance desired/actual bit depth */
inflate_huft * FAR *tl; /* literal/length tree result */
inflate_huft * FAR *td; /* distance tree result */
inflate_huft *hp; /* space for trees */
z_streamp z; /* for messages */
{
int r;
uInt hn = 0; /* hufts used in space */
uIntf *v; /* work area for huft_build */
/* allocate work area */
if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
return Z_MEM_ERROR;
/* build literal/length tree */
r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
if (r != Z_OK || *bl == 0)
{
if (r == Z_DATA_ERROR)
z->msg = (char*)"oversubscribed literal/length tree";
else if (r != Z_MEM_ERROR)
{
z->msg = (char*)"incomplete literal/length tree";
r = Z_DATA_ERROR;
}
ZFREE(z, v);
return r;
}
/* build distance tree */
r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
if (r != Z_OK || (*bd == 0 && nl > 257))
{
if (r == Z_DATA_ERROR)
z->msg = (char*)"oversubscribed distance tree";
else if (r == Z_BUF_ERROR) {
#ifdef PKZIP_BUG_WORKAROUND
r = Z_OK;
}
#else
z->msg = (char*)"incomplete distance tree";
r = Z_DATA_ERROR;
}
else if (r != Z_MEM_ERROR)
{
z->msg = (char*)"empty distance tree with lengths";
r = Z_DATA_ERROR;
}
ZFREE(z, v);
return r;
#endif
}
/* done */
ZFREE(z, v);
return Z_OK;
}
/* build fixed tables only once--keep them here */
#ifdef BUILDFIXED
local int fixed_built = 0;
#define FIXEDH 544 /* number of hufts used by fixed tables */
local inflate_huft fixed_mem[FIXEDH];
local uInt fixed_bl;
local uInt fixed_bd;
local inflate_huft *fixed_tl;
local inflate_huft *fixed_td;
#else
#include "inffixed.h"
#endif
int inflate_trees_fixed(bl, bd, tl, td, z)
uIntf *bl; /* literal desired/actual bit depth */
uIntf *bd; /* distance desired/actual bit depth */
inflate_huft * FAR *tl; /* literal/length tree result */
inflate_huft * FAR *td; /* distance tree result */
z_streamp z; /* for memory allocation */
{
#ifdef BUILDFIXED
/* build fixed tables if not already */
if (!fixed_built)
{
int k; /* temporary variable */
uInt f = 0; /* number of hufts used in fixed_mem */
uIntf *c; /* length list for huft_build */
uIntf *v; /* work area for huft_build */
/* allocate memory */
if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
return Z_MEM_ERROR;
if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
{
ZFREE(z, c);
return Z_MEM_ERROR;
}
/* literal table */
for (k = 0; k < 144; k++)
c[k] = 8;
for (; k < 256; k++)
c[k] = 9;
for (; k < 280; k++)
c[k] = 7;
for (; k < 288; k++)
c[k] = 8;
fixed_bl = 9;
huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
fixed_mem, &f, v);
/* distance table */
for (k = 0; k < 30; k++)
c[k] = 5;
fixed_bd = 5;
huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
fixed_mem, &f, v);
/* done */
ZFREE(z, v);
ZFREE(z, c);
fixed_built = 1;
}
#endif
*bl = fixed_bl;
*bd = fixed_bd;
*tl = fixed_tl;
*td = fixed_td;
return Z_OK;
}

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