mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-05-08 11:38:01 +03:00
Reworked source tree so it compiles
This commit is contained in:
parent
19e33444e7
commit
8ef16a91f2
164 changed files with 3183 additions and 20134 deletions
148
code/qcommon/Linklist.h
Normal file
148
code/qcommon/Linklist.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// linklist.h:
|
||||
//
|
||||
// WARNING: This file is shared between fgame, cgame and possibly the user interface.
|
||||
// It is instanced in each one of these directories because of the way that SourceSafe works.
|
||||
//
|
||||
|
||||
#ifndef __linklist_h
|
||||
#define __linklist_h
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define NewNode(type) ((type *)Z_Malloc(sizeof(type)))
|
||||
|
||||
#define LL_New(rootnode,type,next,prev) \
|
||||
{ \
|
||||
(rootnode) = NewNode(type); \
|
||||
(rootnode)->prev = (rootnode); \
|
||||
(rootnode)->next = (rootnode); \
|
||||
}
|
||||
|
||||
#define LL_Add(rootnode, newnode, next, prev) \
|
||||
{ \
|
||||
(newnode)->next = (rootnode); \
|
||||
(newnode)->prev = (rootnode)->prev; \
|
||||
(rootnode)->prev->next = (newnode); \
|
||||
(rootnode)->prev = (newnode); \
|
||||
}
|
||||
//MED
|
||||
#define LL_AddFirst(rootnode, newnode, next, prev) \
|
||||
{ \
|
||||
(newnode)->prev = (rootnode); \
|
||||
(newnode)->next = (rootnode)->next; \
|
||||
(rootnode)->next->prev = (newnode); \
|
||||
(rootnode)->next = (newnode); \
|
||||
}
|
||||
|
||||
#define LL_Transfer(oldroot,newroot,next,prev) \
|
||||
{ \
|
||||
if (oldroot->prev != oldroot) \
|
||||
{ \
|
||||
oldroot->prev->next = newroot; \
|
||||
oldroot->next->prev = newroot->prev; \
|
||||
newroot->prev->next = oldroot->next; \
|
||||
newroot->prev = oldroot->prev; \
|
||||
oldroot->next = oldroot; \
|
||||
oldroot->prev = oldroot; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LL_Reverse(root,type,next,prev) \
|
||||
{ \
|
||||
type *newend,*trav,*tprev; \
|
||||
\
|
||||
newend = root->next; \
|
||||
for(trav = root->prev; trav != newend; trav = tprev) \
|
||||
{ \
|
||||
tprev = trav->prev; \
|
||||
LL_Move(trav,newend,next,prev); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define LL_Remove(node,next,prev) \
|
||||
{ \
|
||||
node->prev->next = node->next; \
|
||||
node->next->prev = node->prev; \
|
||||
node->next = node; \
|
||||
node->prev = node; \
|
||||
}
|
||||
|
||||
#define LL_SortedInsertion(rootnode,insertnode,next,prev,type,sortparm) \
|
||||
{ \
|
||||
type *hoya; \
|
||||
\
|
||||
hoya = rootnode->next; \
|
||||
while((hoya != rootnode) && (insertnode->sortparm > hoya->sortparm)) \
|
||||
{ \
|
||||
hoya = hoya->next; \
|
||||
} \
|
||||
LL_Add(hoya,insertnode,next,prev); \
|
||||
}
|
||||
|
||||
#define LL_Move(node,newroot,next,prev) \
|
||||
{ \
|
||||
LL_Remove(node,next,prev); \
|
||||
LL_Add(newroot,node,next,prev); \
|
||||
}
|
||||
|
||||
#define LL_Empty(list,next,prev) \
|
||||
( \
|
||||
((list)->next == (list)) && \
|
||||
((list)->prev == (list)) \
|
||||
)
|
||||
|
||||
#define LL_Free(list) Z_Free(list)
|
||||
#define LL_Reset(list,next,prev) (list)->next = (list)->prev = (list)
|
||||
|
||||
#define LL_SafeRemove(node,next,prev) \
|
||||
{ \
|
||||
if( node->prev ) node->prev->next = node->next; \
|
||||
if( node->next ) node->next->prev = node->prev; \
|
||||
}
|
||||
|
||||
#define LL_SafeAdd(rootnode, newnode, next, prev) \
|
||||
{ \
|
||||
(newnode)->next = NULL; \
|
||||
(newnode)->prev = (rootnode); \
|
||||
if((rootnode)) (rootnode)->next = (newnode); \
|
||||
(rootnode) = (newnode); \
|
||||
}
|
||||
|
||||
#define LL_SafeAddFirst(rootnode, newnode, next, prev) \
|
||||
{ \
|
||||
(newnode)->prev = NULL; \
|
||||
(newnode)->next = (rootnode); \
|
||||
if((rootnode)) (rootnode)->prev = (newnode); \
|
||||
(rootnode) = (newnode); \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
915
code/qcommon/class.cpp
Normal file
915
code/qcommon/class.cpp
Normal file
|
@ -0,0 +1,915 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// class.cpp: General class.
|
||||
|
||||
#include "class.h"
|
||||
#include "listener.h"
|
||||
#include <q_shared.h>
|
||||
|
||||
#ifdef GAME_DLL
|
||||
#include "level.h"
|
||||
#include <scriptmaster.h>
|
||||
|
||||
#define CLASS_Printf if( level.current_map ) glbs.Printf
|
||||
#define CLASS_DPrintf if( level.current_map ) glbs.DPrintf
|
||||
#define CLASS_Error if( level.current_map ) glbs.Error
|
||||
#else
|
||||
#define CLASS_Printf Com_Printf
|
||||
#define CLASS_DPrintf Com_DPrintf
|
||||
#define CLASS_Error Com_Error
|
||||
#endif
|
||||
|
||||
ClassDef *ClassDef::classlist;
|
||||
int ClassDef::numclasses;
|
||||
|
||||
int ClassDef::dump_numclasses;
|
||||
int ClassDef::dump_numevents;
|
||||
Container< int > ClassDef::sortedList;
|
||||
Container< ClassDef * > ClassDef::sortedClassList;
|
||||
|
||||
int ClassDef::compareClasses( const void *arg1, const void *arg2 )
|
||||
{
|
||||
ClassDef *c1 = *( ClassDef ** )arg1;
|
||||
ClassDef *c2 = *( ClassDef ** )arg2;
|
||||
|
||||
return Q_stricmp( c1->classname, c2->classname );
|
||||
}
|
||||
|
||||
void ClassDef::SortClassList( Container< ClassDef * > *sortedList )
|
||||
{
|
||||
ClassDef *c;
|
||||
|
||||
sortedList->Resize( numclasses );
|
||||
|
||||
for( c = classlist->next; c != classlist; c = c->next )
|
||||
{
|
||||
sortedList->AddObject( c );
|
||||
}
|
||||
|
||||
qsort( ( void * )sortedList->AddressOfObjectAt( 1 ),
|
||||
( size_t )sortedList->NumObjects(),
|
||||
sizeof( ClassDef * ), compareClasses );
|
||||
}
|
||||
|
||||
ClassDef *getClassForID( const char *name )
|
||||
{
|
||||
ClassDef *classlist = ClassDef::classlist;
|
||||
ClassDef *c;
|
||||
|
||||
for( c = classlist->next; c != classlist; c = c->next )
|
||||
{
|
||||
if( c->classID && !Q_stricmp( c->classID, name ) )
|
||||
{
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ClassDef *getClass( const char *name )
|
||||
{
|
||||
if( name == NULL || name == "" ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ClassDef *list = ClassDef::classlist;
|
||||
ClassDef *c;
|
||||
|
||||
for( c = list->next; c != list; c = c->next )
|
||||
{
|
||||
if( Q_stricmp( c->classname, name ) == 0 ) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ClassDef *getClassList
|
||||
(
|
||||
void
|
||||
)
|
||||
|
||||
{
|
||||
return ClassDef::classlist;
|
||||
}
|
||||
|
||||
void listAllClasses
|
||||
(
|
||||
void
|
||||
)
|
||||
|
||||
{
|
||||
ClassDef *c;
|
||||
ClassDef *list = ClassDef::classlist;
|
||||
|
||||
for( c = list->next; c != list; c = c->next )
|
||||
{
|
||||
CLASS_DPrintf( "%s\n", c->classname );
|
||||
}
|
||||
}
|
||||
|
||||
void listInheritanceOrder
|
||||
(
|
||||
const char *classname
|
||||
)
|
||||
|
||||
{
|
||||
ClassDef *cls;
|
||||
ClassDef *c;
|
||||
|
||||
cls = getClass( classname );
|
||||
if( !cls )
|
||||
{
|
||||
CLASS_DPrintf( "Unknown class: %s\n", classname );
|
||||
return;
|
||||
}
|
||||
for( c = cls; c != NULL; c = c->super )
|
||||
{
|
||||
CLASS_DPrintf( "%s\n", c->classname );
|
||||
}
|
||||
}
|
||||
|
||||
qboolean checkInheritance( const ClassDef *superclass, const ClassDef *subclass )
|
||||
{
|
||||
const ClassDef *c;
|
||||
|
||||
for( c = subclass; c != NULL; c = c->super )
|
||||
{
|
||||
if ( c == superclass )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean checkInheritance( ClassDef *superclass, const char *subclass )
|
||||
{
|
||||
ClassDef *c;
|
||||
|
||||
c = getClass( subclass );
|
||||
|
||||
if ( c == NULL )
|
||||
{
|
||||
CLASS_DPrintf( "Unknown class: %s\n", subclass );
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkInheritance( superclass, c );
|
||||
}
|
||||
|
||||
qboolean checkInheritance( const char *superclass, const char *subclass )
|
||||
{
|
||||
ClassDef *c1;
|
||||
ClassDef *c2;
|
||||
|
||||
c1 = getClass( superclass );
|
||||
c2 = getClass( subclass );
|
||||
|
||||
if ( c1 == NULL )
|
||||
{
|
||||
CLASS_DPrintf( "Unknown class: %s\n", superclass );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( c2 == NULL )
|
||||
{
|
||||
CLASS_DPrintf( "Unknown class: %s\n", subclass );
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkInheritance( c1, c2 );
|
||||
}
|
||||
|
||||
void CLASS_Print( FILE *class_file, const char *fmt, ... )
|
||||
{
|
||||
va_list argptr;
|
||||
char text[ 1024 ];
|
||||
|
||||
va_start( argptr, fmt );
|
||||
vsprintf( text, fmt, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
if( class_file )
|
||||
fprintf( class_file, text );
|
||||
else
|
||||
CLASS_DPrintf( text );
|
||||
}
|
||||
|
||||
size_t totalmemallocated = 0;
|
||||
unsigned int numclassesallocated = 0;
|
||||
|
||||
bool classInited = false;
|
||||
|
||||
#ifndef _DEBUG_MEM
|
||||
void *Class::operator new( size_t s )
|
||||
{
|
||||
size_t *p;
|
||||
|
||||
if ( s == 0 )
|
||||
return 0;
|
||||
|
||||
s += sizeof( size_t );
|
||||
|
||||
#ifdef GAME_DLL
|
||||
p = ( size_t * )gi.Malloc( s );
|
||||
#elif defined ( CGAME_DLL )
|
||||
p = ( size_t * )cgi.Malloc( s );
|
||||
#endif
|
||||
|
||||
*p = s;
|
||||
|
||||
totalmemallocated += s;
|
||||
numclassesallocated++;
|
||||
|
||||
p++;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void Class::operator delete( void *ptr )
|
||||
{
|
||||
size_t *p = ( ( size_t * )ptr ) - 1;
|
||||
|
||||
totalmemallocated -= *p;
|
||||
numclassesallocated--;
|
||||
|
||||
#ifdef GAME_DLL
|
||||
gi.Free( p );
|
||||
#elif defined ( CGAME_DLL )
|
||||
cgi.Free( p );
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Class::Class()
|
||||
{
|
||||
SafePtrList = NULL;
|
||||
}
|
||||
|
||||
Class::~Class()
|
||||
{
|
||||
ClearSafePointers();
|
||||
}
|
||||
|
||||
void Class::Archive( Archiver& arc )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Class::ClearSafePointers( void )
|
||||
{
|
||||
while( SafePtrList != NULL ) {
|
||||
SafePtrList->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Class::warning( const char *function, const char *format, ... )
|
||||
{
|
||||
char buffer[ MAX_STRING_CHARS ];
|
||||
const char *classname;
|
||||
va_list va;
|
||||
|
||||
va_start( va, format );
|
||||
vsprintf( buffer, format, va );
|
||||
|
||||
classname = classinfo()->classname;
|
||||
|
||||
#ifdef GAME_DLL
|
||||
gi.DPrintf(
|
||||
#elif defined CGAME_DLL
|
||||
cgi.DPrintf(
|
||||
#else
|
||||
Com_DPrintf(
|
||||
#endif
|
||||
"%s::%s : %s\n", classname, function, buffer );
|
||||
}
|
||||
|
||||
void Class::error
|
||||
(
|
||||
const char *function,
|
||||
const char *fmt,
|
||||
...
|
||||
)
|
||||
|
||||
{
|
||||
va_list argptr;
|
||||
char text[ 1024 ];
|
||||
|
||||
va_start( argptr, fmt );
|
||||
vsprintf( text, fmt, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
if( getClassID() )
|
||||
{
|
||||
CLASS_Error( ERR_DROP, "%s::%s : %s\n", getClassID(), function, text );
|
||||
}
|
||||
else
|
||||
{
|
||||
CLASS_Error( ERR_DROP, "%s::%s : %s\n", getClassname(), function, text );
|
||||
}
|
||||
}
|
||||
|
||||
ClassDef::ClassDef()
|
||||
{
|
||||
this->classname = NULL;
|
||||
this->classID = NULL;
|
||||
this->superclass = NULL;
|
||||
this->responses = NULL;
|
||||
this->numEvents = 0;
|
||||
this->responseLookup = NULL;
|
||||
this->newInstance = NULL;
|
||||
this->classSize = 0;
|
||||
this->super = NULL;
|
||||
this->prev = this;
|
||||
this->next = this;
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
this->waitTillSet = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
ClassDef::ClassDef( const char *classname, const char *classID, const char *superclass, ResponseDef<Class> *responses,
|
||||
void *( *newInstance )( void ), int classSize )
|
||||
{
|
||||
ClassDef *node;
|
||||
|
||||
if( classlist == NULL ) {
|
||||
classlist = new ClassDef;
|
||||
}
|
||||
|
||||
this->classname = classname;
|
||||
this->classID = classID;
|
||||
this->superclass = superclass;
|
||||
this->responses = responses;
|
||||
this->numEvents = 0;
|
||||
this->responseLookup = NULL;
|
||||
this->newInstance = newInstance;
|
||||
this->classSize = classSize;
|
||||
this->super = getClass( superclass );
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
this->waitTillSet = NULL;
|
||||
#endif
|
||||
|
||||
if( !classID ) {
|
||||
this->classID = "";
|
||||
}
|
||||
|
||||
for( node = classlist->next; node != classlist; node = node->next )
|
||||
{
|
||||
if( ( node->super == NULL ) && ( !Q_stricmp( node->superclass, this->classname ) ) &&
|
||||
( Q_stricmp( node->classname, "Class" ) ) )
|
||||
{
|
||||
node->super = this;
|
||||
}
|
||||
}
|
||||
|
||||
// Add to front of list
|
||||
LL_Add( classlist, this, prev, next );
|
||||
|
||||
numclasses++;
|
||||
}
|
||||
|
||||
ClassDef::~ClassDef()
|
||||
{
|
||||
ClassDef *node;
|
||||
|
||||
if( classlist != this )
|
||||
{
|
||||
LL_Remove( this, prev, next );
|
||||
|
||||
// Check if any subclasses were initialized before their superclass
|
||||
for( node = classlist->next; node != classlist; node = node->next )
|
||||
{
|
||||
if( node->super == this )
|
||||
{
|
||||
node->super = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the head of the list is deleted before the list is cleared, then we may have problems
|
||||
assert( this->next == this->prev );
|
||||
}
|
||||
|
||||
if( responseLookup )
|
||||
{
|
||||
delete[] responseLookup;
|
||||
responseLookup = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
|
||||
void ClassDef::AddWaitTill( str s )
|
||||
{
|
||||
return AddWaitTill( Director.AddString( s ) );
|
||||
}
|
||||
|
||||
void ClassDef::AddWaitTill( const_str s )
|
||||
{
|
||||
if( !waitTillSet )
|
||||
{
|
||||
waitTillSet = new con_set < const_str, const_str >;
|
||||
}
|
||||
|
||||
waitTillSet->addKeyValue( s ) = s;
|
||||
}
|
||||
|
||||
void ClassDef::RemoveWaitTill( str s )
|
||||
{
|
||||
|
||||
return RemoveWaitTill( Director.AddString( s ) );
|
||||
}
|
||||
|
||||
void ClassDef::RemoveWaitTill( const_str s )
|
||||
{
|
||||
if( waitTillSet )
|
||||
{
|
||||
waitTillSet->remove( s );
|
||||
}
|
||||
}
|
||||
|
||||
bool ClassDef::WaitTillDefined( str s )
|
||||
{
|
||||
return WaitTillDefined( Director.AddString( s ) );
|
||||
}
|
||||
|
||||
bool ClassDef::WaitTillDefined( const_str s )
|
||||
{
|
||||
if( !waitTillSet )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return waitTillSet->findKeyValue( s ) != NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
EventDef *ClassDef::GetDef( int eventnum )
|
||||
{
|
||||
ResponseDef< Class > *r = responseLookup[ eventnum ];
|
||||
|
||||
if( r )
|
||||
{
|
||||
return r->def;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ClassDef::GetFlags( Event *event )
|
||||
{
|
||||
EventDef *def = GetDef( event->eventnum );
|
||||
|
||||
if( def )
|
||||
{
|
||||
return def->flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ClassDef::BuildResponseList( void )
|
||||
{
|
||||
ClassDef *c;
|
||||
ResponseDef<Class> *r;
|
||||
int ev;
|
||||
int i;
|
||||
qboolean *set;
|
||||
int num;
|
||||
|
||||
if( responseLookup )
|
||||
{
|
||||
delete[] responseLookup;
|
||||
responseLookup = NULL;
|
||||
}
|
||||
|
||||
num = Event::NumEventCommands();//size will be total event count, because it WAS faster to look for an event via eventnum
|
||||
//nowadays there's not much overhead in performance, TODO: change size to appropriate.
|
||||
responseLookup = ( ResponseDef< Class > ** )new char[ sizeof( ResponseDef< Class > * ) * num ];
|
||||
memset( responseLookup, 0, sizeof( ResponseDef< Class > * ) * num );
|
||||
|
||||
set = new qboolean[ num ];
|
||||
memset( set, 0, sizeof( qboolean ) * num );
|
||||
|
||||
this->numEvents = num;
|
||||
|
||||
for( c = this; c != NULL; c = c->super )
|
||||
{
|
||||
r = c->responses;
|
||||
|
||||
if( r )
|
||||
{
|
||||
for( i = 0; r[ i ].event != NULL; i++ )
|
||||
{
|
||||
ev = ( int )r[ i ].event->eventnum;
|
||||
r[ i ].def = r[ i ].event->getInfo();
|
||||
|
||||
if( !set[ ev ] )
|
||||
{
|
||||
set[ ev ] = true;
|
||||
|
||||
if( r[ i ].response )
|
||||
{
|
||||
responseLookup[ ev ] = &r[ i ];
|
||||
}
|
||||
else
|
||||
{
|
||||
responseLookup[ ev ] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] set;
|
||||
}
|
||||
|
||||
void ClassDef::BuildEventResponses( void )
|
||||
{
|
||||
ClassDef *c;
|
||||
int amount;
|
||||
int numclasses;
|
||||
|
||||
amount = 0;
|
||||
numclasses = 0;
|
||||
|
||||
for( c = classlist->next; c != classlist; c = c->next )
|
||||
{
|
||||
c->BuildResponseList();
|
||||
|
||||
amount += c->numEvents * sizeof( Response * );
|
||||
numclasses++;
|
||||
}
|
||||
|
||||
CLASS_DPrintf( "\n------------------\nEvent system initialized: "
|
||||
"%d classes %d events %d total memory in response list\n\n", numclasses, Event::NumEventCommands(), amount );
|
||||
}
|
||||
|
||||
const char *Class::getClassID( void ) const
|
||||
{
|
||||
return classinfo()->classID;
|
||||
}
|
||||
|
||||
const char *Class::getClassname( void ) const
|
||||
{
|
||||
return classinfo()->classname;
|
||||
}
|
||||
|
||||
const char *Class::getSuperclass( void ) const
|
||||
{
|
||||
return classinfo()->superclass;
|
||||
}
|
||||
|
||||
#define MAX_INHERITANCE 64
|
||||
void ClassEvents
|
||||
(
|
||||
const char *classname,
|
||||
qboolean print_to_disk
|
||||
)
|
||||
|
||||
{
|
||||
ClassDef *c;
|
||||
ResponseDef<Class> *r;
|
||||
int ev;
|
||||
int i, j;
|
||||
qboolean *set;
|
||||
int num, orderNum;
|
||||
Event **events;
|
||||
byte *order;
|
||||
FILE *class_file;
|
||||
str classNames[ MAX_INHERITANCE ];
|
||||
str class_filename;
|
||||
|
||||
c = getClass( classname );
|
||||
if( !c )
|
||||
{
|
||||
CLASS_DPrintf( "Unknown class: %s\n", classname );
|
||||
return;
|
||||
}
|
||||
|
||||
class_file = NULL;
|
||||
|
||||
if( print_to_disk )
|
||||
{
|
||||
class_filename = str( classname ) + ".txt";
|
||||
class_file = fopen( class_filename.c_str(), "w" );
|
||||
if( class_file == NULL )
|
||||
return;
|
||||
}
|
||||
|
||||
num = Event::NumEventCommands();
|
||||
|
||||
set = new qboolean[ num ];
|
||||
memset( set, 0, sizeof( qboolean ) * num );
|
||||
|
||||
events = new Event *[ num ];
|
||||
memset( events, 0, sizeof( Event * ) * num );
|
||||
|
||||
order = new byte[ num ];
|
||||
memset( order, 0, sizeof( byte ) * num );
|
||||
|
||||
orderNum = 0;
|
||||
for( ; c != NULL; c = c->super )
|
||||
{
|
||||
if( orderNum < MAX_INHERITANCE )
|
||||
{
|
||||
classNames[ orderNum ] = c->classname;
|
||||
}
|
||||
r = c->responses;
|
||||
if( r )
|
||||
{
|
||||
for( i = 0; r[ i ].event != NULL; i++ )
|
||||
{
|
||||
ev = ( int )r[ i ].event->eventnum;
|
||||
if( !set[ ev ] )
|
||||
{
|
||||
set[ ev ] = true;
|
||||
|
||||
if( r[ i ].response )
|
||||
{
|
||||
events[ ev ] = r[ i ].event;
|
||||
order[ ev ] = orderNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
orderNum++;
|
||||
}
|
||||
|
||||
CLASS_Print( class_file, "********************************************************\n" );
|
||||
CLASS_Print( class_file, "********************************************************\n" );
|
||||
CLASS_Print( class_file, "* All Events For Class: %s\n", classname );
|
||||
CLASS_Print( class_file, "********************************************************\n" );
|
||||
CLASS_Print( class_file, "********************************************************\n\n" );
|
||||
|
||||
for( j = orderNum - 1; j >= 0; j-- )
|
||||
{
|
||||
CLASS_Print( class_file, "\n********************************************************\n" );
|
||||
CLASS_Print( class_file, "* Class: %s\n", classNames[ j ].c_str() );
|
||||
CLASS_Print( class_file, "********************************************************\n\n" );
|
||||
for( i = 1; i < num; i++ )
|
||||
{
|
||||
int index;
|
||||
|
||||
index = ClassDef::sortedList.ObjectAt( i );
|
||||
if( events[ index ] && ( order[ index ] == j ) )
|
||||
{
|
||||
Event::eventDefList[ events[ index ] ].PrintEventDocumentation( class_file, qfalse );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( class_file != NULL )
|
||||
{
|
||||
CLASS_DPrintf( "Printed class info to file %s\n", class_filename.c_str() );
|
||||
fclose( class_file );
|
||||
}
|
||||
|
||||
delete[] events;
|
||||
delete[] order;
|
||||
delete[] set;
|
||||
}
|
||||
|
||||
void DumpClass
|
||||
(
|
||||
FILE * class_file,
|
||||
const char * className
|
||||
)
|
||||
|
||||
{
|
||||
ClassDef *c;
|
||||
ResponseDef<Class> *r;
|
||||
int ev;
|
||||
int i;
|
||||
int num, num2;
|
||||
Event **events;
|
||||
|
||||
c = getClass( className );
|
||||
if( !c )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
num = Event::commandList.size();
|
||||
num2 = Event::NumEventCommands();
|
||||
|
||||
events = new Event *[ num2 ];
|
||||
memset( events, 0, sizeof( Event * ) * num2 );
|
||||
|
||||
// gather event responses for this class
|
||||
r = c->responses;
|
||||
if( r )
|
||||
{
|
||||
for( i = 0; r[ i ].event != NULL; i++ )
|
||||
{
|
||||
ev = ( int )r[ i ].event->eventnum;
|
||||
if( r[ i ].response )
|
||||
{
|
||||
events[ ev ] = r[ i ].event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLASS_Print( class_file, "\n" );
|
||||
if( c->classID[ 0 ] )
|
||||
{
|
||||
CLASS_Print( class_file, "<h2> <a name=\"%s\">%s (<i>%s</i>)</a>", c->classname, c->classname, c->classID );
|
||||
}
|
||||
else
|
||||
{
|
||||
CLASS_Print( class_file, "<h2> <a name=\"%s\">%s</a>", c->classname, c->classname );
|
||||
}
|
||||
|
||||
// print out lineage
|
||||
for( c = c->super; c != NULL; c = c->super )
|
||||
{
|
||||
CLASS_Print( class_file, " -> <a href=\"#%s\">%s</a>", c->classname, c->classname );
|
||||
}
|
||||
CLASS_Print( class_file, "</h2>\n" );
|
||||
|
||||
ClassDef::dump_numclasses++;
|
||||
|
||||
CLASS_Print( class_file, "<BLOCKQUOTE>\n" );
|
||||
for( i = 1; i < num; i++ )
|
||||
{
|
||||
int index;
|
||||
|
||||
index = ClassDef::sortedList.ObjectAt( i );
|
||||
if( events[ index ] )
|
||||
{
|
||||
Event::eventDefList[ events[ index ] ].PrintEventDocumentation( class_file, qtrue );
|
||||
ClassDef::dump_numevents++;
|
||||
}
|
||||
}
|
||||
CLASS_Print( class_file, "</BLOCKQUOTE>\n" );
|
||||
delete[] events;
|
||||
}
|
||||
|
||||
|
||||
#define MAX_CLASSES 1024
|
||||
void DumpAllClasses
|
||||
(
|
||||
void
|
||||
)
|
||||
|
||||
{
|
||||
int i, num;
|
||||
ClassDef *c;
|
||||
FILE * class_file;
|
||||
str class_filename;
|
||||
str class_title;
|
||||
str classes[ MAX_CLASSES ];
|
||||
|
||||
#if defined( GAME_DLL )
|
||||
class_filename = "g_allclasses.html";
|
||||
class_title = "Game Module";
|
||||
#elif defined( CGAME_DLL )
|
||||
class_filename = "cg_allclasses.html";
|
||||
class_title = "Client Game Module";
|
||||
#else
|
||||
class_filename = "cl_allclasses.html";
|
||||
class_title = "Client Module";
|
||||
#endif
|
||||
|
||||
class_file = fopen( class_filename.c_str(), "w" );
|
||||
if( class_file == NULL )
|
||||
return;
|
||||
|
||||
// construct the HTML header for the document
|
||||
CLASS_Print( class_file, "<HTML>\n" );
|
||||
CLASS_Print( class_file, "<HEAD>\n" );
|
||||
CLASS_Print( class_file, "<Title>%s Classes</Title>\n", class_title.c_str() );
|
||||
CLASS_Print( class_file, "</HEAD>\n" );
|
||||
CLASS_Print( class_file, "<BODY>\n" );
|
||||
CLASS_Print( class_file, "<H1>\n" );
|
||||
CLASS_Print( class_file, "<center>%s Classes</center>\n", class_title.c_str() );
|
||||
CLASS_Print( class_file, "</H1>\n" );
|
||||
#if defined( GAME_DLL )
|
||||
//
|
||||
// print out some commonly used classnames
|
||||
//
|
||||
CLASS_Print( class_file, "<h2>" );
|
||||
CLASS_Print( class_file, "<a href=\"#Actor\">Actor</a>, " );
|
||||
CLASS_Print( class_file, "<a href=\"#Animate\">Animate</a>, " );
|
||||
CLASS_Print( class_file, "<a href=\"#Entity\">Entity</a>, " );
|
||||
CLASS_Print( class_file, "<a href=\"#ScriptSlave\">ScriptSlave</a>, " );
|
||||
CLASS_Print( class_file, "<a href=\"#ScriptThread\">ScriptThread</a>, " );
|
||||
CLASS_Print( class_file, "<a href=\"#Sentient\">Sentient</a>, " );
|
||||
CLASS_Print( class_file, "<a href=\"#StateMap\">StateMap</a>, " );
|
||||
CLASS_Print( class_file, "<a href=\"#Trigger\">Trigger</a>, " );
|
||||
CLASS_Print( class_file, "<a href=\"#World\">World</a>" );
|
||||
CLASS_Print( class_file, "</h2>" );
|
||||
#endif
|
||||
|
||||
ClassDef::dump_numclasses = 0;
|
||||
ClassDef::dump_numevents = 0;
|
||||
|
||||
ClassDef::sortedList.ClearObjectList();
|
||||
ClassDef::sortedClassList.ClearObjectList();
|
||||
|
||||
Event::SortEventList( &ClassDef::sortedList );
|
||||
ClassDef::SortClassList( &ClassDef::sortedClassList );
|
||||
|
||||
num = ClassDef::sortedClassList.NumObjects();
|
||||
|
||||
// go through and process each class from smallest to greatest
|
||||
for( i = 1; i <= num; i++ )
|
||||
{
|
||||
c = ClassDef::sortedClassList.ObjectAt( i );
|
||||
DumpClass( class_file, c->classname );
|
||||
}
|
||||
|
||||
if( class_file != NULL )
|
||||
{
|
||||
CLASS_Print( class_file, "<H2>\n" );
|
||||
CLASS_Print( class_file, "%d %s Classes.<BR>%d %s Events.\n", ClassDef::dump_numclasses, class_title.c_str(), ClassDef::dump_numevents, class_title.c_str() );
|
||||
CLASS_Print( class_file, "</H2>\n" );
|
||||
CLASS_Print( class_file, "</BODY>\n" );
|
||||
CLASS_Print( class_file, "</HTML>\n" );
|
||||
CLASS_DPrintf( "Dumped all classes to file %s\n", class_filename.c_str() );
|
||||
fclose( class_file );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
qboolean Class::inheritsFrom( ClassDef *c ) const
|
||||
{
|
||||
return checkInheritance( c, classinfo() );
|
||||
}
|
||||
|
||||
qboolean Class::inheritsFrom( const char * name ) const
|
||||
{
|
||||
ClassDef *c;
|
||||
|
||||
c = getClass( name );
|
||||
|
||||
if ( c == NULL )
|
||||
{
|
||||
CLASS_Printf( "Unknown class: %s\n", name );
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkInheritance( c, classinfo() );
|
||||
}
|
||||
|
||||
qboolean Class::isInheritedBy( const char * name ) const
|
||||
{
|
||||
ClassDef *c;
|
||||
|
||||
c = getClass( name );
|
||||
|
||||
if ( c == NULL )
|
||||
{
|
||||
CLASS_DPrintf( "Unknown class: %s\n", name );
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkInheritance( classinfo(), c );
|
||||
}
|
||||
|
||||
qboolean Class::isInheritedBy( ClassDef *c ) const
|
||||
{
|
||||
return checkInheritance( classinfo(), c );
|
||||
}
|
||||
|
||||
ClassDefHook::ClassDefHook()
|
||||
{
|
||||
this->classdef = NULL;
|
||||
}
|
||||
|
||||
CLASS_DECLARATION( NULL, Class, NULL )
|
||||
{
|
||||
{ NULL, NULL }
|
||||
};
|
280
code/qcommon/class.h
Normal file
280
code/qcommon/class.h
Normal file
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// class.h: General class
|
||||
|
||||
#ifndef __CLASS_H__
|
||||
#define __CLASS_H__
|
||||
|
||||
#include "q_shared.h"
|
||||
#include "container.h"
|
||||
#include "con_set.h"
|
||||
#include "str.h"
|
||||
|
||||
#include "const_str.h"
|
||||
|
||||
class Class;
|
||||
class Event;
|
||||
|
||||
#define isSubclassOf( classname )inheritsFrom( &classname::ClassInfo )
|
||||
#define isSuperclassOf( classname )isInheritedBy( &classname::ClassInfo )
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
|
||||
#define CLASS_DECLARATION( parentclass, classname, classid ) \
|
||||
ClassDef classname::ClassInfo \
|
||||
( \
|
||||
#classname, classid, #parentclass, \
|
||||
(ResponseDef<Class> *)classname::Responses, \
|
||||
classname::_newInstance, sizeof( classname ) \
|
||||
); \
|
||||
void *classname::_newInstance( void ) \
|
||||
{ \
|
||||
return new classname; \
|
||||
} \
|
||||
ClassDef *classname::classinfo( void ) const \
|
||||
{ \
|
||||
return &(classname::ClassInfo); \
|
||||
} \
|
||||
ClassDef *classname::classinfostatic( void ) \
|
||||
{ \
|
||||
return &(classname::ClassInfo); \
|
||||
} \
|
||||
void classname::AddWaitTill( str s ) \
|
||||
{ \
|
||||
classname::ClassInfo.AddWaitTill( s ); \
|
||||
} \
|
||||
void classname::AddWaitTill( const_str s ) \
|
||||
{ \
|
||||
classname::ClassInfo.AddWaitTill( s ); \
|
||||
} \
|
||||
void classname::RemoveWaitTill( str s ) \
|
||||
{ \
|
||||
classname::ClassInfo.RemoveWaitTill( s ); \
|
||||
} \
|
||||
void classname::RemoveWaitTill( const_str s ) \
|
||||
{ \
|
||||
classname::ClassInfo.RemoveWaitTill( s ); \
|
||||
} \
|
||||
bool classname::WaitTillDefined( str s ) \
|
||||
{ \
|
||||
return classname::ClassInfo.WaitTillDefined( s ); \
|
||||
} \
|
||||
bool classname::WaitTillDefined( const_str s ) \
|
||||
{ \
|
||||
return classname::ClassInfo.WaitTillDefined( s ); \
|
||||
} \
|
||||
ResponseDef<classname> classname::Responses[] =
|
||||
|
||||
#define CLASS_PROTOTYPE( classname ) \
|
||||
public: \
|
||||
static ClassDef ClassInfo; \
|
||||
static ClassDefHook _ClassInfo_; \
|
||||
static void *_newInstance( void ); \
|
||||
static ClassDef *classinfostatic(void); \
|
||||
virtual ClassDef *classinfo(void) const; \
|
||||
static void AddWaitTill( str s ); \
|
||||
static void AddWaitTill( const_str s ); \
|
||||
static void RemoveWaitTill( str s ); \
|
||||
static void RemoveWaitTill( const_str s ); \
|
||||
static bool WaitTillDefined( str s ); \
|
||||
static bool WaitTillDefined( const_str s ); \
|
||||
static ResponseDef<classname> Responses[]
|
||||
|
||||
#else
|
||||
|
||||
#define CLASS_DECLARATION( parentclass, classname, classid ) \
|
||||
ClassDef classname::ClassInfo \
|
||||
( \
|
||||
#classname, classid, #parentclass, \
|
||||
(ResponseDef<Class> *)classname::Responses, \
|
||||
classname::_newInstance, sizeof( classname ) \
|
||||
); \
|
||||
void *classname::_newInstance( void ) \
|
||||
{ \
|
||||
return new classname; \
|
||||
} \
|
||||
ClassDef *classname::classinfo( void ) const \
|
||||
{ \
|
||||
return &(classname::ClassInfo); \
|
||||
} \
|
||||
ClassDef *classname::classinfostatic( void ) \
|
||||
{ \
|
||||
return &(classname::ClassInfo); \
|
||||
} \
|
||||
ResponseDef<classname> classname::Responses[] =
|
||||
|
||||
#define CLASS_PROTOTYPE( classname ) \
|
||||
public: \
|
||||
static ClassDef ClassInfo; \
|
||||
static ClassDefHook _ClassInfo_; \
|
||||
static void *_newInstance( void ); \
|
||||
static ClassDef *classinfostatic(void); \
|
||||
virtual ClassDef *classinfo(void) const; \
|
||||
static ResponseDef<classname> Responses[]
|
||||
|
||||
#endif
|
||||
|
||||
typedef void ( Class::*Response )( Event *ev );
|
||||
|
||||
class EventDef;
|
||||
|
||||
template< class Type >
|
||||
struct ResponseDef
|
||||
{
|
||||
Event *event;
|
||||
void ( Type::*response )( Event *ev );
|
||||
EventDef *def;
|
||||
};
|
||||
|
||||
class ClassDef
|
||||
{
|
||||
public:
|
||||
const char *classname;
|
||||
const char *classID;
|
||||
const char *superclass;
|
||||
void *(*newInstance)(void);
|
||||
int classSize;
|
||||
ResponseDef<Class> *responses;
|
||||
ResponseDef<Class> **responseLookup;
|
||||
ClassDef *super;
|
||||
ClassDef *next;
|
||||
ClassDef *prev;
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
con_set<const_str, const_str> *waitTillSet;
|
||||
#endif
|
||||
|
||||
int numEvents;
|
||||
|
||||
static ClassDef *classlist;
|
||||
static int numclasses;
|
||||
|
||||
static void BuildEventResponses();
|
||||
|
||||
void BuildResponseList();
|
||||
|
||||
static int dump_numclasses;
|
||||
static int dump_numevents;
|
||||
static Container< int > sortedList;
|
||||
static Container< ClassDef * > sortedClassList;
|
||||
|
||||
ClassDef();
|
||||
~ClassDef();
|
||||
|
||||
static int compareClasses( const void *arg1, const void *arg2 );
|
||||
static void SortClassList( Container< ClassDef * > *sortedList );
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
void AddWaitTill( str s );
|
||||
void AddWaitTill( const_str s );
|
||||
void RemoveWaitTill( str s );
|
||||
void RemoveWaitTill( const_str s );
|
||||
bool WaitTillDefined( str s );
|
||||
bool WaitTillDefined( const_str s );
|
||||
#endif
|
||||
|
||||
/* Create-a-class function */
|
||||
ClassDef( const char *classname, const char *classID, const char *superclass, ResponseDef<Class> *responses,
|
||||
void *( *newInstance )( void ), int classSize );
|
||||
void CreateInternal( const char *classname, const char *classID, const char *superclass, ResponseDef<Class> *responses,
|
||||
void *( *newInstance )( void ), int classSize );
|
||||
void CreateInternalWin( const char *classname, const char *classID, const char *superclass, ResponseDef<Class> *responses,
|
||||
void *( *newInstance )( void ), int classSize );
|
||||
|
||||
EventDef *GetDef( int eventnum );
|
||||
int GetFlags( Event *event );
|
||||
|
||||
void Destroy();
|
||||
};
|
||||
|
||||
ClassDef *getClassList( void );
|
||||
qboolean checkInheritance( const ClassDef *superclass, const ClassDef *subclass );
|
||||
qboolean checkInheritance( ClassDef *superclass, const char *subclass );
|
||||
qboolean checkInheritance( const char *superclass, const char *subclass );
|
||||
void CLASS_Print( FILE *class_file, const char *fmt, ... );
|
||||
void ClassEvents( const char *classname, qboolean print_to_disk );
|
||||
void DumpClass( FILE * class_file, const char * className );
|
||||
void DumpAllClasses( void );
|
||||
|
||||
class ClassDefHook
|
||||
{
|
||||
private:
|
||||
ClassDef *classdef;
|
||||
|
||||
public:
|
||||
//void * operator new( size_t );
|
||||
//void operator delete( void * );
|
||||
|
||||
ClassDefHook();
|
||||
~ClassDefHook();
|
||||
|
||||
/* Hook-a-class function */
|
||||
ClassDefHook( ClassDef * classdef, ResponseDef<Class> *responses );
|
||||
};
|
||||
|
||||
ClassDef *getClassForID( const char *name );
|
||||
ClassDef *getClass( const char * name );
|
||||
ClassDef *getClassList( void );
|
||||
void listAllClasses( void );
|
||||
void listInheritanceOrder( const char *classname );
|
||||
|
||||
class SafePtrBase;
|
||||
class Archiver;
|
||||
|
||||
class Class
|
||||
{
|
||||
public:
|
||||
SafePtrBase *SafePtrList;
|
||||
|
||||
private:
|
||||
void ClearSafePointers();
|
||||
|
||||
public:
|
||||
CLASS_PROTOTYPE( Class );
|
||||
|
||||
#ifndef _DEBUG_MEM
|
||||
void * operator new( size_t );
|
||||
void operator delete( void * );
|
||||
#endif
|
||||
|
||||
Class();
|
||||
virtual ~Class();
|
||||
|
||||
virtual void Archive( Archiver& arc );
|
||||
|
||||
const char *getClassID( void ) const;
|
||||
const char *getClassname( void ) const;
|
||||
const char *getSuperclass( void ) const;
|
||||
|
||||
qboolean inheritsFrom( ClassDef *c ) const;
|
||||
qboolean inheritsFrom( const char * name ) const;
|
||||
qboolean isInheritedBy( const char * name ) const;
|
||||
qboolean isInheritedBy( ClassDef *c ) const;
|
||||
|
||||
void warning( const char *function, const char *format, ... );
|
||||
void error( const char *function, const char *format, ... );
|
||||
};
|
||||
|
||||
#include "safeptr.h"
|
||||
|
||||
#endif /* __CLASS_H__ */
|
|
@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
*/
|
||||
|
||||
#include "qfiles.h"
|
||||
#include "q_shared.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -31,11 +31,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
#include <baseimp.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
baseImport_t bi;
|
||||
cvar_t *sv_scriptfiles;
|
||||
cvar_t *g_scriptcheck;
|
||||
cvar_t *g_showopcodes;
|
||||
|
@ -762,35 +759,6 @@ void B_Free( void *ptr ) {
|
|||
return Z_Free( ptr );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
Com_FillBaseImports
|
||||
====================
|
||||
*/
|
||||
void Com_FillBaseImports( void ) {
|
||||
bi.Printf = Com_Printf;
|
||||
bi.DPrintf = Com_DPrintf;
|
||||
bi.Error = Com_Error;
|
||||
bi.Malloc = B_Malloc;
|
||||
bi.Free = B_Free;
|
||||
bi.Milliseconds = Sys_Milliseconds;
|
||||
bi.FS_ReadFile = FS_ReadFileEx;
|
||||
bi.FS_FreeFile = FS_FreeFile;
|
||||
bi.FS_CanonicalFilename = FS_CanonicalFilename;
|
||||
bi.FS_FileNewer = FS_FileNewer;
|
||||
bi.FS_Flush = FS_Flush;
|
||||
bi.FS_FOpenFileAppend = FS_FOpenFileAppend;
|
||||
bi.FS_FOpenFileWrite = FS_FOpenFileWrite;
|
||||
bi.FS_FreeFileList = FS_FreeFileList;
|
||||
bi.FS_ListFiles = FS_ListFiles;
|
||||
bi.FS_PrepFileWrite = FS_PrepFileWrite;
|
||||
bi.FS_Read = FS_Read;
|
||||
bi.FS_Seek = FS_Seek;
|
||||
bi.FS_Tell = FS_FTell;
|
||||
bi.FS_Write = FS_Write;
|
||||
bi.FS_WriteFile = FS_WriteFile;
|
||||
}
|
||||
|
||||
void CL_ShutdownCGame( void );
|
||||
void CL_ShutdownUI( void );
|
||||
void SV_ShutdownGameProgs( void );
|
||||
|
@ -1303,8 +1271,6 @@ void Com_Init( char *commandLine ) {
|
|||
// cvar and command buffer management
|
||||
Com_ParseCommandLine( commandLine );
|
||||
|
||||
Com_FillBaseImports();
|
||||
|
||||
Swap_Init();
|
||||
Cbuf_Init();
|
||||
Z_InitMemory();
|
||||
|
|
|
@ -22,7 +22,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
// con_set.cpp: C++ map/set classes
|
||||
|
||||
#include "glb_local.h"
|
||||
#include "con_set.h"
|
||||
#include "short3.h"
|
||||
#include "str.h"
|
||||
#include "vector.h"
|
||||
|
||||
// Basic Hash functions
|
||||
|
||||
|
|
|
@ -25,7 +25,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#ifndef __CON_SET_H__
|
||||
#define __CON_SET_H__
|
||||
|
||||
#include <mem_blockalloc.h>
|
||||
|
||||
class Class;
|
||||
class Archiver;
|
||||
|
||||
template< typename key, typename value >
|
||||
class con_map_enum;
|
||||
|
@ -55,7 +58,7 @@ public:
|
|||
|
||||
Entry();
|
||||
|
||||
#ifndef NO_ARCHIVE
|
||||
#ifdef ARCHIVE_SUPPORTED
|
||||
void Archive( Archiver& arc );
|
||||
#endif
|
||||
};
|
||||
|
@ -85,7 +88,7 @@ public:
|
|||
con_set();
|
||||
~con_set();
|
||||
|
||||
#ifndef NO_ARCHIVE
|
||||
#ifdef ARCHIVE_SUPPORTED
|
||||
void Archive( Archiver& arc );
|
||||
#endif
|
||||
|
||||
|
@ -135,7 +138,7 @@ private:
|
|||
con_set< key, value > m_con_set;
|
||||
|
||||
public:
|
||||
#ifndef NO_ARCHIVE
|
||||
#ifdef ARCHIVE_SUPPORTED
|
||||
void Archive( Archiver& arc );
|
||||
#endif
|
||||
|
||||
|
|
90
code/qcommon/con_timer.cpp
Normal file
90
code/qcommon/con_timer.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
#include "con_timer.h"
|
||||
|
||||
#if defined (ARCHIVE_SUPPORTED)
|
||||
#include "archive.h"
|
||||
#endif
|
||||
|
||||
con_timer::con_timer(void)
|
||||
{
|
||||
m_inttime = 0;
|
||||
m_bDirty = false;
|
||||
}
|
||||
|
||||
void con_timer::AddElement(Class* e, int inttime)
|
||||
{
|
||||
Element element;
|
||||
|
||||
element.obj = e;
|
||||
element.inttime = inttime;
|
||||
|
||||
m_Elements.AddObject(element);
|
||||
|
||||
if (inttime <= m_inttime) {
|
||||
SetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void con_timer::RemoveElement(Class* e)
|
||||
{
|
||||
for (int i = m_Elements.NumObjects(); i > 0; i--)
|
||||
{
|
||||
Element* index = &m_Elements.ObjectAt(i);
|
||||
|
||||
if (index->obj == e)
|
||||
{
|
||||
m_Elements.RemoveObjectAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class* con_timer::GetNextElement(int& foundtime)
|
||||
{
|
||||
int best_inttime;
|
||||
int i;
|
||||
int foundIndex;
|
||||
Class* result;
|
||||
|
||||
foundIndex = 0;
|
||||
best_inttime = m_inttime;
|
||||
|
||||
for (i = m_Elements.NumObjects(); i > 0; i--)
|
||||
{
|
||||
if (m_Elements.ObjectAt(i).inttime <= best_inttime)
|
||||
{
|
||||
best_inttime = m_Elements.ObjectAt(i).inttime;
|
||||
foundIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundIndex)
|
||||
{
|
||||
result = m_Elements.ObjectAt(foundIndex).obj;
|
||||
m_Elements.RemoveObjectAt(foundIndex);
|
||||
foundtime = best_inttime;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NULL;
|
||||
m_bDirty = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(ARCHIVE_SUPPORTED)
|
||||
|
||||
void con_timer::ArchiveElement(Archiver& arc, Element* e)
|
||||
{
|
||||
arc.ArchiveObjectPointer(&e->obj);
|
||||
arc.ArchiveInteger(&e->inttime);
|
||||
}
|
||||
|
||||
void con_timer::Archive(Archiver& arc)
|
||||
{
|
||||
arc.ArchiveBool(&m_bDirty);
|
||||
arc.ArchiveInteger(&m_inttime);
|
||||
|
||||
m_Elements.Archive(arc, con_timer::ArchiveElement);
|
||||
}
|
||||
#endif
|
34
code/qcommon/con_timer.h
Normal file
34
code/qcommon/con_timer.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#include "class.h"
|
||||
|
||||
class con_timer : public Class
|
||||
{
|
||||
public:
|
||||
class Element
|
||||
{
|
||||
public:
|
||||
Class* obj;
|
||||
int inttime;
|
||||
};
|
||||
|
||||
private:
|
||||
Container< con_timer::Element > m_Elements;
|
||||
bool m_bDirty;
|
||||
int m_inttime;
|
||||
|
||||
public:
|
||||
con_timer();
|
||||
|
||||
void AddElement(Class* e, int inttime);
|
||||
void RemoveElement(Class* e);
|
||||
|
||||
Class* GetNextElement(int& foundTime);
|
||||
|
||||
void SetDirty(void) { m_bDirty = true; };
|
||||
bool IsDirty(void) { return m_bDirty; };
|
||||
void SetTime(int inttime) { m_inttime = inttime; };
|
||||
|
||||
#if defined (ARCHIVE_SUPPORTED)
|
||||
static void ArchiveElement(class Archiver& arc, Element* e);
|
||||
void Archive(class Archiver& arc) override;
|
||||
#endif
|
||||
};
|
140
code/qcommon/const_str.h
Normal file
140
code/qcommon/const_str.h
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// const_str.h: Strings constant, improve performance in string comparison
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef unsigned int const_str;
|
||||
|
||||
#ifdef GAME_DLL
|
||||
|
||||
enum
|
||||
{
|
||||
STRING_NULL = 0,
|
||||
STRING_EMPTY = 1,
|
||||
STRING_TOUCH, STRING_BLOCK, STRING_TRIGGER, STRING_USE,
|
||||
STRING_DAMAGE,STRING_LOCATION,
|
||||
STRING_SAY, STRING_FAIL, STRING_BUMP,
|
||||
STRING_DEFAULT, STRING_ALL,
|
||||
STRING_MOVE_ACTION, STRING_RESUME, STRING_OPEN, STRING_CLOSE, STRING_PICKUP, STRING_REACH, STRING_START,
|
||||
STRING_TELEPORT,
|
||||
STRING_MOVE, STRING_MOVE_END, STRING_MOVETO, STRING_WALKTO, STRING_RUNTO, STRING_CROUCHTO, STRING_CRAWLTO, STRING_STOP,
|
||||
STRING_RESET, STRING_PRESPAWN, STRING_SPAWN, STRING_PLAYERSPAWN, STRING_SKIP, STRING_ROUNDSTART,
|
||||
STRING_VISIBLE, STRING_NOT_VISIBLE,
|
||||
STRING_DONE, STRING_ANIMDONE, STRING_UPPERANIMDONE, STRING_SAYDONE, STRING_FLAGGEDANIMDONE,
|
||||
STRING_IDLE, STRING_WALK, STRING_SHUFFLE,
|
||||
STRING_ANIM_CROUCH_SCR,
|
||||
STRING_FORGOT,
|
||||
STRING_JOG_HUNCH, STRING_JOG_HUNCH_RIFLE,
|
||||
STRING_KILLED,
|
||||
STRING_ALARM, STRING_SCRIPTCLASS, STRING_FACT_SCRIPT_FACTORY,
|
||||
STRING_DEATH, STRING_DEATH_FALL_TO_KNEES,
|
||||
STRING_ENEMY,
|
||||
STRING_DEAD,
|
||||
STRING_MOOD,
|
||||
STRING_PATROL, STRING_RUNNER, STRING_FOLLOW,
|
||||
STRING_ACTION, STRING_MOVE_BEGIN, STRING_ACTION_BEGIN, STRING_ACTION_END,
|
||||
STRING_SUCCESS, STRING_ENTRY, STRING_EXIT, STRING_PATH, STRING_NODE,
|
||||
STRING_ASK_COUNT,
|
||||
STRING_ATTACKER, STRING_USECOVER, STRING_WAITCOVER, STRING_VOID, STRING_END, STRING_ATTACK, STRING_NEAR,
|
||||
STRING_PAPERS, STRING_CHECK_PAPERS,
|
||||
STRING_TIMEOUT,
|
||||
STRING_HOSTILE, STRING_LEADER,
|
||||
STRING_GAMEMAP,
|
||||
STRING_BORED, STRING_NERVOUS, STRING_CURIOUS, STRING_ALERT, STRING_GREET, STRING_DEFEND,
|
||||
STRING_ANIM, STRING_ANIM_SCRIPTED, STRING_ANIM_CURIOUS, STRING_ANIMLOOP, STRING_UNDEFINED, STRING_NOTSET,
|
||||
STRING_INCREMENT, STRING_DECREMENT, STRING_TOGGLE,
|
||||
STRING_NORMAL, STRING_SUSPENSE, STRING_MYSTERY, STRING_SURPRISE,
|
||||
STRING_ANIM_CROUCH_RUN_SCR,
|
||||
STRING_ANIM_AIM_SCR, STRING_ANIM_SHOOT_SCR, STRING_ANIM_MG42_SHOOT_SCR, STRING_ANIM_MG42_IDLE_SCR, STRING_ANIM_MG42_RELOAD_SCR,
|
||||
STRING_DRIVE,
|
||||
STRING_GLOBAL_WEAPON_SCR, STRING_GLOBAL_MOVETO_SCR,
|
||||
STRING_GLOBAL_ANIM_SCR, STRING_GLOBAL_ANIM_SCRIPTED_SCR, STRING_GLOBAL_ANIM_NOCLIP_SCR, STRING_GLOBAL_WALKTO_SCR, STRING_GLOBAL_RUNTO_SCR, STRING_AIMAT,
|
||||
STRING_GLOBAL_DISABLE_AI_SCR,
|
||||
STRING_GLOBAL_CROUCHTO_SCR, STRING_GLOBAL_CRAWLTO_SCR,
|
||||
STRING_GLOBAL_KILLED_SCR, STRING_GLOBAL_PAIN_SCR, STRING_PAIN,
|
||||
STRING_TRACK, STRING_HASENEMY,
|
||||
STRING_ANIM_COWER_SCR, STRING_ANIM_STAND_SCR, STRING_ANIM_IDLE_SCR, STRING_ANIM_SURPRISE_SCR, STRING_ANIM_STANDSHOCK_SCR, STRING_ANIM_STANDIDENTIFY_SCR, STRING_ANIM_STANDFLINCH_SCR, STRING_ANIM_DOG_IDLE_SCR, STRING_ANIM_DOG_ATTACK_SCR, STRING_ANIM_DOG_CURIOUS_SCR, STRING_ANIM_DOG_CHASE_SCR,
|
||||
STRING_CANNON, STRING_GRENADE, STRING_HEAVY,
|
||||
STRING_ITEM, STRING_ITEMS, STRING_ITEM1, STRING_ITEM2, STRING_ITEM3, STRING_ITEM4,
|
||||
STRING_STAND,
|
||||
STRING_MG, STRING_PISTOL, STRING_RIFLE, STRING_SMG,
|
||||
STRING_TURNTO,
|
||||
STRING_STANDING, STRING_CROUCHING, STRING_PRONE, STRING_OFFGROUND, STRING_WALKING, STRING_RUNNING, STRING_FALLING,
|
||||
STRING_ANIM_NOTHING, STRING_ANIM_DIRECT, STRING_ANIM_PATH, STRING_ANIM_WAYPOINT, STRING_ANIM_DIRECT_NOGRAVITY,
|
||||
STRING_EMOTION_NONE, STRING_EMOTION_NEUTRAL,
|
||||
STRING_EMOTION_WORRY, STRING_EMOTION_PANIC, STRING_EMOTION_FEAR,
|
||||
STRING_EMOTION_DISGUST, STRING_EMOTION_ANGER,
|
||||
STRING_EMOTION_AIMING, STRING_EMOTION_DETERMINED,
|
||||
STRING_EMOTION_DEAD,
|
||||
STRING_EMOTION_CURIOUS,
|
||||
STRING_ANIM_EMOTION_SCR,
|
||||
STRING_FORCEANIM, STRING_FORCEANIM_SCRIPTED,
|
||||
STRING_TURRET, STRING_COVER,
|
||||
STRING_ANIM_PAIN_SCR, STRING_ANIM_KILLED_SCR, STRING_ANIM_ATTACK_SCR, STRING_ANIM_SNIPER_SCR,
|
||||
STRING_KNEES, STRING_CRAWL, STRING_FLOOR,
|
||||
STRING_ANIM_PATROL_SCR, STRING_ANIM_RUN_SCR, STRING_CROUCH, STRING_CROUCHWALK, STRING_CROUCHRUN, STRING_ANIM_CROUCH_WALK_SCR, STRING_ANIM_WALK_SCR, STRING_ANIM_PRONE_SCR,
|
||||
STRING_ANIM_RUNAWAYFIRING_SCR, STRING_ANIM_RUN_SHOOT_SCR, STRING_ANIM_RUNTO_ALARM_SCR, STRING_ANIM_RUNTO_CASUAL_SCR, STRING_ANIM_RUNTO_COVER_SCR, STRING_ANIM_RUNTO_DANGER_SCR, STRING_ANIM_RUNTO_DIVE_SCR, STRING_ANIM_RUNTO_FLEE_SCR, STRING_ANIM_RUNTO_INOPEN_SCR,
|
||||
STRING_ANIM_DISGUISE_SALUTE_SCR, STRING_ANIM_DISGUISE_WAIT_SCR, STRING_ANIM_DISGUISE_PAPERS_SCR, STRING_ANIM_DISGUISE_ENEMY_SCR, STRING_ANIM_DISGUISE_HALT_SCR, STRING_ANIM_DISGUISE_ACCEPT_SCR, STRING_ANIM_DISGUISE_DENY_SCR,
|
||||
STRING_ANIM_CORNERLEFT_SCR, STRING_ANIM_CORNERRIGHT_SCR,
|
||||
STRING_ANIM_OVERATTACK_SCR,
|
||||
STRING_ANIM_CONTINUE_LAST_ANIM_SCR,
|
||||
STRING_FLAGGED,
|
||||
STRING_ANIM_FULLBODY_SCR,
|
||||
STRING_INTERNAL,
|
||||
STRING_DISGUISE_SALUTE, STRING_DISGUISE_SENTRY, STRING_DISGUISE_OFFICER, STRING_DISGUISE_ROVER, STRING_DISGUISE_NONE,
|
||||
STRING_MACHINEGUNNER,
|
||||
STRING_DISGUISE,
|
||||
STRING_DOG_IDLE, STRING_DOG_ATTACK, STRING_DOG_CURIOUS, STRING_DOG_GRENADE,
|
||||
STRING_ANIM_GRENADERETURN_SCR, STRING_ANIM_GRENADEKICK_SCR, STRING_ANIM_GRENADETHROW_SCR, STRING_ANIM_GRENADETOSS_SCR, STRING_ANIM_GRENADEMARTYR_SCR,
|
||||
STRING_MOVEDONE,
|
||||
STRING_AIM, STRING_ONTARGET,
|
||||
STRING_UNARMED,
|
||||
STRING_BALCONY_IDLE, STRING_BALCONY_CURIOUS, STRING_BALCONY_ATTACK, STRING_BALCONY_DISGUISE, STRING_BALCONY_GRENADE, STRING_BALCONY_PAIN, STRING_BALCONY_KILLED,
|
||||
STRING_WEAPONLESS,
|
||||
STRING_DEATH_BALCONY_INTRO, STRING_DEATH_BALCONY_LOOP, STRING_DEATH_BALCONY_OUTTRO,
|
||||
STRING_SOUNDDONE,
|
||||
STRING_NOCLIP,
|
||||
STRING_GERMAN, STRING_AMERICAN, STRING_SPECTATOR, STRING_FREEFORALL, STRING_ALLIES, STRING_AXIS,
|
||||
STRING_DRAW, STRING_KILLS, STRING_ALLIESWIN, STRING_AXISWIN,
|
||||
STRING_ANIM_SAY_CURIOUS_SIGHT_SCR, STRING_ANIM_SAY_CURIOUS_SOUND_SCR, STRING_ANIM_SAY_GRENADE_SIGHTED_SCR, STRING_ANIM_SAY_KILL_SCR, STRING_ANIM_SAY_MANDOWN_SCR, STRING_ANIM_SAY_SIGHTED_SCR,
|
||||
STRING_VEHICLEANIMDONE,
|
||||
STRING_POSTTHINK,
|
||||
STRING_TURNDONE,
|
||||
STRING_ANIM_NO_KILLED_SCR,
|
||||
STRING_MG42, STRING_MP40,
|
||||
STRING_REMOVE, STRING_DELETE,
|
||||
STRING_RESPAWN,
|
||||
STRING_NONE,
|
||||
STRING_LENGTH_
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
enum
|
||||
{
|
||||
STRING_NULL = 0,
|
||||
STRING_EMPTY = 1
|
||||
};
|
||||
|
||||
#endif
|
491
code/qcommon/container.h
Normal file
491
code/qcommon/container.h
Normal file
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2008 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// container.h: C++ Container
|
||||
|
||||
#ifndef __CONTAINER_H__
|
||||
#define __CONTAINER_H__
|
||||
|
||||
#ifdef GAME_DLL
|
||||
#ifdef WIN32
|
||||
#define glbprintf( text ) gi.Printf( text )
|
||||
#else
|
||||
#define glbprintf( text )
|
||||
#endif
|
||||
#elif defined CGAME_DLL
|
||||
#define glbprintf( text ) cgi.Printf( text )
|
||||
#else
|
||||
#define glbprintf( text ) printf( text )
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define CONTAINER_Error( id, text ) glbprintf( text ); assert( 0 );
|
||||
#else
|
||||
#define CONTAINER_Error( id, text ) throw( text ) //gi.Error
|
||||
#endif
|
||||
#define CONTAINER_DPrintf( text ) glbprintf( text )
|
||||
#define CONTAINER_WDPrintf( text ) glbprintf( text )
|
||||
|
||||
class Archiver;
|
||||
|
||||
template< class Type >
|
||||
class Container
|
||||
{
|
||||
private:
|
||||
Type *objlist;
|
||||
int numobjects;
|
||||
int maxobjects;
|
||||
|
||||
private:
|
||||
void Copy( const Container<Type>& container );
|
||||
|
||||
public:
|
||||
Container();
|
||||
Container( const Container<Type>& container );
|
||||
~Container();
|
||||
|
||||
void Archive( Archiver& arc );
|
||||
void Archive( Archiver& arc, void( *ArchiveFunc )( Archiver &arc, Type *obj ) );
|
||||
|
||||
int AddObject( const Type& obj );
|
||||
int AddUniqueObject( const Type& obj );
|
||||
void AddObjectAt( int index, const Type& obj );
|
||||
Type *AddressOfObjectAt( int index );
|
||||
// void Archive( Archiver &arc );
|
||||
void ClearObjectList( void );
|
||||
void Fix( void );
|
||||
void FreeObjectList( void );
|
||||
int IndexOfObject( const Type& obj );
|
||||
void InsertObjectAt( int index, const Type& obj );
|
||||
int MaxObjects( void ) const;
|
||||
int NumObjects( void ) const;
|
||||
Type& ObjectAt( const size_t index ) const;
|
||||
bool ObjectInList( const Type& obj );
|
||||
void RemoveObjectAt( int index );
|
||||
void RemoveObject( const Type& obj );
|
||||
void Reset( void );
|
||||
void Resize( int maxelements );
|
||||
void SetObjectAt( int index, const Type& obj );
|
||||
void Sort( int( *compare )( const void *elem1, const void *elem2 ) );
|
||||
Type& operator[]( const int index ) const;
|
||||
Container<Type>& operator=( const Container<Type>& container );
|
||||
};
|
||||
|
||||
template< class Type >
|
||||
Container<Type>::Container()
|
||||
{
|
||||
objlist = NULL;
|
||||
numobjects = 0;
|
||||
maxobjects = 0;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
Container<Type>::Container( const Container<Type>& container )
|
||||
{
|
||||
objlist = NULL;
|
||||
|
||||
Copy( container );
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
Container<Type>::~Container()
|
||||
{
|
||||
FreeObjectList();
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
int Container<Type>::AddObject( const Type& obj )
|
||||
{
|
||||
if ( !objlist )
|
||||
Resize( 10 );
|
||||
|
||||
if ( numobjects >= maxobjects ) {
|
||||
Resize( numobjects * 2 );
|
||||
}
|
||||
|
||||
objlist[numobjects] = obj;
|
||||
numobjects++;
|
||||
|
||||
return numobjects;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
int Container<Type>::AddUniqueObject( const Type& obj )
|
||||
{
|
||||
int index;
|
||||
|
||||
index = IndexOfObject( obj );
|
||||
|
||||
if ( !index ) {
|
||||
index = AddObject( obj );
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::AddObjectAt( int index, const Type& obj )
|
||||
{
|
||||
if ( index > maxobjects )
|
||||
Resize( index );
|
||||
|
||||
if ( index > numobjects )
|
||||
numobjects = index;
|
||||
|
||||
SetObjectAt( index, obj );
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
Type *Container<Type>::AddressOfObjectAt( int index )
|
||||
{
|
||||
if ( index > maxobjects ) {
|
||||
CONTAINER_Error( ERR_DROP, "Container::AddressOfObjectAt : index is greater than maxobjects" );
|
||||
}
|
||||
|
||||
if ( index > numobjects ) {
|
||||
numobjects = index;
|
||||
}
|
||||
|
||||
return &objlist[index - 1];
|
||||
}
|
||||
|
||||
/*template< class Type >
|
||||
void Container<Type>::Archive( Archiver &arc )
|
||||
{
|
||||
|
||||
}*/
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::ClearObjectList( void )
|
||||
{
|
||||
if ( objlist && numobjects )
|
||||
{
|
||||
delete[] objlist;
|
||||
|
||||
if ( maxobjects == 0 )
|
||||
{
|
||||
objlist = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
objlist = new Type[maxobjects];
|
||||
numobjects = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::Fix( void )
|
||||
{
|
||||
if( !objlist || !numobjects ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Type *newlist = new Type[ numobjects ];
|
||||
int j = 0;
|
||||
|
||||
for( int i = 0; i < numobjects; i++ )
|
||||
{
|
||||
if( objlist[ i ] == NULL ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
newlist[ j ] = objlist[ i ];
|
||||
j++;
|
||||
}
|
||||
|
||||
numobjects = j;
|
||||
|
||||
delete[] objlist;
|
||||
objlist = newlist;
|
||||
|
||||
if( !numobjects ) {
|
||||
ClearObjectList();
|
||||
}
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::FreeObjectList( void )
|
||||
{
|
||||
if( objlist ) {
|
||||
delete[] objlist;
|
||||
}
|
||||
|
||||
objlist = NULL;
|
||||
numobjects = 0;
|
||||
maxobjects = 0;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
int Container<Type>::IndexOfObject( const Type& obj )
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( !objlist ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( i = 0; i < numobjects; i++ )
|
||||
{
|
||||
if ( objlist[i] == obj )
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::InsertObjectAt( int index, const Type& obj )
|
||||
{
|
||||
if ( ( index <= 0 ) || ( index > numobjects + 1 ) )
|
||||
{
|
||||
CONTAINER_Error( ERR_DROP, "Container::InsertObjectAt : index out of range" );
|
||||
return;
|
||||
}
|
||||
|
||||
numobjects++;
|
||||
int arrayIndex = index - 1;
|
||||
|
||||
if ( numobjects > maxobjects )
|
||||
{
|
||||
maxobjects = numobjects;
|
||||
if ( !objlist ) {
|
||||
objlist = new Type[maxobjects];
|
||||
objlist[arrayIndex] = obj;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Type *temp = objlist;
|
||||
if ( maxobjects < numobjects )
|
||||
{
|
||||
maxobjects = numobjects;
|
||||
}
|
||||
|
||||
objlist = new Type[maxobjects];
|
||||
|
||||
int i;
|
||||
for ( i = arrayIndex - 1; i >= 0; i-- ) {
|
||||
objlist[i] = temp[i];
|
||||
}
|
||||
|
||||
objlist[arrayIndex] = obj;
|
||||
for ( i = numobjects - 1; i > arrayIndex; i-- ) {
|
||||
objlist[i] = temp[i - 1];
|
||||
}
|
||||
|
||||
delete[] temp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i = numobjects - 1; i > arrayIndex; i-- ) {
|
||||
objlist[i] = objlist[i - 1];
|
||||
}
|
||||
objlist[arrayIndex] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
int Container<Type>::MaxObjects( void ) const
|
||||
{
|
||||
return maxobjects;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
int Container<Type>::NumObjects( void ) const
|
||||
{
|
||||
return numobjects;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
Type& Container<Type>::ObjectAt( const size_t index ) const
|
||||
{
|
||||
if( ( index <= 0 ) || ( index > numobjects ) ) {
|
||||
CONTAINER_Error( ERR_DROP, "Container::ObjectAt : index out of range" );
|
||||
}
|
||||
|
||||
return objlist[index - 1];
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
bool Container<Type>::ObjectInList( const Type& obj )
|
||||
{
|
||||
if ( !IndexOfObject( obj ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::RemoveObjectAt( int index )
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( !objlist )
|
||||
return;
|
||||
|
||||
if ( ( index <= 0 ) || ( index > numobjects ) )
|
||||
return;
|
||||
|
||||
i = index - 1;
|
||||
numobjects--;
|
||||
|
||||
for ( i = index - 1; i < numobjects; i++ )
|
||||
objlist[i] = objlist[i + 1];
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::RemoveObject( const Type& obj )
|
||||
{
|
||||
int index;
|
||||
|
||||
index = IndexOfObject( obj );
|
||||
|
||||
assert( index );
|
||||
if ( !index )
|
||||
{
|
||||
CONTAINER_WDPrintf( "Container::RemoveObject : Object not in list\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveObjectAt( index );
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::Reset()
|
||||
{
|
||||
objlist = NULL;
|
||||
numobjects = 0;
|
||||
maxobjects = 0;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::Resize( int maxelements )
|
||||
{
|
||||
Type* temp;
|
||||
int i;
|
||||
|
||||
if ( maxelements <= 0 )
|
||||
{
|
||||
FreeObjectList();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !objlist )
|
||||
{
|
||||
maxobjects = maxelements;
|
||||
objlist = new Type[maxobjects];
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = objlist;
|
||||
|
||||
maxobjects = maxelements;
|
||||
|
||||
if ( maxobjects < numobjects ) {
|
||||
maxobjects = numobjects;
|
||||
}
|
||||
|
||||
objlist = new Type[maxobjects];
|
||||
|
||||
for ( i = 0; i < numobjects; i++ ) {
|
||||
objlist[i] = temp[i];
|
||||
}
|
||||
|
||||
delete[] temp;
|
||||
}
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::SetObjectAt( int index, const Type& obj )
|
||||
{
|
||||
if ( !objlist )
|
||||
return;
|
||||
|
||||
if( ( index <= 0 ) || ( index > numobjects ) ) {
|
||||
CONTAINER_Error( ERR_DROP, "Container::SetObjectAt : index out of range" );
|
||||
}
|
||||
|
||||
objlist[index - 1] = obj;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::Sort( int( *compare )( const void *elem1, const void *elem2 ) )
|
||||
|
||||
{
|
||||
if ( !objlist ) {
|
||||
return;
|
||||
}
|
||||
|
||||
qsort( ( void * )objlist, ( size_t )numobjects, sizeof( Type ), compare );
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
Type& Container<Type>::operator[]( const int index ) const
|
||||
{
|
||||
return ObjectAt( index + 1 );
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
void Container<Type>::Copy( const Container<Type>& container )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( &container == this ) {
|
||||
return;
|
||||
}
|
||||
|
||||
FreeObjectList();
|
||||
|
||||
numobjects = container.numobjects;
|
||||
maxobjects = container.maxobjects;
|
||||
objlist = NULL;
|
||||
|
||||
if( container.objlist == NULL || !container.maxobjects ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Resize( maxobjects );
|
||||
|
||||
if( !container.numobjects ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for( i = 0; i < container.numobjects; i++ ) {
|
||||
objlist[ i ] = container.objlist[ i ];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template< class Type >
|
||||
Container<Type>& Container<Type>::operator=( const Container<Type>& container )
|
||||
{
|
||||
Copy( container );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif /* __CONTAINER_H__ */
|
59
code/qcommon/containerclass.h
Normal file
59
code/qcommon/containerclass.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2008 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// containerclass.h: C++ Class Container for use with SafePtr
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "container.h"
|
||||
|
||||
template< class Type >
|
||||
class ContainerClass : public Class {
|
||||
Container< Type > value;
|
||||
|
||||
public:
|
||||
virtual ~ContainerClass() { value.FreeObjectList(); }
|
||||
|
||||
virtual void Archive( Archiver& arc );
|
||||
|
||||
int AddObject( const Type& obj ) { return value.AddObject( obj ); }
|
||||
int AddUniqueObject( const Type& obj ) { return value.AddUniqueObject( obj ); }
|
||||
void AddObjectAt( int index, const Type& obj ) { return value.AddObjectAt( index, obj ); }
|
||||
Type *AddressOfObjectAt( int index ) { return value.AddressOfObjectAt( index ); }
|
||||
|
||||
void ClearObjectList( void ) { return value.ClearObjectList(); }
|
||||
void Fix( void ) { return value.Fix(); }
|
||||
void FreeObjectList( void ) { return value.FreeObjectList(); }
|
||||
int IndexOfObject( const Type& obj ) { return value.IndexOfObject( obj ); }
|
||||
void InsertObjectAt( int index, const Type& obj ) { return value.InsertObjectAt( index, obj ); }
|
||||
int NumObjects( void ) const { return value.NumObjects(); }
|
||||
Type& ObjectAt( const size_t index ) const { return value.ObjectAt( index ); }
|
||||
bool ObjectInList( const Type& obj ) { return value.ObjectInList( obj ); }
|
||||
void RemoveObjectAt( int index ) { return value.RemoveObjectAt( index ); }
|
||||
void RemoveObject( const Type& obj ) { return value.RemoveObject( obj ); }
|
||||
void Reset( void ) { return value.Reset(); }
|
||||
void Resize( int maxelements ) { return value.Resize( maxelements ); }
|
||||
void SetObjectAt( int index, const Type& obj ) { return value.SetObjectAt( index, obj ); }
|
||||
void Sort( int( *compare )( const void *elem1, const void *elem2 ) ) { return value.Sort( compare ); }
|
||||
Type& operator[]( const int index ) const { return value[ index ]; }
|
||||
Container<Type>& operator=( const Container<Type>& container ) { return value = container; }
|
||||
};
|
4699
code/qcommon/listener.cpp
Normal file
4699
code/qcommon/listener.cpp
Normal file
File diff suppressed because it is too large
Load diff
674
code/qcommon/listener.h
Normal file
674
code/qcommon/listener.h
Normal file
|
@ -0,0 +1,674 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2008 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// listener.h: Listener
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "class.h"
|
||||
#include "containerclass.h"
|
||||
#include "con_arrayset.h"
|
||||
#include "str.h"
|
||||
#include "vector.h"
|
||||
|
||||
class Entity;
|
||||
class Listener;
|
||||
class ScriptClass;
|
||||
class ScriptThread;
|
||||
class ScriptVariable;
|
||||
class ScriptVariableList;
|
||||
class ScriptVM;
|
||||
class SimpleEntity;
|
||||
class Archiver;
|
||||
class EventQueueNode;
|
||||
|
||||
// entity subclass
|
||||
#define EF_ENTITY (1<<0)
|
||||
#define EF_ANIMATE (1<<1)
|
||||
#define EF_SENTIENT (1<<2)
|
||||
#define EF_PLAYER (1<<3)
|
||||
#define EF_ACTOR (1<<4)
|
||||
#define EF_ITEM (1<<5)
|
||||
#define EF_INVENTORYITEM (1<<6)
|
||||
#define EF_WEAPON (1<<7)
|
||||
#define EF_PROJECTILE (1<<8)
|
||||
#define EF_DOOR (1<<9)
|
||||
#define EF_CAMERA (1<<10)
|
||||
#define EF_VEHICLE (1<<11)
|
||||
#define EF_VEHICLETANK (1<<12)
|
||||
#define EF_VEHICLETURRET (1<<13)
|
||||
#define EF_TURRET (1<<14)
|
||||
#define EF_PATHNODE (1<<15)
|
||||
#define EF_WAYPOINT (1<<16)
|
||||
#define EF_TEMPWAYPOINT (1<<17)
|
||||
#define EF_VEHICLEPOINT (1<<18)
|
||||
#define EF_SPLINEPATH (1<<19)
|
||||
#define EF_CRATEOBJECT (1<<20)
|
||||
#define EF_BOT (1<<21)
|
||||
|
||||
// Event flags
|
||||
#define EV_CONSOLE (1<<0) // Allow entry from console
|
||||
#define EV_CHEAT (1<<1) // Only allow entry from console if cheats are enabled
|
||||
#define EV_CODEONLY (1<<2) // Hide from eventlist
|
||||
#define EV_CACHE (1<<3) // This event is used to cache data in
|
||||
#define EV_TIKIONLY (1<<4) // This command only applies to TIKI files
|
||||
#define EV_SCRIPTONLY (1<<5) // This command only applies to SCRIPT files
|
||||
#define EV_SERVERCMD (1<<6) // Client : server command
|
||||
#define EV_DEFAULT -1 // default flag
|
||||
|
||||
// Event types
|
||||
#define EV_NORMAL 0 // Normal command
|
||||
#define EV_RETURN 1 // Return as a function (local.var = local ReturnCommand)
|
||||
#define EV_GETTER 2 // Return as a variable (local.var = local.listener.some_getter)
|
||||
#define EV_SETTER 3 // Set as a variable (local.listener.some_setter = "value")
|
||||
|
||||
// times for posting events
|
||||
// Even though negative times technically don't make sense, the effect is to
|
||||
// sort events that take place at the start of a map so that they are executed
|
||||
// in the proper order. For example, spawnargs must occur before any script
|
||||
// commands take place, while unused entities must be removed before the spawnargs
|
||||
// are parsed.
|
||||
|
||||
#define EV_REMOVE -12.0f // remove any unused entities before spawnargs are parsed
|
||||
#define EV_PRIORITY_SPAWNARG -11.0f // for priority spawn args passed in by the bsp file
|
||||
#define EV_SPAWNARG -10.0f // for spawn args passed in by the bsp file
|
||||
#define EV_LINKDOORS -9.0f // for finding out which doors are linked together
|
||||
#define EV_LINKBEAMS -9.0f // for finding out the endpoints of beams
|
||||
#define EV_VEHICLE -9.0f
|
||||
#define EV_SETUP_ROPEPIECE -8.0f
|
||||
#define EV_SETUP_ROPEBASE -7.0f
|
||||
#define EV_PROCESS_INIT -6.0f
|
||||
#define EV_POSTSPAWN -5.0f // for any processing that must occur after all objects are spawned
|
||||
#define EV_SPAWNENTITIES -4.0f
|
||||
#define EV_PRIORITY_SPAWNACTOR -3.0f
|
||||
#define EV_SPAWNACTOR -2.0f
|
||||
|
||||
// Posted Event Flags
|
||||
#define EVENT_LEGS_ANIM (1<<0) // this event is associated with an animation for the legs
|
||||
#define EVENT_TORSO_ANIM (1<<1) // this event is associated with an animation for the torso
|
||||
#define EVENT_DIALOG_ANIM (1<<2) // this event is associated with an animation for dialog lip syncing
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IS_STRING,
|
||||
IS_VECTOR,
|
||||
IS_BOOLEAN,
|
||||
IS_INTEGER,
|
||||
IS_FLOAT,
|
||||
IS_ENTITY,
|
||||
IS_LISTENER
|
||||
} vartype;
|
||||
|
||||
class EventArgDef : public Class
|
||||
{
|
||||
private:
|
||||
int type;
|
||||
str name;
|
||||
float minRange[ 3 ];
|
||||
qboolean minRangeDefault[ 3 ];
|
||||
float maxRange[ 3 ];
|
||||
qboolean maxRangeDefault[ 3 ];
|
||||
qboolean optional;
|
||||
public:
|
||||
|
||||
EventArgDef()
|
||||
{
|
||||
type = IS_INTEGER;
|
||||
//name = "undefined";
|
||||
optional = false;
|
||||
};
|
||||
void Setup( const char * eventName, const char *argName, const char *argType, const char *argRange );
|
||||
void PrintArgument( FILE *event_file = NULL );
|
||||
void PrintRange( FILE *event_file = NULL );
|
||||
int getType( void );
|
||||
const char *getName( void );
|
||||
qboolean isOptional( void );
|
||||
|
||||
float GetMinRange( int index )
|
||||
{
|
||||
if( index < 3 )
|
||||
return minRange[ index ];
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
qboolean GetMinRangeDefault( int index )
|
||||
{
|
||||
if( index < 3 )
|
||||
return minRangeDefault[ index ];
|
||||
return false;
|
||||
}
|
||||
|
||||
float GetMaxRange( int index )
|
||||
{
|
||||
if( index < 3 )
|
||||
return maxRange[ index ];
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
qboolean GetMaxRangeDefault( int index )
|
||||
{
|
||||
if( index < 3 )
|
||||
return maxRangeDefault[ index ];
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
inline int EventArgDef::getType
|
||||
(
|
||||
void
|
||||
)
|
||||
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
inline const char *EventArgDef::getName
|
||||
(
|
||||
void
|
||||
)
|
||||
|
||||
{
|
||||
return name.c_str();
|
||||
}
|
||||
|
||||
inline qboolean EventArgDef::isOptional
|
||||
(
|
||||
void
|
||||
)
|
||||
|
||||
{
|
||||
return optional;
|
||||
}
|
||||
|
||||
class EventDef {
|
||||
public:
|
||||
str command;
|
||||
int flags;
|
||||
const char *formatspec;
|
||||
const char *argument_names;
|
||||
const char *documentation;
|
||||
uchar type;
|
||||
Container<EventArgDef> *definition;
|
||||
|
||||
EventDef() { definition = NULL; }
|
||||
|
||||
void Error( const char *format, ... );
|
||||
|
||||
void PrintDocumentation( FILE *event_file, bool html );
|
||||
void PrintEventDocumentation( FILE *event_file, bool html );
|
||||
|
||||
void DeleteDocumentation( void );
|
||||
void SetupDocumentation( void );
|
||||
};
|
||||
|
||||
class command_t {
|
||||
public:
|
||||
str command;
|
||||
int flags;
|
||||
uchar type;
|
||||
|
||||
friend bool operator==( const str &name, const command_t &command );
|
||||
friend bool operator==( const command_t &cmd1, const command_t &cmd2 );
|
||||
};
|
||||
|
||||
inline bool operator==( const str &name, const command_t &command )
|
||||
{
|
||||
return command.command == name;
|
||||
}
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
inline bool operator==( const command_t &cmd1, const command_t &cmd2 )
|
||||
{
|
||||
return ( cmd2.command == cmd1.command && ( cmd2.type == ( uchar )-1 || cmd2.type == cmd1.type ) );
|
||||
}
|
||||
#else
|
||||
inline bool operator==( const command_t &cmd1, const command_t &cmd2 )
|
||||
{
|
||||
return ( cmd2.command == cmd1.command );
|
||||
}
|
||||
#endif
|
||||
|
||||
class Event : public Class
|
||||
{
|
||||
public:
|
||||
qboolean fromScript;
|
||||
short unsigned int eventnum;
|
||||
short unsigned int dataSize;
|
||||
ScriptVariable *data;
|
||||
|
||||
#ifdef _DEBUG
|
||||
// should be used only for debugging purposes
|
||||
str name;
|
||||
#endif
|
||||
|
||||
public:
|
||||
CLASS_PROTOTYPE( Event );
|
||||
|
||||
static con_map< Event *, EventDef > eventDefList;
|
||||
static con_arrayset< command_t, command_t > commandList;
|
||||
|
||||
static con_map< const_str, unsigned int > normalCommandList;
|
||||
static con_map< const_str, unsigned int > returnCommandList;
|
||||
static con_map< const_str, unsigned int > getterCommandList;
|
||||
static con_map< const_str, unsigned int > setterCommandList;
|
||||
|
||||
static void LoadEvents( void );
|
||||
|
||||
static EventQueueNode EventQueue;
|
||||
|
||||
static int totalevents;
|
||||
static int NumEventCommands();
|
||||
|
||||
static void ListCommands( const char *mask = NULL );
|
||||
static void ListDocumentation( const char *mask, qboolean print_to_file = qfalse );
|
||||
static void PendingEvents( const char *mask = NULL );
|
||||
|
||||
static int GetEvent( str name, uchar type = EV_NORMAL );
|
||||
static int GetEventWithFlags( str name, int flags, uchar type = EV_NORMAL );
|
||||
|
||||
static command_t *GetEventInfo( int eventnum );
|
||||
static int GetEventFlags( int eventnum );
|
||||
static str& GetEventName( int index );
|
||||
|
||||
static int compareEvents( const void *arg1, const void *arg2 );
|
||||
static void SortEventList( Container< int > *sortedList );
|
||||
|
||||
virtual void ErrorInternal( Listener *l, str text );
|
||||
|
||||
static unsigned int FindEventNum( str s );
|
||||
static unsigned int FindNormalEventNum( const_str s );
|
||||
static unsigned int FindNormalEventNum( str s );
|
||||
static unsigned int FindReturnEventNum( const_str s );
|
||||
static unsigned int FindReturnEventNum( str s );
|
||||
static unsigned int FindSetterEventNum( const_str s );
|
||||
static unsigned int FindSetterEventNum( str s );
|
||||
static unsigned int FindGetterEventNum( const_str s );
|
||||
static unsigned int FindGetterEventNum( str s );
|
||||
|
||||
bool operator==( Event ev ) { return eventnum == ev.eventnum; }
|
||||
bool operator!=( Event ev ) { return eventnum != ev.eventnum; }
|
||||
|
||||
#ifndef _DEBUG_MEM
|
||||
void *operator new( size_t size );
|
||||
void operator delete( void *ptr );
|
||||
#endif
|
||||
|
||||
Event();
|
||||
Event( const Event *ev );
|
||||
Event( const Event &ev );
|
||||
Event( int index );
|
||||
Event( str command );
|
||||
Event( str command, uchar type );
|
||||
Event
|
||||
(
|
||||
const char *command,
|
||||
int flags,
|
||||
const char *formatspec, // Arguments are : 'e' (Entity) 'v' (Vector) 'i' (Integer) 'f' (Float) 's' (String) 'b' (Boolean).
|
||||
// Uppercase arguments means optional.
|
||||
const char *argument_names,
|
||||
const char *documentation,
|
||||
uchar type = EV_NORMAL
|
||||
);
|
||||
|
||||
~Event();
|
||||
|
||||
#if defined(ARCHIVE_SUPPORTED)
|
||||
void Archive( Archiver &arc ) override;
|
||||
#endif
|
||||
|
||||
#ifdef _GAME_DLL
|
||||
eventInfo_t *getInfo();
|
||||
#else
|
||||
EventDef *getInfo();
|
||||
#endif
|
||||
|
||||
str& getName();
|
||||
|
||||
void AddContainer( Container< SafePtr< Listener > > *container );
|
||||
void AddEntity( Entity * ent );
|
||||
void AddFloat( float number );
|
||||
void AddInteger( int number );
|
||||
void AddListener( Listener * listener );
|
||||
void AddNil( void );
|
||||
void AddConstString( const_str string );
|
||||
void AddString( str string );
|
||||
void AddToken( str token );
|
||||
void AddTokens( int argc, const char **argv );
|
||||
void AddValue( const ScriptVariable &value );
|
||||
void AddVector( const Vector& vector );
|
||||
|
||||
void Clear( void );
|
||||
|
||||
void CheckPos( int pos );
|
||||
|
||||
bool GetBoolean( int pos );
|
||||
|
||||
const_str GetConstString( int pos );
|
||||
|
||||
Entity *GetEntity( int pos );
|
||||
|
||||
float GetFloat( int pos );
|
||||
int GetInteger( int pos );
|
||||
Listener *GetListener( int pos );
|
||||
|
||||
class PathNode *GetPathNode( int pos );
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
SimpleEntity *GetSimpleEntity( int pos );
|
||||
#endif
|
||||
|
||||
str GetString( int pos );
|
||||
str GetToken( int pos );
|
||||
ScriptVariable& GetValue( int pos );
|
||||
ScriptVariable& GetValue( void );
|
||||
Vector GetVector( int pos );
|
||||
|
||||
class Waypoint *GetWaypoint( int pos );
|
||||
|
||||
qboolean IsEntityAt( int pos );
|
||||
qboolean IsListenerAt( int pos );
|
||||
qboolean IsNilAt( int pos );
|
||||
qboolean IsNumericAt( int pos );
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
qboolean IsSimpleEntityAt( int pos );
|
||||
#endif
|
||||
qboolean IsStringAt( int pos );
|
||||
qboolean IsVectorAt( int pos );
|
||||
|
||||
qboolean IsFromScript( void );
|
||||
|
||||
const char *GetFormat();
|
||||
int NumArgs();
|
||||
};
|
||||
|
||||
typedef struct eventInfo
|
||||
{
|
||||
Event *ev;
|
||||
const char *command;
|
||||
int flags;
|
||||
const char *formatspec;
|
||||
const char *argument_names;
|
||||
const char *documentation;
|
||||
int type;
|
||||
eventInfo *prev;
|
||||
} eventInfo_t;
|
||||
|
||||
#define NODE_CANCEL 1
|
||||
#define NODE_FIXED_EVENT 2
|
||||
|
||||
class EventQueueNode {
|
||||
public:
|
||||
Event *event;
|
||||
int inttime;
|
||||
int flags;
|
||||
SafePtr< Listener > m_sourceobject;
|
||||
|
||||
EventQueueNode *prev;
|
||||
EventQueueNode *next;
|
||||
|
||||
#ifdef _DEBUG
|
||||
str name;
|
||||
#endif
|
||||
|
||||
EventQueueNode() { prev = this; next = this; }
|
||||
Listener *GetSourceObject( void ) { return m_sourceobject; }
|
||||
void SetSourceObject( Listener *obj ) { m_sourceobject = obj; }
|
||||
};
|
||||
|
||||
template< class Type1, class Type2 >
|
||||
class con_map;
|
||||
|
||||
using ConList = ContainerClass< SafePtr< Listener > >;
|
||||
using eventMap = con_map< Event *, EventDef * >;
|
||||
|
||||
using ListenerPtr = SafePtr< Listener >;
|
||||
|
||||
class Listener : public Class
|
||||
{
|
||||
public:
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
con_set< const_str, ConList > *m_NotifyList;
|
||||
con_set< const_str, ConList > *m_WaitForList;
|
||||
con_set< const_str, ConList > *m_EndList;
|
||||
ScriptVariableList *vars;
|
||||
#endif
|
||||
|
||||
static bool EventSystemStarted;
|
||||
|
||||
private:
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
void ExecuteScriptInternal( Event *ev, ScriptVariable& scriptVariable );
|
||||
void ExecuteThreadInternal( Event *ev, ScriptVariable& returnValue );
|
||||
void WaitExecuteScriptInternal( Event *ev, ScriptVariable& returnValue );
|
||||
void WaitExecuteThreadInternal( Event *ev, ScriptVariable& returnValue );
|
||||
#endif
|
||||
|
||||
EventQueueNode *PostEventInternal( Event *ev, float delay, int flags );
|
||||
|
||||
public:
|
||||
CLASS_PROTOTYPE( Listener );
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
/* Game functions */
|
||||
virtual ScriptThread *CreateThreadInternal( const ScriptVariable& label );
|
||||
virtual ScriptThread *CreateScriptInternal( const ScriptVariable& label );
|
||||
virtual void StoppedNotify( void );
|
||||
virtual void StartedWaitFor( void );
|
||||
virtual void StoppedWaitFor( const_str name, bool bDeleting );
|
||||
#endif
|
||||
|
||||
virtual Listener *GetScriptOwner( void );
|
||||
|
||||
Listener();
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void Archive( Archiver &arc );
|
||||
|
||||
void CancelEventsOfType( Event *ev );
|
||||
void CancelEventsOfType( Event &ev );
|
||||
void CancelFlaggedEvents( int flags );
|
||||
void CancelPendingEvents( void );
|
||||
|
||||
qboolean EventPending( Event &ev );
|
||||
|
||||
void PostEvent( Event *ev, float delay, int flags = 0 );
|
||||
void PostEvent( const Event &ev, float delay, int flags = 0 );
|
||||
|
||||
qboolean PostponeAllEvents( float time );
|
||||
qboolean PostponeEvent( Event& ev, float time );
|
||||
|
||||
bool ProcessEvent( const Event &ev );
|
||||
bool ProcessEvent( Event *ev );
|
||||
bool ProcessEvent( Event &ev );
|
||||
ScriptVariable& ProcessEventReturn( Event * ev );
|
||||
|
||||
void ProcessContainerEvent( const Container< Event * >& conev );
|
||||
|
||||
qboolean ProcessPendingEvents( void );
|
||||
|
||||
bool ProcessScriptEvent( Event &ev );
|
||||
bool ProcessScriptEvent( Event *ev );
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
|
||||
void CreateVars( void );
|
||||
void ClearVars( void );
|
||||
ScriptVariableList *Vars( void );
|
||||
|
||||
bool BroadcastEvent( Event &event, ConList *listeners );
|
||||
bool BroadcastEvent( str name, Event &event );
|
||||
bool BroadcastEvent( const_str name, Event &event );
|
||||
void CancelWaiting( str name );
|
||||
void CancelWaiting( const_str name );
|
||||
void CancelWaitingAll( void );
|
||||
void CancelWaitingSources( const_str name, ConList &listeners, ConList &stoppedListeners );
|
||||
|
||||
void ExecuteThread( str scriptName, str label, Event *params = NULL );
|
||||
void ExecuteThread( str scriptName, str label, Event ¶ms );
|
||||
|
||||
void EndOn( str name, Listener *listener );
|
||||
void EndOn( const_str name, Listener *listener );
|
||||
void Notify( const char *name );
|
||||
void Register( str name, Listener *listener );
|
||||
void Register( const_str name, Listener *listener );
|
||||
void RegisterSource( const_str name, Listener *listener );
|
||||
void RegisterTarget( const_str name, Listener *listener );
|
||||
void Unregister( str name );
|
||||
void Unregister( const_str name );
|
||||
void Unregister( str name, Listener *listener );
|
||||
void Unregister( const_str name, Listener *listener );
|
||||
void UnregisterAll( void );
|
||||
bool UnregisterSource( const_str name, Listener *listener );
|
||||
bool UnregisterTarget( const_str name, Listener *listener );
|
||||
void UnregisterTargets( const_str name, ConList &listeners, ConList &stoppedListeners, Container< const_str > &stoppedNames );
|
||||
void AbortRegistration( const_str name, Listener *l );
|
||||
|
||||
int RegisterSize( const_str name ) const;
|
||||
int RegisterSize( str name ) const;
|
||||
int WaitingSize( const_str name ) const;
|
||||
int WaitingSize( str name ) const;
|
||||
|
||||
bool WaitTillDisabled( str s );
|
||||
bool WaitTillDisabled( const_str s );
|
||||
#endif
|
||||
|
||||
int GetFlags( Event *event ) const;
|
||||
qboolean ValidEvent( str name ) const;
|
||||
|
||||
//
|
||||
// Scripting functions
|
||||
//
|
||||
void CommandDelay( Event *ev );
|
||||
void EventDelete( Event *ev );
|
||||
void EventInheritsFrom( Event *ev );
|
||||
void EventIsInheritedBy( Event *ev );
|
||||
void GetClassname( Event *ev );
|
||||
|
||||
#ifndef NO_SCRIPTENGINE
|
||||
void CancelFor( Event *ev );
|
||||
void CreateReturnThread( Event *ev );
|
||||
void CreateThread( Event *ev );
|
||||
void ExecuteReturnScript( Event *ev );
|
||||
void ExecuteScript( Event *ev );
|
||||
void EventDelayThrow( Event *ev );
|
||||
void EventEndOn( Event *ev );
|
||||
void EventGetOwner( Event *ev );
|
||||
void EventNotify( Event *ev );
|
||||
void EventThrow( Event *ev );
|
||||
void EventUnregister( Event *ev );
|
||||
void WaitCreateReturnThread( Event *ev );
|
||||
void WaitCreateThread( Event *ev );
|
||||
void WaitExecuteReturnScript( Event *ev );
|
||||
void WaitExecuteScript( Event *ev );
|
||||
void WaitTill( Event *ev );
|
||||
void WaitTillTimeout( Event *ev );
|
||||
void WaitTillAny( Event *ev );
|
||||
void WaitTillAnyTimeout( Event *ev );
|
||||
#endif
|
||||
};
|
||||
|
||||
qboolean IsNumeric( const char *str );
|
||||
|
||||
extern Event EV_DelayThrow;
|
||||
extern Event EV_Delete;
|
||||
extern Event EV_Remove;
|
||||
extern Event EV_ScriptRemove;
|
||||
extern Event EV_Throw;
|
||||
|
||||
extern Event EV_Listener_CreateThread;
|
||||
extern Event EV_Listener_CreateReturnThread;
|
||||
extern Event EV_Listener_ExecuteReturnScript;
|
||||
extern Event EV_Listener_ExecuteScript;
|
||||
extern Event EV_Listener_WaitCreateReturnThread;
|
||||
|
||||
extern int DisableListenerNotify;
|
||||
|
||||
extern cvar_t *g_showevents;
|
||||
extern cvar_t *g_eventlimit;
|
||||
extern cvar_t *g_timeevents;
|
||||
extern cvar_t *g_watch;
|
||||
extern cvar_t *g_eventstats;
|
||||
|
||||
extern MEM_BlockAlloc< Event, MEM_BLOCKSIZE > Event_allocator;
|
||||
|
||||
#if defined( GAME_DLL )
|
||||
//
|
||||
// game dll specific defines
|
||||
//
|
||||
#define EVENT_DebugPrintf gi.DebugPrintf
|
||||
#define EVENT_DPrintf gi.DPrintf
|
||||
#define EVENT_Printf gi.Printf
|
||||
#define EVENT_time level.time
|
||||
#define EVENT_realtime gi.Milliseconds()
|
||||
#define EVENT_Error gi.Error
|
||||
|
||||
#define EVENT_FILENAME "events.txt"
|
||||
|
||||
#elif defined ( CGAME_DLL )
|
||||
//
|
||||
// cgame dll specific defines
|
||||
//
|
||||
#define EVENT_DebugPrintf cgi.DebugPrintf
|
||||
#define EVENT_DPrintf cgi.Printf
|
||||
#define EVENT_Printf cgi.Printf
|
||||
#ifndef CGAME_HOOK
|
||||
#define EVENT_time ( ( ( float )cg.time / 1000.0f ) )
|
||||
#else
|
||||
#define EVENT_time ( ( ( float )cg->time / 1000.0f ) )
|
||||
#endif
|
||||
#define EVENT_realtime cgi.Milliseconds()
|
||||
#define EVENT_Error cgi.Error
|
||||
|
||||
#define EVENT_FILENAME "cg_events.txt"
|
||||
|
||||
#elif defined ( UI_LIB )
|
||||
|
||||
#define EVENT_DebugPrintf Com_DebugPrintf
|
||||
#define EVENT_DPrintf Com_Printf
|
||||
#define EVENT_Printf Com_Printf
|
||||
#define EVENT_time ( ( ( float )cls.realtime / 1000.0f ) )
|
||||
#define EVENT_realtime Sys_Milliseconds()
|
||||
#define EVENT_Error Com_Error
|
||||
|
||||
#define EVENT_FILENAME "ui_events.txt"
|
||||
|
||||
#else
|
||||
//
|
||||
// client specific defines
|
||||
//
|
||||
#define EVENT_DebugPrintf Com_DebugPrintf
|
||||
#define EVENT_DPrintf Com_Printf
|
||||
#define EVENT_Printf Com_Printf
|
||||
#define EVENT_time ( ( ( float )cls.realtime / 1000.0f ) )
|
||||
#define EVENT_realtime Sys_Milliseconds()
|
||||
#define EVENT_Error Com_Error
|
||||
|
||||
#define EVENT_FILENAME "cl_events.txt"
|
||||
#endif
|
||||
|
||||
void L_ClearEventList();
|
||||
bool L_EventSystemStarted( void );
|
||||
void L_InitEvents( void );
|
||||
void L_ProcessPendingEvents();
|
||||
void L_ShutdownEvents( void );
|
||||
void L_ArchiveEvents( Archiver& arc );
|
||||
void L_UnarchiveEvents( Archiver& arc );
|
971
code/qcommon/lz77.cpp
Normal file
971
code/qcommon/lz77.cpp
Normal file
|
@ -0,0 +1,971 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// lz77.cpp: LZ77 Compression Algorithm
|
||||
|
||||
// FIXME: MOHAA devs decided to make things on their own, so we need to find out their lz77 compression algorithm...
|
||||
// we need this to make .pth files work properly
|
||||
// so we currently use an ugly decompile hack to do so
|
||||
|
||||
#include "lz77.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
unsigned int cLZ77::m_pDictionary[ 65535 ];
|
||||
|
||||
cLZ77 g_lz77;
|
||||
|
||||
/*************************************************************************
|
||||
* Constants used for LZ77 coding
|
||||
*************************************************************************/
|
||||
|
||||
/* Maximum offset (can be any size < 2^31). Lower values give faster
|
||||
compression, while higher values gives better compression. The default
|
||||
value of 100000 is quite high. Experiment to see what works best for
|
||||
you. */
|
||||
#define LZ_MAX_OFFSET 100000
|
||||
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* INTERNAL FUNCTIONS *
|
||||
*************************************************************************/
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* _LZ_StringCompare() - Return maximum length string match.
|
||||
*************************************************************************/
|
||||
|
||||
static unsigned int _LZ_StringCompare( unsigned char * str1,
|
||||
unsigned char * str2, unsigned int minlen, unsigned int maxlen )
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
for( len = minlen; ( len < maxlen ) && ( str1[ len ] == str2[ len ] ); ++len );
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* _LZ_WriteVarSize() - Write unsigned integer with variable number of
|
||||
* bytes depending on value.
|
||||
*************************************************************************/
|
||||
|
||||
static int _LZ_WriteVarSize( unsigned int x, unsigned char * buf )
|
||||
{
|
||||
unsigned int y;
|
||||
int num_bytes, i, b;
|
||||
|
||||
/* Determine number of bytes needed to store the number x */
|
||||
y = x >> 3;
|
||||
for( num_bytes = 5; num_bytes >= 2; --num_bytes )
|
||||
{
|
||||
if( y & 0xfe000000 ) break;
|
||||
y <<= 7;
|
||||
}
|
||||
|
||||
/* Write all bytes, seven bits in each, with 8:th bit set for all */
|
||||
/* but the last byte. */
|
||||
for( i = num_bytes - 1; i >= 0; --i )
|
||||
{
|
||||
b = ( x >> ( i * 7 ) ) & 0x0000007f;
|
||||
if( i > 0 )
|
||||
{
|
||||
b |= 0x00000080;
|
||||
}
|
||||
*buf++ = ( unsigned char )b;
|
||||
}
|
||||
|
||||
/* Return number of bytes written */
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* _LZ_ReadVarSize() - Read unsigned integer with variable number of
|
||||
* bytes depending on value.
|
||||
*************************************************************************/
|
||||
|
||||
static int _LZ_ReadVarSize( unsigned int * x, unsigned char * buf )
|
||||
{
|
||||
unsigned int y, b, num_bytes;
|
||||
|
||||
/* Read complete value (stop when byte contains zero in 8:th bit) */
|
||||
y = 0;
|
||||
num_bytes = 0;
|
||||
do
|
||||
{
|
||||
b = ( unsigned int )( *buf++ );
|
||||
y = ( y << 7 ) | ( b & 0x0000007f );
|
||||
++num_bytes;
|
||||
} while( b & 0x00000080 );
|
||||
|
||||
/* Store value in x */
|
||||
*x = y;
|
||||
|
||||
/* Return number of bytes read */
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* PUBLIC FUNCTIONS *
|
||||
*************************************************************************/
|
||||
|
||||
cLZ77::cLZ77()
|
||||
{
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* cLZ77::CompressData - Compress a block of data using an LZ77 coder.
|
||||
* in - Input (uncompressed) buffer.
|
||||
* out - Output (compressed) buffer. This buffer must be 0.4% larger
|
||||
* than the input buffer, plus one byte.
|
||||
* insize - Number of input bytes.
|
||||
* out_len - Output length
|
||||
* The function returns the size of the compressed data.
|
||||
*************************************************************************/
|
||||
|
||||
unsigned int cLZ77::CompressData( unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len )
|
||||
{
|
||||
unsigned char *v5; // eax@1
|
||||
unsigned char *v6; // ebx@2
|
||||
unsigned int v7; // eax@3
|
||||
int v8; // edx@3
|
||||
unsigned int v9; // ecx@3
|
||||
cLZ77 *v10; // edi@3
|
||||
unsigned int v11; // esi@3
|
||||
unsigned int v12; // eax@4
|
||||
int v13; // ecx@5
|
||||
unsigned int v14; // eax@7
|
||||
cLZ77 *v15; // ecx@7
|
||||
int v16; // esi@7
|
||||
int v17; // ecx@8
|
||||
int v18; // edi@9
|
||||
int v19; // eax@12
|
||||
int v20; // edx@13
|
||||
char v21; // zf@15
|
||||
char v22; // cf@17
|
||||
unsigned int v24; // eax@20
|
||||
unsigned char *v25; // ecx@20
|
||||
unsigned char *v26; // ebx@20
|
||||
unsigned char *v27; // ecx@21
|
||||
unsigned char *v28; // eax@23
|
||||
unsigned char *v29; // eax@23
|
||||
unsigned char *v30; // edx@25
|
||||
unsigned int v31; // eax@26
|
||||
unsigned char *v32; // ebx@26
|
||||
unsigned int v33; // eax@27
|
||||
unsigned char *v34; // edx@27
|
||||
char v35; // cl@27
|
||||
cLZ77 *v36; // ebx@27
|
||||
char v37; // cf@29
|
||||
unsigned char *v38; // esi@32
|
||||
char v39; // dl@32
|
||||
unsigned char *v40; // edi@32
|
||||
char v41; // dl@32
|
||||
unsigned char *v42; // edi@32
|
||||
unsigned int v43; // ecx@32
|
||||
unsigned char *v44; // esi@33
|
||||
char v45; // cl@33
|
||||
unsigned char *v46; // edi@33
|
||||
char v47; // dl@33
|
||||
unsigned char *v48; // edi@33
|
||||
unsigned int v49; // ecx@33
|
||||
int v50; // esi@39
|
||||
unsigned int v51; // eax@41
|
||||
unsigned int v52; // edx@41
|
||||
unsigned int v53; // eax@45
|
||||
unsigned char *v54; // edi@45
|
||||
unsigned char *v55; // edx@46
|
||||
unsigned char *v56; // edx@47
|
||||
cLZ77 *v57; // ecx@47
|
||||
int v58; // ecx@49
|
||||
unsigned int v59; // eax@51
|
||||
unsigned char *v60; // ebx@51
|
||||
unsigned char *v61; // edi@52
|
||||
unsigned char *v62; // edx@54
|
||||
unsigned char *v63; // edi@54
|
||||
cLZ77 *v64; // edi@58
|
||||
int v65; // edx@60
|
||||
unsigned char *v66; // [sp+0h] [bp-10h]@39
|
||||
|
||||
this->op = out;
|
||||
v5 = in + 4;
|
||||
this->in_end = &in[ in_len ];
|
||||
this->ip_end = &in[ in_len - 13 ];
|
||||
this->ii = in;
|
||||
this->ip = in + 4;
|
||||
do
|
||||
{
|
||||
v6 = v5;
|
||||
while( 1 )
|
||||
{
|
||||
v8 = v6 - in;
|
||||
v10 = this;
|
||||
v11 = 33 * ( *v6 ^ 32 * ( v6[ 1 ] ^ 32 * ( v6[ 2 ] ^ ( ( unsigned int )v6[ 3 ] << 6 ) ) ) ) >> 5;
|
||||
v9 = ( 33 * ( *v6 ^ 32 * ( v6[ 1 ] ^ 32 * ( v6[ 2 ] ^ ( ( unsigned int )v6[ 3 ] << 6 ) ) ) ) >> 5 ) & 0x3FFF;
|
||||
this->dindex = v9;
|
||||
v7 = m_pDictionary[ v9 ];
|
||||
this->m_off = v7;
|
||||
if( v6 - in <= v7 || ( v12 = v8 - v7, v10 = this, this->m_off = v12, v12 > 0xBFFF ) )
|
||||
{
|
||||
m_pDictionary[ v9 ] = v8;
|
||||
goto LABEL_64;
|
||||
}
|
||||
v13 = ( int )&v6[ -v12 ];
|
||||
this->m_pos = &v6[ -v12 ];
|
||||
if( v12 <= 0x800 || *( unsigned char * )( v13 + 3 ) == v6[ 3 ] )
|
||||
{
|
||||
if( *( unsigned char * )v13 != *v6 || *( unsigned char * )( v13 + 1 ) != v6[ 1 ] || *( unsigned char * )( v13 + 2 ) != v6[ 2 ] )
|
||||
{
|
||||
LABEL_17:
|
||||
m_pDictionary[ dindex ] = v6 - in;
|
||||
v5 = this->ip + 1;
|
||||
v22 = v5 < this->ip_end;
|
||||
this->ip = v5;
|
||||
goto LABEL_18;
|
||||
}
|
||||
goto LABEL_20;
|
||||
}
|
||||
v15 = this;
|
||||
v16 = v11 & 0x7FF ^ 0x201F;
|
||||
this->dindex = v16;
|
||||
v14 = m_pDictionary[ v16 ];
|
||||
this->m_off = v14;
|
||||
if( v8 <= v14 )
|
||||
break;
|
||||
v10 = this;
|
||||
v17 = v8 - v14;
|
||||
this->m_off = v8 - v14;
|
||||
if( v8 - v14 > 0xBFFF )
|
||||
goto LABEL_63;
|
||||
v18 = ( int )&v6[ -v17 ];
|
||||
this->m_pos = &v6[ -v17 ];
|
||||
if( ( unsigned int )v17 <= 0x800 || *( unsigned char * )( v18 + 3 ) == v6[ 3 ] )
|
||||
{
|
||||
if( *( unsigned char * )v18 != *v6 || *( unsigned char * )( v18 + 1 ) != v6[ 1 ] )
|
||||
goto LABEL_17;
|
||||
v21 = *( unsigned char * )( v18 + 2 ) == v6[ 2 ];
|
||||
}
|
||||
else
|
||||
{
|
||||
if( v8 <= ( unsigned int )v17 )
|
||||
{
|
||||
m_pDictionary[ v16 ] = v8;
|
||||
v15 = this;
|
||||
goto LABEL_66;
|
||||
}
|
||||
v10 = this;
|
||||
v19 = v8 - v17;
|
||||
this->m_off = v8 - v17;
|
||||
if( ( unsigned int )( v8 - v17 ) > 0xBFFF )
|
||||
{
|
||||
LABEL_63:
|
||||
m_pDictionary[ v16 ] = v8;
|
||||
LABEL_64:
|
||||
v5 = v10->ip + 1;
|
||||
v22 = v5 < v10->ip_end;
|
||||
v10->ip = v5;
|
||||
goto LABEL_18;
|
||||
}
|
||||
v20 = ( int )&v6[ -v19 ];
|
||||
this->m_pos = &v6[ -v19 ];
|
||||
if( v6[ -v19 ] != *v6 || *( unsigned char * )( v20 + 1 ) != v6[ 1 ] )
|
||||
goto LABEL_17;
|
||||
v21 = *( unsigned char * )( v20 + 2 ) == v6[ 2 ];
|
||||
}
|
||||
if( !v21 )
|
||||
goto LABEL_17;
|
||||
LABEL_20:
|
||||
m_pDictionary[ this->dindex ] = v6 - in;
|
||||
v26 = this->ip;
|
||||
v25 = this->ii;
|
||||
v24 = ( unsigned int )&this->ip[ -( unsigned int )v25 ];
|
||||
if( ( signed int )&this->ip[ -( unsigned int )v25 ] > 0 )
|
||||
{
|
||||
v27 = &this->ip[ -( unsigned int )v25 ];
|
||||
if( v24 > 3 )
|
||||
{
|
||||
if( v24 > 0x12 )
|
||||
{
|
||||
v65 = v24 - 18;
|
||||
*this->op++ = 0;
|
||||
if( v24 - 18 > 0xFF )
|
||||
{
|
||||
do
|
||||
{
|
||||
v65 -= 255;
|
||||
*this->op++ = 0;
|
||||
} while( ( unsigned int )v65 > 0xFF );
|
||||
}
|
||||
v64 = this;
|
||||
*this->op = v65;
|
||||
}
|
||||
else
|
||||
{
|
||||
v64 = this;
|
||||
*this->op = v24 - 3;
|
||||
}
|
||||
++v64->op;
|
||||
}
|
||||
else
|
||||
{
|
||||
*( this->op - 2 ) |= v24;
|
||||
}
|
||||
do
|
||||
{
|
||||
*this->op = *this->ii;
|
||||
v29 = this->ii;
|
||||
++this->op;
|
||||
v28 = v29 + 1;
|
||||
--v27;
|
||||
this->ii = v28;
|
||||
} while( v27 );
|
||||
v26 = this->ip;
|
||||
v25 = v28;
|
||||
}
|
||||
v30 = this->m_pos;
|
||||
this->ip = v26 + 4;
|
||||
if( v30[ 3 ] == v26[ 3 ] )
|
||||
{
|
||||
this->ip = v26 + 5;
|
||||
if( v30[ 4 ] == v26[ 4 ] )
|
||||
{
|
||||
this->ip = v26 + 6;
|
||||
if( v30[ 5 ] == v26[ 5 ] )
|
||||
{
|
||||
this->ip = v26 + 7;
|
||||
if( v30[ 6 ] == v26[ 6 ] )
|
||||
{
|
||||
this->ip = v26 + 8;
|
||||
if( v30[ 7 ] == v26[ 7 ] )
|
||||
{
|
||||
this->ip = v26 + 9;
|
||||
if( v30[ 8 ] == v26[ 8 ] )
|
||||
{
|
||||
v50 = ( int )( v30 + 9 );
|
||||
v66 = this->in_end;
|
||||
if( v26 + 9 < v66 )
|
||||
{
|
||||
if( v26[ 9 ] == v30[ 9 ] )
|
||||
{
|
||||
do
|
||||
{
|
||||
++v50;
|
||||
v62 = this->ip;
|
||||
v63 = this->ip + 1;
|
||||
this->ip = v63;
|
||||
} while( v63 < v66 && v62[ 1 ] == *( unsigned char * )v50 );
|
||||
}
|
||||
}
|
||||
v51 = this->m_off;
|
||||
v52 = ( unsigned int )&this->ip[ -( unsigned int )v25 ];
|
||||
this->m_len = v52;
|
||||
if( v51 > 0x4000 )
|
||||
{
|
||||
v58 = v51 - 16384;
|
||||
this->m_off = v51 - 16384;
|
||||
if( v52 <= 9 )
|
||||
{
|
||||
*this->op++ = ( ( v58 & 0x4000u ) >> 11 ) | ( unsigned char )( *( unsigned char * )&( this->m_len ) - 2 ) | 0x10;
|
||||
goto LABEL_44;
|
||||
}
|
||||
v60 = this->op;
|
||||
this->m_len = v52 - 9;
|
||||
*v60 = ( ( v58 & 0x4000u ) >> 11 ) | 0x10;
|
||||
v59 = this->m_len;
|
||||
++this->op;
|
||||
for( ; v59 > 0xFF; ++this->op )
|
||||
{
|
||||
v61 = this->op;
|
||||
this->m_len = v59 - 255;
|
||||
*v61 = 0;
|
||||
v59 = this->m_len;
|
||||
}
|
||||
v56 = this->op;
|
||||
v57 = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->m_off = v51 - 1;
|
||||
if( v52 <= 0x21 )
|
||||
{
|
||||
*this->op++ = ( *( unsigned char * )&( this->m_len ) - 2 ) | 0x20;
|
||||
LABEL_44:
|
||||
v36 = this;
|
||||
*this->op = 4 * ( this->m_off & 0x3F );
|
||||
v34 = this->op;
|
||||
v33 = this->m_off >> 6;
|
||||
this->op = v34 + 1;
|
||||
goto LABEL_28;
|
||||
}
|
||||
v54 = this->op;
|
||||
this->m_len = v52 - 33;
|
||||
*v54 = 32;
|
||||
v53 = this->m_len;
|
||||
++this->op;
|
||||
for( ; v53 > 0xFF; ++this->op )
|
||||
{
|
||||
v55 = this->op;
|
||||
this->m_len = v53 - 255;
|
||||
*v55 = 0;
|
||||
v53 = this->m_len;
|
||||
}
|
||||
v57 = this;
|
||||
v56 = this->op;
|
||||
}
|
||||
*v56 = *( unsigned char * )&( v57->m_len );
|
||||
++v57->op;
|
||||
goto LABEL_44;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
v31 = this->m_off;
|
||||
v32 = this->ip - 1;
|
||||
this->ip = v32;
|
||||
this->m_len = v32 - v25;
|
||||
if( v31 > 0x800 )
|
||||
{
|
||||
if( v31 > 0x4000 )
|
||||
{
|
||||
v44 = this->op;
|
||||
v45 = *( unsigned char * )&( this->m_len );
|
||||
this->m_off = v31 - 16384;
|
||||
*v44 = ( ( ( v31 - 16384 ) & 0x4000 ) >> 11 ) | ( unsigned char )( v45 - 2 ) | 0x10;
|
||||
v46 = this->op;
|
||||
v47 = *( unsigned char * )&( this->m_off );
|
||||
this->op = v46 + 1;
|
||||
v46[ 1 ] = 4 * ( v47 & 0x3F );
|
||||
v48 = this->op;
|
||||
v49 = this->m_off >> 6;
|
||||
this->op = v48 + 1;
|
||||
v48[ 1 ] = v49;
|
||||
++this->op;
|
||||
}
|
||||
else
|
||||
{
|
||||
v38 = this->op;
|
||||
v39 = *( unsigned char * )&( this->m_len );
|
||||
this->m_off = v31 - 1;
|
||||
*v38 = ( v39 - 2 ) | 0x20;
|
||||
v40 = this->op;
|
||||
v41 = *( unsigned char * )&( this->m_off );
|
||||
this->op = v40 + 1;
|
||||
v40[ 1 ] = 4 * ( v41 & 0x3F );
|
||||
v42 = this->op;
|
||||
v43 = this->m_off >> 6;
|
||||
this->op = v42 + 1;
|
||||
v42[ 1 ] = v43;
|
||||
++this->op;
|
||||
}
|
||||
goto LABEL_29;
|
||||
}
|
||||
v35 = *( unsigned char * )&( this->m_len );
|
||||
v36 = this;
|
||||
this->m_off = v31 - 1;
|
||||
*this->op = 4 * ( this->m_off & 7 ) | 32 * ( v35 - 1 );
|
||||
v34 = this->op;
|
||||
v33 = this->m_off >> 3;
|
||||
this->op = v34 + 1;
|
||||
LABEL_28:
|
||||
v34[ 1 ] = v33;
|
||||
++v36->op;
|
||||
LABEL_29:
|
||||
v37 = this->ip < this->ip_end;
|
||||
v6 = this->ip;
|
||||
this->ii = this->ip;
|
||||
if( !v37 )
|
||||
goto LABEL_19;
|
||||
}
|
||||
m_pDictionary[ v16 ] = v8;
|
||||
LABEL_66:
|
||||
v5 = v15->ip + 1;
|
||||
v22 = v5 < v15->ip_end;
|
||||
v15->ip = v5;
|
||||
LABEL_18:
|
||||
;
|
||||
} while( v22 );
|
||||
LABEL_19:
|
||||
*out_len = ( unsigned int )&this->op[ -( unsigned int )out ];
|
||||
return this->in_end - this->ii;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* cLZ77::Compress - Compress a block of data using an LZ77 coder.
|
||||
* in - Input (uncompressed) buffer.
|
||||
* out - Output (compressed) buffer. This buffer must be 0.4% larger
|
||||
* than the input buffer, plus one byte.
|
||||
* insize - Number of input bytes.
|
||||
* out_len - Output length
|
||||
* The function returns the size of the compressed data.
|
||||
*************************************************************************/
|
||||
|
||||
int cLZ77::Compress( unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len )
|
||||
{
|
||||
unsigned char *v5; // edx@1
|
||||
unsigned int v6; // ecx@1
|
||||
unsigned char *v7; // ebx@3
|
||||
unsigned char v8; // al@6
|
||||
int result; // eax@7
|
||||
int v10; // edx@7
|
||||
int v11; // eax@9
|
||||
|
||||
v5 = out;
|
||||
v6 = in_len;
|
||||
if( in_len > 0xD )
|
||||
{
|
||||
v6 = CompressData( in, in_len, out, out_len );
|
||||
v5 = &out[ *out_len ];
|
||||
}
|
||||
if( v6 )
|
||||
{
|
||||
v7 = &in[ in_len ] - v6;
|
||||
if( v5 != out || v6 > 0xEE )
|
||||
{
|
||||
if( v6 <= 3 )
|
||||
{
|
||||
*( v5 - 2 ) |= v6;
|
||||
goto LABEL_6;
|
||||
}
|
||||
if( v6 > 0x12 )
|
||||
{
|
||||
*v5 = 0;
|
||||
v11 = v6 - 18;
|
||||
++v5;
|
||||
if( v6 - 18 > 0xFF )
|
||||
{
|
||||
do
|
||||
{
|
||||
*v5 = 0;
|
||||
v11 -= 255;
|
||||
++v5;
|
||||
} while( ( unsigned int )v11 > 0xFF );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*( unsigned char * )&v11 = v6 - 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*( unsigned char * )&v11 = v6 + 17;
|
||||
}
|
||||
*v5++ = v11;
|
||||
do
|
||||
{
|
||||
LABEL_6:
|
||||
v8 = *v7++;
|
||||
*v5++ = v8;
|
||||
--v6;
|
||||
} while( v6 );
|
||||
}
|
||||
*v5 = 17;
|
||||
v10 = ( int )( v5 + 1 );
|
||||
result = 0;
|
||||
*( unsigned char * )v10++ = 0;
|
||||
*( unsigned char * )v10 = 0;
|
||||
*out_len = v10 + 1 - ( unsigned int )out;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* cLZ77::Decompress - Uncompress a block of data using an LZ77 decoder.
|
||||
* in - Input (compressed) buffer.
|
||||
* out - Output (uncompressed) buffer. This buffer must be large
|
||||
* enough to hold the uncompressed data.
|
||||
* insize - Number of input bytes.
|
||||
* out_len - Output length
|
||||
*************************************************************************/
|
||||
int cLZ77::Decompress( unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len )
|
||||
{
|
||||
unsigned char v5; // al@1
|
||||
int v6; // esi@2
|
||||
int v7; // ebx@4
|
||||
unsigned int v8; // esi@4
|
||||
unsigned char *v9; // ecx@5
|
||||
int v10; // edx@5
|
||||
int v11; // edx@5
|
||||
unsigned char *v12; // edx@5
|
||||
unsigned char *v13; // esi@5
|
||||
unsigned char *v14; // esi@6
|
||||
unsigned char *v15; // ebx@6
|
||||
int v16; // ecx@7
|
||||
unsigned char v17; // dl@7
|
||||
int v18; // eax@8
|
||||
unsigned char *v19; // ebx@12
|
||||
int v20; // esi@12
|
||||
unsigned int v21; // esi@12
|
||||
int v22; // ecx@12
|
||||
int v23; // edx@12
|
||||
int v24; // eax@12
|
||||
int v25; // ecx@12
|
||||
unsigned char *v26; // ecx@12
|
||||
unsigned char *v27; // ebx@12
|
||||
int v28; // esi@16
|
||||
int v29; // ecx@17
|
||||
int v30; // ebx@17
|
||||
int v31; // edx@18
|
||||
int v32; // ecx@18
|
||||
int v33; // ebx@20
|
||||
int v34; // ecx@21
|
||||
int v35; // ebx@21
|
||||
unsigned int v36; // edx@21
|
||||
unsigned char *v37; // edx@23
|
||||
int v38; // esi@24
|
||||
unsigned char *v39; // ecx@29
|
||||
unsigned char *v40; // ebx@29
|
||||
int v41; // ebx@34
|
||||
int v42; // ecx@35
|
||||
int v43; // ebx@35
|
||||
int v44; // edx@36
|
||||
int v45; // ecx@36
|
||||
int v46; // edx@38
|
||||
int v47; // ecx@39
|
||||
unsigned char *v48; // ecx@39
|
||||
unsigned int v49; // edx@39
|
||||
unsigned int v50; // eax@41
|
||||
int result; // eax@42
|
||||
unsigned char *v52; // ebx@45
|
||||
int v53; // edx@45
|
||||
int v54; // esi@45
|
||||
int v55; // ecx@45
|
||||
int v56; // edx@45
|
||||
int v57; // ebx@49
|
||||
int v58; // eax@50
|
||||
int v59; // esi@51
|
||||
unsigned char *v60; // [sp+0h] [bp-14h]@21
|
||||
|
||||
ip_end = &in[ in_len ];
|
||||
*( unsigned int * )out_len = 0;
|
||||
ip = in;
|
||||
op = ( unsigned char * )out;
|
||||
v5 = *in;
|
||||
if( *in <= 17u )
|
||||
{
|
||||
v16 = ( int )ip;
|
||||
goto LABEL_46;
|
||||
}
|
||||
v6 = v5 - 17;
|
||||
ip = in + 1;
|
||||
if( ( unsigned int )v5 - 17 <= 3 )
|
||||
{
|
||||
v16 = ( int )( in + 1 );
|
||||
goto LABEL_8;
|
||||
}
|
||||
do
|
||||
{
|
||||
*op++ = *ip++;
|
||||
--v6;
|
||||
} while( v6 );
|
||||
LABEL_4:
|
||||
v7 = ( int )ip;
|
||||
v8 = *ip++;
|
||||
if( v8 <= 0xF )
|
||||
{
|
||||
v9 = op;
|
||||
v10 = ( int )&v9[ -( v8 >> 2 ) - 2049 ];
|
||||
m_pos = ( unsigned char * )v10;
|
||||
v11 = v10 - 4 * *( unsigned char * )( v7 + 1 );
|
||||
m_pos = ( unsigned char * )v11;
|
||||
ip = ( unsigned char * )( v7 + 2 );
|
||||
*v9 = *( unsigned char * )v11;
|
||||
v12 = m_pos;
|
||||
m_pos = v12 + 1;
|
||||
v13 = op;
|
||||
op = v13 + 1;
|
||||
v13[ 1 ] = v12[ 1 ];
|
||||
LABEL_6:
|
||||
v14 = m_pos;
|
||||
m_pos = v14 + 1;
|
||||
v15 = op;
|
||||
op = v15 + 1;
|
||||
v15[ 1 ] = v14[ 1 ];
|
||||
++op;
|
||||
goto LABEL_7;
|
||||
}
|
||||
while( 1 )
|
||||
{
|
||||
if( v8 > 0x3F )
|
||||
{
|
||||
v19 = op;
|
||||
v21 = v8 >> 2;
|
||||
v22 = ( int )&v19[ -( v21 & 7 ) - 1 ];
|
||||
v23 = ( int )ip;
|
||||
m_pos = ( unsigned char * )v22;
|
||||
v24 = *( unsigned char * )v23;
|
||||
ip = ( unsigned char * )( v23 + 1 );
|
||||
v20 = ( v21 >> 3 ) - 1;
|
||||
v25 = v22 - 8 * v24;
|
||||
m_pos = ( unsigned char * )v25;
|
||||
*v19 = *( unsigned char * )v25;
|
||||
v26 = m_pos;
|
||||
m_pos = v26 + 1;
|
||||
v27 = op;
|
||||
op = v27 + 1;
|
||||
v27[ 1 ] = v26[ 1 ];
|
||||
++m_pos;
|
||||
++op;
|
||||
do
|
||||
{
|
||||
*op++ = *m_pos++;
|
||||
--v20;
|
||||
} while( v20 );
|
||||
goto LABEL_7;
|
||||
}
|
||||
if( v8 > 0x1F )
|
||||
{
|
||||
v28 = v8 & 0x1F;
|
||||
if( !v28 )
|
||||
{
|
||||
v29 = ( int )ip;
|
||||
v30 = ( int )ip;
|
||||
if( !*ip )
|
||||
{
|
||||
do
|
||||
{
|
||||
v31 = v30 + 1;
|
||||
v32 = v30;
|
||||
v28 += 255;
|
||||
ip = ( unsigned char * )( v30++ + 1 );
|
||||
} while( !*( unsigned char * )( v32 + 1 ) );
|
||||
v29 = v31;
|
||||
}
|
||||
v33 = *( unsigned char * )v29;
|
||||
ip = ( unsigned char * )( v29 + 1 );
|
||||
v28 += v33 + 31;
|
||||
}
|
||||
v34 = ( int )( op - 1 );
|
||||
v60 = op;
|
||||
v35 = ( int )ip;
|
||||
m_pos = ( unsigned char * )v34;
|
||||
v36 = *( unsigned short * )v35;
|
||||
ip = ( unsigned char * )( v35 + 2 );
|
||||
m_pos = ( unsigned char * )( v34 - ( v36 >> 2 ) );
|
||||
goto LABEL_22;
|
||||
}
|
||||
if( v8 <= 0xF )
|
||||
{
|
||||
v52 = op;
|
||||
v53 = ( int )&v52[ -( v8 >> 2 ) - 1 ];
|
||||
v54 = ( int )ip;
|
||||
m_pos = ( unsigned char * )v53;
|
||||
v55 = *( unsigned char * )v54;
|
||||
ip = ( unsigned char * )( v54 + 1 );
|
||||
v56 = v53 - 4 * v55;
|
||||
m_pos = ( unsigned char * )v56;
|
||||
*v52 = *( unsigned char * )v56;
|
||||
goto LABEL_6;
|
||||
}
|
||||
v60 = op;
|
||||
v41 = ( int )&v60[ -2048 * ( v8 & 8 ) ];
|
||||
v28 = v8 & 7;
|
||||
m_pos = ( unsigned char * )v41;
|
||||
if( !v28 )
|
||||
{
|
||||
v42 = ( int )ip;
|
||||
v43 = ( int )ip;
|
||||
if( !*ip )
|
||||
{
|
||||
do
|
||||
{
|
||||
v44 = v43 + 1;
|
||||
v45 = v43;
|
||||
v28 += 255;
|
||||
ip = ( unsigned char * )( v43++ + 1 );
|
||||
} while( !*( unsigned char * )( v45 + 1 ) );
|
||||
v42 = v44;
|
||||
}
|
||||
v46 = *( unsigned char * )v42;
|
||||
ip = ( unsigned char * )( v42 + 1 );
|
||||
v28 += v46 + 7;
|
||||
}
|
||||
v48 = m_pos;
|
||||
v49 = *( unsigned short * )ip;
|
||||
ip += 2;
|
||||
v47 = ( int )&v48[ -( v49 >> 2 ) ];
|
||||
m_pos = ( unsigned char * )v47;
|
||||
if( ( unsigned char * )v47 == v60 )
|
||||
break;
|
||||
m_pos = ( unsigned char * )( v47 - 16384 );
|
||||
LABEL_22:
|
||||
if( ( unsigned int )v28 <= 5 )
|
||||
{
|
||||
v37 = m_pos;
|
||||
LABEL_29:
|
||||
*v60 = *v37;
|
||||
v39 = m_pos;
|
||||
m_pos = v39 + 1;
|
||||
v40 = op;
|
||||
op = v40 + 1;
|
||||
v40[ 1 ] = v39[ 1 ];
|
||||
++m_pos;
|
||||
++op;
|
||||
do
|
||||
{
|
||||
*op++ = *m_pos++;
|
||||
--v28;
|
||||
} while( v28 );
|
||||
goto LABEL_7;
|
||||
}
|
||||
v37 = m_pos;
|
||||
if( ( signed int )( v60 - v37 ) <= 3 )
|
||||
goto LABEL_29;
|
||||
v38 = v28 - 2;
|
||||
*( unsigned int * )v60 = *( unsigned int * )v37;
|
||||
op += 4;
|
||||
m_pos += 4;
|
||||
do
|
||||
{
|
||||
v38 -= 4;
|
||||
*( unsigned int * )op = *( unsigned int * )m_pos;
|
||||
op += 4;
|
||||
m_pos += 4;
|
||||
} while( ( unsigned int )v38 > 3 );
|
||||
for( ; v38; --v38 )
|
||||
*op++ = *m_pos++;
|
||||
LABEL_7:
|
||||
v16 = ( int )ip;
|
||||
v17 = *( ip - 2 ) & 3;
|
||||
v6 = v17;
|
||||
if( v17 )
|
||||
{
|
||||
LABEL_8:
|
||||
while( 1 )
|
||||
{
|
||||
*op = *( unsigned char * )v16;
|
||||
v18 = ( int )ip;
|
||||
++op;
|
||||
--v6;
|
||||
ip = ( unsigned char * )( v18 + 1 );
|
||||
if( !v6 )
|
||||
break;
|
||||
v16 = v18 + 1;
|
||||
}
|
||||
v8 = *( unsigned char * )( v18 + 1 );
|
||||
ip = ( unsigned char * )( v18 + 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
LABEL_46:
|
||||
v8 = *( unsigned char * )v16;
|
||||
ip = ( unsigned char * )( v16 + 1 );
|
||||
if( v8 <= 0xF )
|
||||
{
|
||||
if( !v8 )
|
||||
{
|
||||
if( !*( unsigned char * )( v16 + 1 ) )
|
||||
{
|
||||
do
|
||||
{
|
||||
v57 = ( int )ip;
|
||||
v8 += 255;
|
||||
++ip;
|
||||
} while( !*( unsigned char * )( v57 + 1 ) );
|
||||
}
|
||||
v58 = *ip++;
|
||||
v8 += v58 + 15;
|
||||
}
|
||||
*( unsigned int * )op = *( unsigned int * )ip;
|
||||
op += 4;
|
||||
ip += 4;
|
||||
v59 = v8 - 1;
|
||||
if( v59 )
|
||||
{
|
||||
if( ( unsigned int )v59 <= 3 )
|
||||
{
|
||||
do
|
||||
{
|
||||
*op++ = *ip++;
|
||||
--v59;
|
||||
} while( v59 );
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
v59 -= 4;
|
||||
*( unsigned int * )op = *( unsigned int * )ip;
|
||||
op += 4;
|
||||
ip += 4;
|
||||
} while( ( unsigned int )v59 > 3 );
|
||||
for( ; v59; --v59 )
|
||||
*op++ = *ip++;
|
||||
}
|
||||
}
|
||||
goto LABEL_4;
|
||||
}
|
||||
}
|
||||
}
|
||||
*out_len = v47 - ( unsigned int )out;
|
||||
v50 = ( unsigned int )ip_end;
|
||||
if( ip == ( unsigned char * )v50 )
|
||||
result = 0;
|
||||
else
|
||||
result = -( ip < ( unsigned char * )v50 ) | 0xFFFFFFFE;
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned char in[ 0x40000 ];
|
||||
static unsigned char out[ 0x41013 ];
|
||||
|
||||
void test_compression()
|
||||
{
|
||||
size_t in_len;
|
||||
size_t out_len;
|
||||
size_t new_len;
|
||||
cLZ77 lz77;
|
||||
|
||||
memset( &in, 0, 0x40000 );
|
||||
|
||||
if( lz77.Compress( in, sizeof( in ), out, &out_len ) )
|
||||
{
|
||||
puts( "Compression Failed!" );
|
||||
return;
|
||||
}
|
||||
|
||||
printf( "Compressed %i bytes into %i bytes\n", 0x40000, out_len );
|
||||
|
||||
if( lz77.Decompress( out, out_len, in, &in_len ) )
|
||||
{
|
||||
new_len = in_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_len = in_len;
|
||||
|
||||
if( in_len == 0x40000 )
|
||||
{
|
||||
printf( "Decompressed %i bytes into %i bytes\n", out_len, 0x40000 );
|
||||
puts( "Compression Test: Passed" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printf( "Decompression got FuBar'd... %i != %i\n", 0x40000, new_len );
|
||||
}
|
53
code/qcommon/lz77.h
Normal file
53
code/qcommon/lz77.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// lz77.h: LZ77 Compression Algorithm
|
||||
|
||||
#ifndef __LZ77_H__
|
||||
#define __LZ77_H__
|
||||
|
||||
class cLZ77 {
|
||||
static unsigned int m_pDictionary[];
|
||||
|
||||
unsigned char *ip;
|
||||
unsigned char *op;
|
||||
unsigned char *in_end;
|
||||
unsigned char *ip_end;
|
||||
unsigned char *ii;
|
||||
unsigned char *m_pos;
|
||||
unsigned int m_off;
|
||||
unsigned int m_len;
|
||||
unsigned int dindex;
|
||||
|
||||
public:
|
||||
cLZ77();
|
||||
|
||||
int Compress( unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len );
|
||||
int Decompress( unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len );
|
||||
|
||||
private:
|
||||
unsigned int CompressData( unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len );
|
||||
};
|
||||
|
||||
extern cLZ77 g_lz77;
|
||||
|
||||
#endif /* __LZ77_H__ */
|
|
@ -22,14 +22,32 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
// mem_blockalloc.cpp: Fast block memory manager
|
||||
|
||||
#include <glb_local.h>
|
||||
#if defined(GAME_DLL)
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
void *MEM_Alloc( int size )
|
||||
{
|
||||
return glbs.Malloc( size );
|
||||
return gi.Malloc( size );
|
||||
}
|
||||
|
||||
void MEM_Free( void *ptr )
|
||||
{
|
||||
return glbs.Free( ptr );
|
||||
return gi.Free( ptr );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "qcommon.h"
|
||||
|
||||
void* MEM_Alloc(int size)
|
||||
{
|
||||
return Z_Malloc(size);
|
||||
}
|
||||
|
||||
void MEM_Free(void* ptr)
|
||||
{
|
||||
return Z_Free(ptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,8 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#ifndef __MEM_BLOCKALLOC_H__
|
||||
#define __MEM_BLOCKALLOC_H__
|
||||
|
||||
#include <linklist.h>
|
||||
#include "dbgheap.h"
|
||||
#include "linklist.h"
|
||||
|
||||
#define MEM_BLOCKSIZE char[ 256 ]
|
||||
|
||||
|
|
|
@ -22,12 +22,23 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
// mem_tempalloc.cpp: Fast temporary memory manager
|
||||
|
||||
#include <glb_local.h>
|
||||
#include <mem_tempalloc.h>
|
||||
|
||||
#ifdef GAME_DLL
|
||||
#include "g_local.h"
|
||||
|
||||
#define MEM_TempAllocate(x) gi.Malloc(x)
|
||||
#define MEM_TempFree(x) gi.Free(x)
|
||||
#else
|
||||
#include "qcommon.h"
|
||||
|
||||
#define MEM_TempAllocate(x) Z_Malloc(x)
|
||||
#define MEM_TempFree(x) Z_Free(x)
|
||||
#endif
|
||||
|
||||
MEM_TempAlloc::MEM_TempAlloc()
|
||||
{
|
||||
m_CurrentMemoryBlock = NULL;
|
||||
m_CurrentMemoryBlock = nullptr;
|
||||
}
|
||||
|
||||
void *MEM_TempAlloc::Alloc( size_t len )
|
||||
|
@ -47,7 +58,7 @@ void *MEM_TempAlloc::Alloc( size_t len )
|
|||
if( len < 65536 )
|
||||
len = 65536;
|
||||
|
||||
m_CurrentMemoryBlock = ( unsigned char * )glbs.Malloc( len + sizeof( unsigned char * ) );
|
||||
m_CurrentMemoryBlock = ( unsigned char * )MEM_TempAllocate( len + sizeof( unsigned char * ) );
|
||||
*( unsigned char ** )m_CurrentMemoryBlock = prev_block;
|
||||
result = m_CurrentMemoryBlock + sizeof( unsigned char * );
|
||||
}
|
||||
|
@ -62,7 +73,7 @@ void MEM_TempAlloc::FreeAll( void )
|
|||
while( m_CurrentMemoryBlock )
|
||||
{
|
||||
prev_block = *( unsigned char ** )m_CurrentMemoryBlock;
|
||||
glbs.Free( m_CurrentMemoryBlock );
|
||||
MEM_TempFree( m_CurrentMemoryBlock );
|
||||
m_CurrentMemoryBlock = prev_block;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -579,7 +579,7 @@ void ByteToDir( int b, vec3_t dir );
|
|||
#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 VectorAdd2D(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1])
|
||||
#define VectorSub2D(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1])
|
||||
#define VectorSub2D(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1])
|
||||
#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
|
||||
#define VectorCopy2D(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1])
|
||||
#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))
|
||||
|
|
|
@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#ifndef __QFILES_H__
|
||||
#define __QFILES_H__
|
||||
|
||||
#include "q_shared.h"
|
||||
|
||||
//
|
||||
// qfiles.h: quake file formats
|
||||
// This file must be identical in the quake and utils directories
|
||||
|
|
246
code/qcommon/safeptr.h
Normal file
246
code/qcommon/safeptr.h
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2008 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// safeptr.h: Safe Pointers
|
||||
|
||||
#ifndef __SAFEPTR_H__
|
||||
#define __SAFEPTR_H__
|
||||
|
||||
#include "linklist.h"
|
||||
|
||||
class SafePtrBase
|
||||
{
|
||||
private:
|
||||
void AddReference( Class *ptr );
|
||||
void RemoveReference( Class *ptr );
|
||||
|
||||
protected:
|
||||
SafePtrBase *prev;
|
||||
SafePtrBase *next;
|
||||
Class *ptr;
|
||||
|
||||
public:
|
||||
SafePtrBase();
|
||||
virtual ~SafePtrBase();
|
||||
void InitSafePtr( Class *newptr );
|
||||
Class *Pointer( void );
|
||||
void Clear( void );
|
||||
};
|
||||
|
||||
inline void SafePtrBase::AddReference( Class *ptr )
|
||||
{
|
||||
if( !ptr->SafePtrList )
|
||||
{
|
||||
ptr->SafePtrList = this;
|
||||
LL_Reset( this, next, prev );
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_Add( ptr->SafePtrList, this, next, prev );
|
||||
}
|
||||
}
|
||||
|
||||
inline void SafePtrBase::RemoveReference( Class *ptr )
|
||||
{
|
||||
if( ptr->SafePtrList == this )
|
||||
{
|
||||
if( ptr->SafePtrList->next == this )
|
||||
{
|
||||
ptr->SafePtrList = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr->SafePtrList = next;
|
||||
LL_Remove( this, next, prev );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_Remove( this, next, prev );
|
||||
}
|
||||
}
|
||||
|
||||
inline void SafePtrBase::Clear( void )
|
||||
{
|
||||
if( ptr )
|
||||
{
|
||||
RemoveReference( ptr );
|
||||
ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline SafePtrBase::SafePtrBase()
|
||||
{
|
||||
prev = nullptr;
|
||||
next = nullptr;
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
||||
inline SafePtrBase::~SafePtrBase()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
inline Class * SafePtrBase::Pointer( void )
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
inline void SafePtrBase::InitSafePtr( Class *newptr )
|
||||
{
|
||||
if( ptr != newptr )
|
||||
{
|
||||
if( ptr )
|
||||
{
|
||||
RemoveReference( ptr );
|
||||
}
|
||||
|
||||
ptr = newptr;
|
||||
if( ptr == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AddReference( ptr );
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
class SafePtr : public SafePtrBase
|
||||
{
|
||||
public:
|
||||
SafePtr( T* objptr = 0 );
|
||||
SafePtr( const SafePtr& obj );
|
||||
|
||||
SafePtr& operator=( const SafePtr& obj );
|
||||
SafePtr& operator=( T * const obj );
|
||||
|
||||
#ifdef LINUX
|
||||
friend bool operator==<>( SafePtr<T> a, T *b );
|
||||
friend bool operator!=<>( SafePtr<T> a, T *b );
|
||||
friend bool operator==<>( T *a, SafePtr<T> b );
|
||||
friend bool operator!=<>( T *a, SafePtr<T> b );
|
||||
friend bool operator==<>( SafePtr<T> a, SafePtr<T> b );
|
||||
friend bool operator!=<>( SafePtr<T> a, SafePtr<T> b );
|
||||
#else
|
||||
// The compiler/linker gets confused when the friend functions definition are not templated
|
||||
template< class U > friend bool operator==( SafePtr<U> a, U *b );
|
||||
template< class U > friend bool operator!=( SafePtr<U> a, U *b );
|
||||
template< class U > friend bool operator==( U *a, SafePtr<U> b );
|
||||
template< class U > friend bool operator!=( U *a, SafePtr<U> b );
|
||||
template< class U > friend bool operator==( SafePtr<U> a, SafePtr<U> b );
|
||||
template< class U > friend bool operator!=( SafePtr<U> a, SafePtr<U> b );
|
||||
#endif
|
||||
|
||||
bool operator !( ) const;
|
||||
operator T*( ) const;
|
||||
T* operator->( ) const;
|
||||
T& operator*( ) const;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
inline SafePtr<T>::SafePtr( T* objptr )
|
||||
{
|
||||
InitSafePtr( ( Class * )objptr );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline SafePtr<T>::SafePtr( const SafePtr& obj )
|
||||
{
|
||||
InitSafePtr( obj.ptr );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline SafePtr<T>& SafePtr<T>::operator=( const SafePtr& obj )
|
||||
{
|
||||
InitSafePtr( obj.ptr );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline SafePtr<T>& SafePtr<T>::operator=( T * const obj )
|
||||
{
|
||||
InitSafePtr( obj );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool operator==( SafePtr<T> a, T *b )
|
||||
{
|
||||
return a.ptr == b;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool operator!=( SafePtr<T> a, T* b )
|
||||
{
|
||||
return a.ptr != b;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool operator==( T* a, SafePtr<T> b )
|
||||
{
|
||||
return a == b.ptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool operator!=( T* a, SafePtr<T> b )
|
||||
{
|
||||
return a != b.ptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool operator==( SafePtr<T> a, SafePtr<T> b )
|
||||
{
|
||||
return a.ptr == b.ptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool operator!=( SafePtr<T> a, SafePtr<T> b )
|
||||
{
|
||||
return a.ptr != b.ptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool SafePtr<T>::operator !( ) const
|
||||
{
|
||||
return ptr == nullptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline SafePtr<T>::operator T*( ) const
|
||||
{
|
||||
return ( T * )ptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T* SafePtr<T>::operator->( ) const
|
||||
{
|
||||
return ( T * )ptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T& SafePtr<T>::operator*( ) const
|
||||
{
|
||||
return *( T * )ptr;
|
||||
}
|
||||
|
||||
#endif
|
1217
code/qcommon/script.cpp
Normal file
1217
code/qcommon/script.cpp
Normal file
File diff suppressed because it is too large
Load diff
188
code/qcommon/script.h
Normal file
188
code/qcommon/script.h
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// script.h: C++ implementation of tokenization/interpretation.
|
||||
|
||||
#ifndef __SCRIPT_H__
|
||||
#define __SCRIPT_H__
|
||||
|
||||
#include "class.h"
|
||||
#include "vector.h"
|
||||
#include "str.h"
|
||||
|
||||
#if defined(ARCHIVE_SUPPORTED)
|
||||
#include "archive.h"
|
||||
#endif
|
||||
|
||||
#define TOKENCOMMENT (';')
|
||||
#define TOKENCOMMENT2 ('#')
|
||||
#define TOKENEOL ('\n')
|
||||
//#define TOKENNULL ('\0')
|
||||
#define TOKENSPACE (' ')
|
||||
#define TOKENSPECIAL ('$')
|
||||
|
||||
#define MAXTOKEN 512
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean tokenready;
|
||||
int offset;
|
||||
int line;
|
||||
char token[ MAXTOKEN ];
|
||||
} scriptmarker_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
//const char *macroName;
|
||||
//const char *macroText;
|
||||
str macroName;
|
||||
str macroText;
|
||||
} macro;
|
||||
|
||||
class Script : public Class
|
||||
{
|
||||
protected:
|
||||
qboolean tokenready;
|
||||
|
||||
str filename;
|
||||
const char *script_p;
|
||||
const char *end_p;
|
||||
Container<macro *> macrolist;
|
||||
|
||||
int line;
|
||||
char token[ MAXTOKEN ];
|
||||
|
||||
qboolean releaseBuffer;
|
||||
qboolean hasError;
|
||||
|
||||
qboolean AtComment( void );
|
||||
void CheckOverflow( void );
|
||||
|
||||
public:
|
||||
const char *buffer;
|
||||
size_t length;
|
||||
|
||||
CLASS_PROTOTYPE( Script );
|
||||
|
||||
#if defined(ARCHIVE_SUPPORTED)
|
||||
virtual void Archive( Archiver &arc );
|
||||
#endif
|
||||
|
||||
~Script();
|
||||
Script( const char* filename );
|
||||
Script();
|
||||
|
||||
void Close( void );
|
||||
const char *Filename( void );
|
||||
int GetLineNumber( void );
|
||||
void Reset( void );
|
||||
void MarkPosition( scriptmarker_t *mark );
|
||||
void RestorePosition( const scriptmarker_t *mark );
|
||||
qboolean SkipToEOL( void );
|
||||
void SkipWhiteSpace( qboolean crossline );
|
||||
void SkipNonToken( qboolean crossline );
|
||||
qboolean TokenAvailable( qboolean crossline );
|
||||
qboolean CommentAvailable( qboolean crossline );
|
||||
void UnGetToken( void );
|
||||
qboolean AtString( qboolean crossline );
|
||||
qboolean AtOpenParen( qboolean crossline );
|
||||
qboolean AtCloseParen( qboolean crossline );
|
||||
qboolean AtComma( qboolean crossline );
|
||||
qboolean AtDot( qboolean crossline );
|
||||
qboolean AtAssignment( qboolean crossline );
|
||||
const char *GetToken( qboolean crossline );
|
||||
const char *GetLine( qboolean crossline );
|
||||
const char *GetRaw( void );
|
||||
const char *GetString( qboolean crossline );
|
||||
qboolean GetSpecific( const char *string );
|
||||
qboolean GetBoolean( qboolean crossline );
|
||||
int GetInteger( qboolean crossline );
|
||||
double GetDouble( qboolean crossline );
|
||||
float GetFloat( qboolean crossline );
|
||||
Vector GetVector( qboolean crossline );
|
||||
int LinesInFile( void );
|
||||
void Parse( const char *data, size_t length, const char *name );
|
||||
void LoadFile( const char *name );
|
||||
void LoadFile( const char *name, int length, const char *buf );
|
||||
const char *Token( void );
|
||||
void AddMacroDefinition( qboolean crossline );
|
||||
const char *GetMacroString( const char *theMacroName );
|
||||
char *EvaluateMacroString( const char *theMacroString );
|
||||
float EvaluateMacroMath(float value, float newval, char oper);
|
||||
const char *GetExprToken(const char *ptr, char *token);
|
||||
const char *GrabNextToken( qboolean crossline );
|
||||
qboolean isMacro( void );
|
||||
|
||||
qboolean EndOfFile();
|
||||
qboolean isValid( void );
|
||||
|
||||
Container<macro *> *GetMacroList() { return ¯olist; }
|
||||
void AddMacro(const char *name, const char *value);
|
||||
};
|
||||
|
||||
#if defined(ARCHIVE_SUPPORTED)
|
||||
|
||||
inline void Script::Archive
|
||||
(
|
||||
Archiver &arc
|
||||
)
|
||||
{
|
||||
int pos;
|
||||
|
||||
arc.ArchiveBoolean( &tokenready );
|
||||
|
||||
arc.ArchiveString( &filename );
|
||||
if ( arc.Loading() )
|
||||
{
|
||||
//
|
||||
// load the file in
|
||||
//
|
||||
LoadFile( filename.c_str() );
|
||||
}
|
||||
|
||||
if ( !arc.Loading() )
|
||||
{
|
||||
//
|
||||
// save out current pointer as an offset
|
||||
//
|
||||
pos = script_p - buffer;
|
||||
}
|
||||
arc.ArchiveInteger( &pos );
|
||||
if ( arc.Loading() )
|
||||
{
|
||||
//
|
||||
// restore the script pointer
|
||||
//
|
||||
script_p = buffer + pos;
|
||||
}
|
||||
|
||||
//const char *end_p;
|
||||
//Container<macro *> macrolist;
|
||||
|
||||
arc.ArchiveInteger( &line );
|
||||
arc.ArchiveRaw( &token, sizeof( token ) );
|
||||
|
||||
//qboolean releaseBuffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -164,8 +164,6 @@ class str
|
|||
void SkipPath();
|
||||
};
|
||||
|
||||
typedef unsigned int const_str;
|
||||
|
||||
char *strstrip( char *string );
|
||||
char *strlwc( char *string );
|
||||
|
||||
|
|
|
@ -145,12 +145,12 @@ typedef struct dloaddef_s {
|
|||
|
||||
#include "../skeletor/skeletor.h"
|
||||
|
||||
#include "../qcommon/tiki_main.h"
|
||||
#include "../tiki/tiki_anim.h"
|
||||
#include "../tiki/tiki_cache.h"
|
||||
#include "../tiki/tiki_commands.h"
|
||||
#include "../tiki/tiki_files.h"
|
||||
#include "../tiki/tiki_imports.h"
|
||||
#include "../tiki/tiki_main.h"
|
||||
#include "../tiki/tiki_parse.h"
|
||||
#include "../tiki/tiki_skel.h"
|
||||
#include "../tiki/tiki_tag.h"
|
||||
|
|
198
code/qcommon/tiki_main.cpp
Normal file
198
code/qcommon/tiki_main.cpp
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// tiki_skel.cpp : TIKI skeletor loader
|
||||
|
||||
#include "q_shared.h"
|
||||
#include "qcommon.h"
|
||||
#include "../tiki/tiki_shared.h"
|
||||
|
||||
int cache_numskel = 0;
|
||||
int cache_maxskel = 0;
|
||||
skelcache_t skelcache[ TIKI_MAX_SKELCACHE ];
|
||||
|
||||
/*
|
||||
===============
|
||||
TIKI_AddPointToBounds
|
||||
===============
|
||||
*/
|
||||
void TIKI_AddPointToBounds( float *v, float *mins, float *maxs )
|
||||
{
|
||||
int i;
|
||||
vec_t val;
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
val = v[ i ];
|
||||
|
||||
if( val < mins[ i ] )
|
||||
{
|
||||
mins[ i ] = val;
|
||||
}
|
||||
|
||||
if( val > maxs[ i ] )
|
||||
{
|
||||
maxs[ i ] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
TIKI_Message
|
||||
===============
|
||||
*/
|
||||
void TIKI_Message( const char *fmt, ... )
|
||||
{
|
||||
char msg[ 1024 ];
|
||||
va_list va;
|
||||
|
||||
va_start( va, fmt );
|
||||
vsprintf( msg, fmt, va );
|
||||
va_end( va );
|
||||
Skel_DPrintf( msg );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
TIKI_Warning
|
||||
===============
|
||||
*/
|
||||
void TIKI_Warning( const char *fmt, ... )
|
||||
{
|
||||
char msg[ 1024 ];
|
||||
va_list va;
|
||||
|
||||
va_start( va, fmt );
|
||||
vsprintf( msg, fmt, va );
|
||||
va_end( va );
|
||||
Skel_DPrintf( msg );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
TIKI_Error
|
||||
===============
|
||||
*/
|
||||
void TIKI_Error( const char *fmt, ... )
|
||||
{
|
||||
char msg[ 1024 ];
|
||||
va_list va;
|
||||
|
||||
va_start( va, fmt );
|
||||
vsprintf( msg, fmt, va );
|
||||
va_end( va );
|
||||
Skel_DPrintf( msg );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
TIKI_SetupIndividualSurface
|
||||
===============
|
||||
*/
|
||||
void TIKI_SetupIndividualSurface( const char *filename, dtikisurface_t *surf, const char *name, dloadsurface_t *loadsurf )
|
||||
{
|
||||
int j;
|
||||
|
||||
surf->numskins = 0;
|
||||
for( j = 0; j < loadsurf->numskins; j++ )
|
||||
{
|
||||
if( surf->numskins >= MAX_TIKI_SHADER )
|
||||
{
|
||||
TIKI_Error( "TIKI_SetupIndividualSurface: Too many skins defined for surface %s in %s.\n", loadsurf->name, filename );
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy( surf->name, name, sizeof( surf->name ) );
|
||||
strncpy( surf->shader[ surf->numskins ], loadsurf->shader[ j ], sizeof( surf->shader[ surf->numskins ] ) );
|
||||
surf->numskins++;
|
||||
}
|
||||
}
|
||||
|
||||
surf->flags = loadsurf->flags;
|
||||
surf->damage_multiplier = loadsurf->damage_multiplier;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
TIKI_CalcAnimDefSize
|
||||
===============
|
||||
*/
|
||||
size_t TIKI_CalcAnimDefSize( dloaddef_t *ld )
|
||||
{
|
||||
int i, j, k;
|
||||
size_t defsize = ld->numclientinitcmds * sizeof( dtikicmd_t ) + ( ld->numserverinitcmds * 3 + ld->numanims ) + sizeof( dtikianimdef_t );
|
||||
|
||||
for( i = 0; i < ld->numserverinitcmds; i++ )
|
||||
{
|
||||
defsize += sizeof( char * );
|
||||
|
||||
for( j = 0; j < ld->loadserverinitcmds[ i ]->num_args; j++ )
|
||||
{
|
||||
defsize += strlen( ld->loadserverinitcmds[ i ]->args[ j ] ) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for( i = 0; i < ld->numclientinitcmds; i++ )
|
||||
{
|
||||
defsize += sizeof( char * );
|
||||
|
||||
for( j = 0; j < ld->loadclientinitcmds[ i ]->num_args; j++ )
|
||||
{
|
||||
defsize += strlen( ld->loadclientinitcmds[ i ]->args[ j ] ) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for( i = 0; i < ld->numanims; i++ )
|
||||
{
|
||||
defsize += ld->loadanims[ i ]->num_server_cmds * sizeof( dtikicmd_t ) + sizeof( dtikianimdef_t );
|
||||
|
||||
for( j = 0; j < ld->loadanims[ i ]->num_server_cmds; j++ )
|
||||
{
|
||||
defsize += ld->loadanims[ i ]->loadservercmds[ j ]->num_args * sizeof( char * );
|
||||
for( k = 0; k < ld->loadanims[ i ]->loadservercmds[ j ]->num_args; k++ )
|
||||
{
|
||||
defsize += strlen( ld->loadanims[ i ]->loadservercmds[ j ]->args[ k ] ) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defsize += ld->modelBuf->cursize + strlen( ld->headmodels ) + 1 + strlen( ld->headskins ) + 1;
|
||||
return defsize;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
TIKI_FillTIKIStructureSkel
|
||||
===============
|
||||
*/
|
||||
dtikianim_t *TIKI_FillTIKIStructureSkel( dloaddef_t *ld )
|
||||
{
|
||||
size_t animdefsize;
|
||||
size_t defsize;
|
||||
|
||||
animdefsize = TIKI_CalcAnimDefSize( ld );
|
||||
defsize = strlen( ld->path );
|
||||
|
||||
// FIXME: what is 477 ?
|
||||
return TIKI_InitTiki( ld, animdefsize + defsize + sizeof( dloaddef_t ) + 477 );
|
||||
}
|
48
code/qcommon/tiki_main.h
Normal file
48
code/qcommon/tiki_main.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// tiki_main.h : TIKI main
|
||||
|
||||
#ifndef __TIKI_MAIN_H__
|
||||
#define __TIKI_MAIN_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int cache_numskel;
|
||||
extern int cache_maxskel;
|
||||
extern skelcache_t skelcache[];
|
||||
|
||||
void TIKI_AddPointToBounds( float *v, float *mins, float *maxs );
|
||||
void TIKI_Message( const char *fmt, ... );
|
||||
void TIKI_Warning( const char *fmt, ... );
|
||||
void TIKI_Error( const char *fmt, ... );
|
||||
void TIKI_SetupIndividualSurface( const char *filename, dtikisurface_t *surf, const char *name, dloadsurface_t *loadsurf );
|
||||
size_t TIKI_CalcAnimDefSize( dloaddef_t *ld );
|
||||
dtikianim_t *TIKI_FillTIKIStructureSkel( dloaddef_t *ld );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __TIKI_MAIN_H__
|
|
@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include "q_shared.h"
|
||||
#include "qcommon.h"
|
||||
#include <tiki.h>
|
||||
#include "dbgheap.h"
|
||||
|
||||
TikiScript *TikiScript::currentScript;
|
||||
|
||||
|
|
1295
code/qcommon/vector.h
Normal file
1295
code/qcommon/vector.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,888 +0,0 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// vm.c -- virtual machine
|
||||
|
||||
/*
|
||||
|
||||
|
||||
intermix code and data
|
||||
symbol table
|
||||
|
||||
a dll has one imported function: VM_SystemCall
|
||||
and one exported function: Perform
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include "vm_local.h"
|
||||
|
||||
|
||||
vm_t *currentVM = NULL;
|
||||
vm_t *lastVM = NULL;
|
||||
int vm_debugLevel;
|
||||
|
||||
#define MAX_VM 3
|
||||
vm_t vmTable[MAX_VM];
|
||||
|
||||
|
||||
void VM_VmInfo_f( void );
|
||||
void VM_VmProfile_f( void );
|
||||
|
||||
|
||||
|
||||
#if 0 // 64bit!
|
||||
// converts a VM pointer to a C pointer and
|
||||
// checks to make sure that the range is acceptable
|
||||
void *VM_VM2C( vmptr_t p, int length ) {
|
||||
return (void *)p;
|
||||
}
|
||||
#endif
|
||||
|
||||
void VM_Debug( int level ) {
|
||||
vm_debugLevel = level;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
VM_Init
|
||||
==============
|
||||
*/
|
||||
void VM_Init( void ) {
|
||||
Cvar_Get( "vm_cgame", "0", CVAR_ARCHIVE );
|
||||
Cvar_Get( "vm_game", "0", CVAR_ARCHIVE );
|
||||
Cvar_Get( "vm_ui", "0", CVAR_ARCHIVE );
|
||||
|
||||
Cmd_AddCommand ("vmprofile", VM_VmProfile_f );
|
||||
Cmd_AddCommand ("vminfo", VM_VmInfo_f );
|
||||
|
||||
Com_Memset( vmTable, 0, sizeof( vmTable ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
VM_ValueToSymbol
|
||||
|
||||
Assumes a program counter value
|
||||
===============
|
||||
*/
|
||||
const char *VM_ValueToSymbol( vm_t *vm, int value ) {
|
||||
vmSymbol_t *sym;
|
||||
static char text[MAX_TOKEN_CHARS];
|
||||
|
||||
sym = vm->symbols;
|
||||
if ( !sym ) {
|
||||
return "NO SYMBOLS";
|
||||
}
|
||||
|
||||
// find the symbol
|
||||
while ( sym->next && sym->next->symValue <= value ) {
|
||||
sym = sym->next;
|
||||
}
|
||||
|
||||
if ( value == sym->symValue ) {
|
||||
return sym->symName;
|
||||
}
|
||||
|
||||
Com_sprintf( text, sizeof( text ), "%s+%i", sym->symName, value - sym->symValue );
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
VM_ValueToFunctionSymbol
|
||||
|
||||
For profiling, find the symbol behind this value
|
||||
===============
|
||||
*/
|
||||
vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value ) {
|
||||
vmSymbol_t *sym;
|
||||
static vmSymbol_t nullSym;
|
||||
|
||||
sym = vm->symbols;
|
||||
if ( !sym ) {
|
||||
return &nullSym;
|
||||
}
|
||||
|
||||
while ( sym->next && sym->next->symValue <= value ) {
|
||||
sym = sym->next;
|
||||
}
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
VM_SymbolToValue
|
||||
===============
|
||||
*/
|
||||
int VM_SymbolToValue( vm_t *vm, const char *symbol ) {
|
||||
vmSymbol_t *sym;
|
||||
|
||||
for ( sym = vm->symbols ; sym ; sym = sym->next ) {
|
||||
if ( !strcmp( symbol, sym->symName ) ) {
|
||||
return sym->symValue;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
VM_SymbolForCompiledPointer
|
||||
=====================
|
||||
*/
|
||||
#if 0 // 64bit!
|
||||
const char *VM_SymbolForCompiledPointer( vm_t *vm, void *code ) {
|
||||
int i;
|
||||
|
||||
if ( code < (void *)vm->codeBase ) {
|
||||
return "Before code block";
|
||||
}
|
||||
if ( code >= (void *)(vm->codeBase + vm->codeLength) ) {
|
||||
return "After code block";
|
||||
}
|
||||
|
||||
// find which original instruction it is after
|
||||
for ( i = 0 ; i < vm->codeLength ; i++ ) {
|
||||
if ( (void *)vm->instructionPointers[i] > code ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
i--;
|
||||
|
||||
// now look up the bytecode instruction pointer
|
||||
return VM_ValueToSymbol( vm, i );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
ParseHex
|
||||
===============
|
||||
*/
|
||||
int ParseHex( const char *text ) {
|
||||
int value;
|
||||
int c;
|
||||
|
||||
value = 0;
|
||||
while ( ( c = *text++ ) != 0 ) {
|
||||
if ( c >= '0' && c <= '9' ) {
|
||||
value = value * 16 + c - '0';
|
||||
continue;
|
||||
}
|
||||
if ( c >= 'a' && c <= 'f' ) {
|
||||
value = value * 16 + 10 + c - 'a';
|
||||
continue;
|
||||
}
|
||||
if ( c >= 'A' && c <= 'F' ) {
|
||||
value = value * 16 + 10 + c - 'A';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
VM_LoadSymbols
|
||||
===============
|
||||
*/
|
||||
void VM_LoadSymbols( vm_t *vm ) {
|
||||
int len;
|
||||
const char *token;
|
||||
char *mapfile, *text_p;
|
||||
char name[MAX_QPATH];
|
||||
char symbols[MAX_QPATH];
|
||||
vmSymbol_t **prev, *sym;
|
||||
int count;
|
||||
int value;
|
||||
int chars;
|
||||
int segment;
|
||||
int numInstructions;
|
||||
|
||||
// don't load symbols if not developer
|
||||
if ( !developer->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
COM_StripExtension(vm->name, name, sizeof(name));
|
||||
Com_sprintf( symbols, sizeof( symbols ), "vm/%s.map", name );
|
||||
len = FS_ReadFile( symbols, (void **)&mapfile );
|
||||
if ( !mapfile ) {
|
||||
Com_Printf( "Couldn't load symbol file: %s\n", symbols );
|
||||
return;
|
||||
}
|
||||
|
||||
numInstructions = vm->instructionPointersLength >> 2;
|
||||
|
||||
// parse the symbols
|
||||
text_p = mapfile;
|
||||
prev = &vm->symbols;
|
||||
count = 0;
|
||||
|
||||
while ( 1 ) {
|
||||
token = COM_Parse( &text_p );
|
||||
if ( !token[0] ) {
|
||||
break;
|
||||
}
|
||||
segment = ParseHex( token );
|
||||
if ( segment ) {
|
||||
COM_Parse( &text_p );
|
||||
COM_Parse( &text_p );
|
||||
continue; // only load code segment values
|
||||
}
|
||||
|
||||
token = COM_Parse( &text_p );
|
||||
if ( !token[0] ) {
|
||||
Com_Printf( "WARNING: incomplete line at end of file\n" );
|
||||
break;
|
||||
}
|
||||
value = ParseHex( token );
|
||||
|
||||
token = COM_Parse( &text_p );
|
||||
if ( !token[0] ) {
|
||||
Com_Printf( "WARNING: incomplete line at end of file\n" );
|
||||
break;
|
||||
}
|
||||
chars = strlen( token );
|
||||
sym = Hunk_Alloc( sizeof( *sym ) + chars, h_high );
|
||||
*prev = sym;
|
||||
prev = &sym->next;
|
||||
sym->next = NULL;
|
||||
|
||||
// convert value from an instruction number to a code offset
|
||||
if ( value >= 0 && value < numInstructions ) {
|
||||
value = vm->instructionPointers[value];
|
||||
}
|
||||
|
||||
sym->symValue = value;
|
||||
Q_strncpyz( sym->symName, token, chars + 1 );
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
vm->numSymbols = count;
|
||||
Com_Printf( "%i symbols parsed from %s\n", count, symbols );
|
||||
FS_FreeFile( mapfile );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
VM_DllSyscall
|
||||
|
||||
Dlls will call this directly
|
||||
|
||||
rcg010206 The horror; the horror.
|
||||
|
||||
The syscall mechanism relies on stack manipulation to get it's args.
|
||||
This is likely due to C's inability to pass "..." parameters to
|
||||
a function in one clean chunk. On PowerPC Linux, these parameters
|
||||
are not necessarily passed on the stack, so while (&arg[0] == arg)
|
||||
is true, (&arg[1] == 2nd function parameter) is not necessarily
|
||||
accurate, as arg's value might have been stored to the stack or
|
||||
other piece of scratch memory to give it a valid address, but the
|
||||
next parameter might still be sitting in a register.
|
||||
|
||||
Quake's syscall system also assumes that the stack grows downward,
|
||||
and that any needed types can be squeezed, safely, into a signed int.
|
||||
|
||||
This hack below copies all needed values for an argument to a
|
||||
array in memory, so that Quake can get the correct values. This can
|
||||
also be used on systems where the stack grows upwards, as the
|
||||
presumably standard and safe stdargs.h macros are used.
|
||||
|
||||
As for having enough space in a signed int for your datatypes, well,
|
||||
it might be better to wait for DOOM 3 before you start porting. :)
|
||||
|
||||
The original code, while probably still inherently dangerous, seems
|
||||
to work well enough for the platforms it already works on. Rather
|
||||
than add the performance hit for those platforms, the original code
|
||||
is still in use there.
|
||||
|
||||
For speed, we just grab 15 arguments, and don't worry about exactly
|
||||
how many the syscall actually needs; the extra is thrown away.
|
||||
|
||||
============
|
||||
*/
|
||||
intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) {
|
||||
#if !id386
|
||||
// rcg010206 - see commentary above
|
||||
intptr_t args[16];
|
||||
int i;
|
||||
va_list ap;
|
||||
|
||||
args[0] = arg;
|
||||
|
||||
va_start(ap, arg);
|
||||
for (i = 1; i < sizeof (args) / sizeof (args[i]); i++)
|
||||
args[i] = va_arg(ap, intptr_t);
|
||||
va_end(ap);
|
||||
|
||||
return currentVM->systemCall( args );
|
||||
#else // original id code
|
||||
return currentVM->systemCall( &arg );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
VM_LoadQVM
|
||||
|
||||
Load a .qvm file
|
||||
=================
|
||||
*/
|
||||
vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
|
||||
int length;
|
||||
int dataLength;
|
||||
int i;
|
||||
char filename[MAX_QPATH];
|
||||
vmHeader_t *header;
|
||||
|
||||
// load the image
|
||||
Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
|
||||
Com_Printf( "Loading vm file %s...\n", filename );
|
||||
length = FS_ReadFile( filename, (void **)&header );
|
||||
if ( !header ) {
|
||||
Com_Printf( "Failed.\n" );
|
||||
VM_Free( vm );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( LittleLong( header->vmMagic ) == VM_MAGIC_VER2 ) {
|
||||
Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
|
||||
|
||||
// byte swap the header
|
||||
for ( i = 0 ; i < sizeof( vmHeader_t ) / 4 ; i++ ) {
|
||||
((int *)header)[i] = LittleLong( ((int *)header)[i] );
|
||||
}
|
||||
|
||||
// validate
|
||||
if ( header->jtrgLength < 0
|
||||
|| header->bssLength < 0
|
||||
|| header->dataLength < 0
|
||||
|| header->litLength < 0
|
||||
|| header->codeLength <= 0 ) {
|
||||
VM_Free( vm );
|
||||
Com_Error( ERR_FATAL, "%s has bad header", filename );
|
||||
}
|
||||
} else if( LittleLong( header->vmMagic ) == VM_MAGIC ) {
|
||||
// byte swap the header
|
||||
// sizeof( vmHeader_t ) - sizeof( int ) is the 1.32b vm header size
|
||||
for ( i = 0 ; i < ( sizeof( vmHeader_t ) - sizeof( int ) ) / 4 ; i++ ) {
|
||||
((int *)header)[i] = LittleLong( ((int *)header)[i] );
|
||||
}
|
||||
|
||||
// validate
|
||||
if ( header->bssLength < 0
|
||||
|| header->dataLength < 0
|
||||
|| header->litLength < 0
|
||||
|| header->codeLength <= 0 ) {
|
||||
VM_Free( vm );
|
||||
Com_Error( ERR_FATAL, "%s has bad header", filename );
|
||||
}
|
||||
} else {
|
||||
VM_Free( vm );
|
||||
Com_Error( ERR_FATAL, "%s does not have a recognisable "
|
||||
"magic number in its header", filename );
|
||||
}
|
||||
|
||||
// round up to next power of 2 so all data operations can
|
||||
// be mask protected
|
||||
dataLength = header->dataLength + header->litLength + header->bssLength;
|
||||
for ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) {
|
||||
}
|
||||
dataLength = 1 << i;
|
||||
|
||||
if( alloc ) {
|
||||
// allocate zero filled space for initialized and uninitialized data
|
||||
vm->dataBase = Hunk_Alloc( dataLength, h_high );
|
||||
vm->dataMask = dataLength - 1;
|
||||
} else {
|
||||
// clear the data
|
||||
Com_Memset( vm->dataBase, 0, dataLength );
|
||||
}
|
||||
|
||||
// copy the intialized data
|
||||
Com_Memcpy( vm->dataBase, (byte *)header + header->dataOffset, header->dataLength + header->litLength );
|
||||
|
||||
// byte swap the longs
|
||||
for ( i = 0 ; i < header->dataLength ; i += 4 ) {
|
||||
*(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) );
|
||||
}
|
||||
|
||||
if( header->vmMagic == VM_MAGIC_VER2 ) {
|
||||
vm->numJumpTableTargets = header->jtrgLength >> 2;
|
||||
Com_Printf( "Loading %d jump table targets\n", vm->numJumpTableTargets );
|
||||
|
||||
if( alloc ) {
|
||||
vm->jumpTableTargets = Hunk_Alloc( header->jtrgLength, h_high );
|
||||
} else {
|
||||
Com_Memset( vm->jumpTableTargets, 0, header->jtrgLength );
|
||||
}
|
||||
|
||||
Com_Memcpy( vm->jumpTableTargets, (byte *)header + header->dataOffset +
|
||||
header->dataLength + header->litLength, header->jtrgLength );
|
||||
|
||||
// byte swap the longs
|
||||
for ( i = 0 ; i < header->jtrgLength ; i += 4 ) {
|
||||
*(int *)(vm->jumpTableTargets + i) = LittleLong( *(int *)(vm->jumpTableTargets + i ) );
|
||||
}
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
VM_Restart
|
||||
|
||||
Reload the data, but leave everything else in place
|
||||
This allows a server to do a map_restart without changing memory allocation
|
||||
=================
|
||||
*/
|
||||
vm_t *VM_Restart( vm_t *vm ) {
|
||||
vmHeader_t *header;
|
||||
|
||||
// DLL's can't be restarted in place
|
||||
if ( vm->dllHandle ) {
|
||||
char name[MAX_QPATH];
|
||||
intptr_t (*systemCall)( intptr_t *parms );
|
||||
|
||||
systemCall = vm->systemCall;
|
||||
Q_strncpyz( name, vm->name, sizeof( name ) );
|
||||
|
||||
VM_Free( vm );
|
||||
|
||||
vm = VM_Create( name, systemCall, VMI_NATIVE );
|
||||
return vm;
|
||||
}
|
||||
|
||||
// load the image
|
||||
Com_Printf( "VM_Restart()\n" );
|
||||
|
||||
if( !( header = VM_LoadQVM( vm, qfalse ) ) ) {
|
||||
Com_Error( ERR_DROP, "VM_Restart failed.\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// free the original file
|
||||
FS_FreeFile( header );
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
VM_Create
|
||||
|
||||
If image ends in .qvm it will be interpreted, otherwise
|
||||
it will attempt to load as a system dll
|
||||
================
|
||||
*/
|
||||
|
||||
#define STACK_SIZE 0x20000
|
||||
|
||||
vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
|
||||
vmInterpret_t interpret ) {
|
||||
vm_t *vm;
|
||||
vmHeader_t *header;
|
||||
int i, remaining;
|
||||
|
||||
if ( !module || !module[0] || !systemCalls ) {
|
||||
Com_Error( ERR_FATAL, "VM_Create: bad parms" );
|
||||
}
|
||||
|
||||
remaining = Hunk_MemoryRemaining();
|
||||
|
||||
// see if we already have the VM
|
||||
for ( i = 0 ; i < MAX_VM ; i++ ) {
|
||||
if (!Q_stricmp(vmTable[i].name, module)) {
|
||||
vm = &vmTable[i];
|
||||
return vm;
|
||||
}
|
||||
}
|
||||
|
||||
// find a free vm
|
||||
for ( i = 0 ; i < MAX_VM ; i++ ) {
|
||||
if ( !vmTable[i].name[0] ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( i == MAX_VM ) {
|
||||
Com_Error( ERR_FATAL, "VM_Create: no free vm_t" );
|
||||
}
|
||||
|
||||
vm = &vmTable[i];
|
||||
|
||||
Q_strncpyz( vm->name, module, sizeof( vm->name ) );
|
||||
vm->systemCall = systemCalls;
|
||||
|
||||
if ( interpret == VMI_NATIVE ) {
|
||||
// try to load as a system dll
|
||||
Com_Printf( "Loading dll file %s.\n", vm->name );
|
||||
vm->dllHandle = Sys_LoadDll( module, vm->fqpath , &vm->entryPoint, VM_DllSyscall );
|
||||
if ( vm->dllHandle ) {
|
||||
return vm;
|
||||
}
|
||||
|
||||
Com_Printf( "Failed to load dll, looking for qvm.\n" );
|
||||
interpret = VMI_COMPILED;
|
||||
}
|
||||
|
||||
// load the image
|
||||
if( !( header = VM_LoadQVM( vm, qtrue ) ) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// allocate space for the jump targets, which will be filled in by the compile/prep functions
|
||||
vm->instructionPointersLength = header->instructionCount * 4;
|
||||
vm->instructionPointers = Hunk_Alloc( vm->instructionPointersLength, h_high );
|
||||
|
||||
// copy or compile the instructions
|
||||
vm->codeLength = header->codeLength;
|
||||
|
||||
vm->compiled = qfalse;
|
||||
|
||||
#ifdef NO_VM_COMPILED
|
||||
if(interpret >= VMI_COMPILED) {
|
||||
Com_Printf("Architecture doesn't have a bytecode compiler, using interpreter\n");
|
||||
interpret = VMI_BYTECODE;
|
||||
}
|
||||
#else
|
||||
if ( interpret >= VMI_COMPILED ) {
|
||||
vm->compiled = qtrue;
|
||||
VM_Compile( vm, header );
|
||||
}
|
||||
#endif
|
||||
// VM_Compile may have reset vm->compiled if compilation failed
|
||||
if (!vm->compiled)
|
||||
{
|
||||
VM_PrepareInterpreter( vm, header );
|
||||
}
|
||||
|
||||
// free the original file
|
||||
FS_FreeFile( header );
|
||||
|
||||
// load the map file
|
||||
VM_LoadSymbols( vm );
|
||||
|
||||
// the stack is implicitly at the end of the image
|
||||
vm->programStack = vm->dataMask + 1;
|
||||
vm->stackBottom = vm->programStack - STACK_SIZE;
|
||||
|
||||
Com_Printf("%s loaded in %d bytes on the hunk\n", module, remaining - Hunk_MemoryRemaining());
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
VM_Free
|
||||
==============
|
||||
*/
|
||||
void VM_Free( vm_t *vm ) {
|
||||
|
||||
if(vm->destroy)
|
||||
vm->destroy(vm);
|
||||
|
||||
if ( vm->dllHandle ) {
|
||||
Sys_UnloadDll( vm->dllHandle );
|
||||
Com_Memset( vm, 0, sizeof( *vm ) );
|
||||
}
|
||||
#if 0 // now automatically freed by hunk
|
||||
if ( vm->codeBase ) {
|
||||
Z_Free( vm->codeBase );
|
||||
}
|
||||
if ( vm->dataBase ) {
|
||||
Z_Free( vm->dataBase );
|
||||
}
|
||||
if ( vm->instructionPointers ) {
|
||||
Z_Free( vm->instructionPointers );
|
||||
}
|
||||
#endif
|
||||
Com_Memset( vm, 0, sizeof( *vm ) );
|
||||
|
||||
currentVM = NULL;
|
||||
lastVM = NULL;
|
||||
}
|
||||
|
||||
void VM_Clear(void) {
|
||||
int i;
|
||||
for (i=0;i<MAX_VM; i++) {
|
||||
if ( vmTable[i].dllHandle ) {
|
||||
Sys_UnloadDll( vmTable[i].dllHandle );
|
||||
}
|
||||
Com_Memset( &vmTable[i], 0, sizeof( vm_t ) );
|
||||
}
|
||||
currentVM = NULL;
|
||||
lastVM = NULL;
|
||||
}
|
||||
|
||||
void *VM_ArgPtr( intptr_t intValue ) {
|
||||
if ( !intValue ) {
|
||||
return NULL;
|
||||
}
|
||||
// currentVM is missing on reconnect
|
||||
if ( currentVM==NULL )
|
||||
return NULL;
|
||||
|
||||
if ( currentVM->entryPoint ) {
|
||||
return (void *)(currentVM->dataBase + intValue);
|
||||
}
|
||||
else {
|
||||
return (void *)(currentVM->dataBase + (intValue & currentVM->dataMask));
|
||||
}
|
||||
}
|
||||
|
||||
void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue ) {
|
||||
if ( !intValue ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// currentVM is missing on reconnect here as well?
|
||||
if ( currentVM==NULL )
|
||||
return NULL;
|
||||
|
||||
//
|
||||
if ( vm->entryPoint ) {
|
||||
return (void *)(vm->dataBase + intValue);
|
||||
}
|
||||
else {
|
||||
return (void *)(vm->dataBase + (intValue & vm->dataMask));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
VM_Call
|
||||
|
||||
|
||||
Upon a system call, the stack will look like:
|
||||
|
||||
sp+32 parm1
|
||||
sp+28 parm0
|
||||
sp+24 return value
|
||||
sp+20 return address
|
||||
sp+16 local1
|
||||
sp+14 local0
|
||||
sp+12 arg1
|
||||
sp+8 arg0
|
||||
sp+4 return stack
|
||||
sp return address
|
||||
|
||||
An interpreted function will immediately execute
|
||||
an OP_ENTER instruction, which will subtract space for
|
||||
locals from sp
|
||||
==============
|
||||
*/
|
||||
#define MAX_STACK 256
|
||||
#define STACK_MASK (MAX_STACK-1)
|
||||
|
||||
intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... ) {
|
||||
vm_t *oldVM;
|
||||
intptr_t r;
|
||||
int i;
|
||||
|
||||
if ( !vm ) {
|
||||
Com_Error( ERR_FATAL, "VM_Call with NULL vm" );
|
||||
}
|
||||
|
||||
oldVM = currentVM;
|
||||
currentVM = vm;
|
||||
lastVM = vm;
|
||||
|
||||
if ( vm_debugLevel ) {
|
||||
Com_Printf( "VM_Call( %d )\n", callnum );
|
||||
}
|
||||
|
||||
// if we have a dll loaded, call it directly
|
||||
if ( vm->entryPoint ) {
|
||||
//rcg010207 - see dissertation at top of VM_DllSyscall() in this file.
|
||||
int args[10];
|
||||
va_list ap;
|
||||
va_start(ap, callnum);
|
||||
for (i = 0; i < sizeof (args) / sizeof (args[i]); i++) {
|
||||
args[i] = va_arg(ap, int);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
r = vm->entryPoint( callnum, args[0], args[1], args[2], args[3],
|
||||
args[4], args[5], args[6], args[7],
|
||||
args[8], args[9]);
|
||||
} else {
|
||||
#if id386 // i386 calling convention doesn't need conversion
|
||||
#ifndef NO_VM_COMPILED
|
||||
if ( vm->compiled )
|
||||
r = VM_CallCompiled( vm, (int*)&callnum );
|
||||
else
|
||||
#endif
|
||||
r = VM_CallInterpreted( vm, (int*)&callnum );
|
||||
#else
|
||||
struct {
|
||||
int callnum;
|
||||
int args[10];
|
||||
} a;
|
||||
va_list ap;
|
||||
|
||||
a.callnum = callnum;
|
||||
va_start(ap, callnum);
|
||||
for (i = 0; i < sizeof (a.args) / sizeof (a.args[0]); i++) {
|
||||
a.args[i] = va_arg(ap, int);
|
||||
}
|
||||
va_end(ap);
|
||||
#ifndef NO_VM_COMPILED
|
||||
if ( vm->compiled )
|
||||
r = VM_CallCompiled( vm, &a.callnum );
|
||||
else
|
||||
#endif
|
||||
r = VM_CallInterpreted( vm, &a.callnum );
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( oldVM != NULL )
|
||||
currentVM = oldVM;
|
||||
return r;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
|
||||
static int QDECL VM_ProfileSort( const void *a, const void *b ) {
|
||||
vmSymbol_t *sa, *sb;
|
||||
|
||||
sa = *(vmSymbol_t **)a;
|
||||
sb = *(vmSymbol_t **)b;
|
||||
|
||||
if ( sa->profileCount < sb->profileCount ) {
|
||||
return -1;
|
||||
}
|
||||
if ( sa->profileCount > sb->profileCount ) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
VM_VmProfile_f
|
||||
|
||||
==============
|
||||
*/
|
||||
void VM_VmProfile_f( void ) {
|
||||
vm_t *vm;
|
||||
vmSymbol_t **sorted, *sym;
|
||||
int i;
|
||||
double total;
|
||||
|
||||
if ( !lastVM ) {
|
||||
return;
|
||||
}
|
||||
|
||||
vm = lastVM;
|
||||
|
||||
if ( !vm->numSymbols ) {
|
||||
return;
|
||||
}
|
||||
|
||||
sorted = Z_Malloc( vm->numSymbols * sizeof( *sorted ) );
|
||||
sorted[0] = vm->symbols;
|
||||
total = sorted[0]->profileCount;
|
||||
for ( i = 1 ; i < vm->numSymbols ; i++ ) {
|
||||
sorted[i] = sorted[i-1]->next;
|
||||
total += sorted[i]->profileCount;
|
||||
}
|
||||
|
||||
qsort( sorted, vm->numSymbols, sizeof( *sorted ), VM_ProfileSort );
|
||||
|
||||
for ( i = 0 ; i < vm->numSymbols ; i++ ) {
|
||||
int perc;
|
||||
|
||||
sym = sorted[i];
|
||||
|
||||
perc = 100 * (float) sym->profileCount / total;
|
||||
Com_Printf( "%2i%% %9i %s\n", perc, sym->profileCount, sym->symName );
|
||||
sym->profileCount = 0;
|
||||
}
|
||||
|
||||
Com_Printf(" %9.0f total\n", total );
|
||||
|
||||
Z_Free( sorted );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
VM_VmInfo_f
|
||||
|
||||
==============
|
||||
*/
|
||||
void VM_VmInfo_f( void ) {
|
||||
vm_t *vm;
|
||||
int i;
|
||||
|
||||
Com_Printf( "Registered virtual machines:\n" );
|
||||
for ( i = 0 ; i < MAX_VM ; i++ ) {
|
||||
vm = &vmTable[i];
|
||||
if ( !vm->name[0] ) {
|
||||
break;
|
||||
}
|
||||
Com_Printf( "%s : ", vm->name );
|
||||
if ( vm->dllHandle ) {
|
||||
Com_Printf( "native\n" );
|
||||
continue;
|
||||
}
|
||||
if ( vm->compiled ) {
|
||||
Com_Printf( "compiled on load\n" );
|
||||
} else {
|
||||
Com_Printf( "interpreted\n" );
|
||||
}
|
||||
Com_Printf( " code length : %7i\n", vm->codeLength );
|
||||
Com_Printf( " table length: %7i\n", vm->instructionPointersLength );
|
||||
Com_Printf( " data length : %7i\n", vm->dataMask + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
VM_LogSyscalls
|
||||
|
||||
Insert calls to this while debugging the vm compiler
|
||||
===============
|
||||
*/
|
||||
void VM_LogSyscalls( int *args ) {
|
||||
static int callnum;
|
||||
static FILE *f;
|
||||
|
||||
if ( !f ) {
|
||||
f = fopen("syscalls.log", "w" );
|
||||
}
|
||||
callnum++;
|
||||
fprintf(f, "%i: %p (%i) = %i %i %i %i\n", callnum, (void*)(args - (int *)currentVM->dataBase),
|
||||
args[0], args[1], args[2], args[3], args[4] );
|
||||
}
|
|
@ -1,921 +0,0 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
#include "vm_local.h"
|
||||
|
||||
//#define DEBUG_VM
|
||||
#ifdef DEBUG_VM
|
||||
static char *opnames[256] = {
|
||||
"OP_UNDEF",
|
||||
|
||||
"OP_IGNORE",
|
||||
|
||||
"OP_BREAK",
|
||||
|
||||
"OP_ENTER",
|
||||
"OP_LEAVE",
|
||||
"OP_CALL",
|
||||
"OP_PUSH",
|
||||
"OP_POP",
|
||||
|
||||
"OP_CONST",
|
||||
|
||||
"OP_LOCAL",
|
||||
|
||||
"OP_JUMP",
|
||||
|
||||
//-------------------
|
||||
|
||||
"OP_EQ",
|
||||
"OP_NE",
|
||||
|
||||
"OP_LTI",
|
||||
"OP_LEI",
|
||||
"OP_GTI",
|
||||
"OP_GEI",
|
||||
|
||||
"OP_LTU",
|
||||
"OP_LEU",
|
||||
"OP_GTU",
|
||||
"OP_GEU",
|
||||
|
||||
"OP_EQF",
|
||||
"OP_NEF",
|
||||
|
||||
"OP_LTF",
|
||||
"OP_LEF",
|
||||
"OP_GTF",
|
||||
"OP_GEF",
|
||||
|
||||
//-------------------
|
||||
|
||||
"OP_LOAD1",
|
||||
"OP_LOAD2",
|
||||
"OP_LOAD4",
|
||||
"OP_STORE1",
|
||||
"OP_STORE2",
|
||||
"OP_STORE4",
|
||||
"OP_ARG",
|
||||
|
||||
"OP_BLOCK_COPY",
|
||||
|
||||
//-------------------
|
||||
|
||||
"OP_SEX8",
|
||||
"OP_SEX16",
|
||||
|
||||
"OP_NEGI",
|
||||
"OP_ADD",
|
||||
"OP_SUB",
|
||||
"OP_DIVI",
|
||||
"OP_DIVU",
|
||||
"OP_MODI",
|
||||
"OP_MODU",
|
||||
"OP_MULI",
|
||||
"OP_MULU",
|
||||
|
||||
"OP_BAND",
|
||||
"OP_BOR",
|
||||
"OP_BXOR",
|
||||
"OP_BCOM",
|
||||
|
||||
"OP_LSH",
|
||||
"OP_RSHI",
|
||||
"OP_RSHU",
|
||||
|
||||
"OP_NEGF",
|
||||
"OP_ADDF",
|
||||
"OP_SUBF",
|
||||
"OP_DIVF",
|
||||
"OP_MULF",
|
||||
|
||||
"OP_CVIF",
|
||||
"OP_CVFI"
|
||||
};
|
||||
#endif
|
||||
|
||||
#if idppc
|
||||
|
||||
//FIXME: these, um... look the same to me
|
||||
#if defined(__GNUC__)
|
||||
static ID_INLINE unsigned int loadWord(void *addr) {
|
||||
unsigned int word;
|
||||
|
||||
asm("lwbrx %0,0,%1" : "=r" (word) : "r" (addr));
|
||||
return word;
|
||||
}
|
||||
#else
|
||||
static ID_INLINE unsigned int __lwbrx(register void *addr,
|
||||
register int offset) {
|
||||
register unsigned int word;
|
||||
|
||||
asm("lwbrx %0,%2,%1" : "=r" (word) : "r" (addr), "b" (offset));
|
||||
return word;
|
||||
}
|
||||
#define loadWord(addr) __lwbrx(addr,0)
|
||||
#endif
|
||||
|
||||
#else
|
||||
static ID_INLINE int loadWord(void *addr) {
|
||||
int word;
|
||||
memcpy(&word, addr, 4);
|
||||
return LittleLong(word);
|
||||
}
|
||||
#endif
|
||||
|
||||
char *VM_Indent( vm_t *vm ) {
|
||||
static char *string = " ";
|
||||
if ( vm->callLevel > 20 ) {
|
||||
return string;
|
||||
}
|
||||
return string + 2 * ( 20 - vm->callLevel );
|
||||
}
|
||||
|
||||
void VM_StackTrace( vm_t *vm, int programCounter, int programStack ) {
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
do {
|
||||
Com_Printf( "%s\n", VM_ValueToSymbol( vm, programCounter ) );
|
||||
programStack = *(int *)&vm->dataBase[programStack+4];
|
||||
programCounter = *(int *)&vm->dataBase[programStack];
|
||||
} while ( programCounter != -1 && ++count < 32 );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
VM_PrepareInterpreter
|
||||
====================
|
||||
*/
|
||||
void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ) {
|
||||
int op;
|
||||
int pc;
|
||||
byte *code;
|
||||
int instruction;
|
||||
int *codeBase;
|
||||
|
||||
vm->codeBase = Hunk_Alloc( vm->codeLength*4, h_high ); // we're now int aligned
|
||||
// memcpy( vm->codeBase, (byte *)header + header->codeOffset, vm->codeLength );
|
||||
|
||||
// we don't need to translate the instructions, but we still need
|
||||
// to find each instructions starting point for jumps
|
||||
pc = 0;
|
||||
instruction = 0;
|
||||
code = (byte *)header + header->codeOffset;
|
||||
codeBase = (int *)vm->codeBase;
|
||||
|
||||
while ( instruction < header->instructionCount ) {
|
||||
vm->instructionPointers[ instruction ] = pc;
|
||||
instruction++;
|
||||
|
||||
op = code[ pc ];
|
||||
codeBase[pc] = op;
|
||||
if ( pc > header->codeLength ) {
|
||||
Com_Error( ERR_FATAL, "VM_PrepareInterpreter: pc > header->codeLength" );
|
||||
}
|
||||
|
||||
pc++;
|
||||
|
||||
// these are the only opcodes that aren't a single byte
|
||||
switch ( op ) {
|
||||
case OP_ENTER:
|
||||
case OP_CONST:
|
||||
case OP_LOCAL:
|
||||
case OP_LEAVE:
|
||||
case OP_EQ:
|
||||
case OP_NE:
|
||||
case OP_LTI:
|
||||
case OP_LEI:
|
||||
case OP_GTI:
|
||||
case OP_GEI:
|
||||
case OP_LTU:
|
||||
case OP_LEU:
|
||||
case OP_GTU:
|
||||
case OP_GEU:
|
||||
case OP_EQF:
|
||||
case OP_NEF:
|
||||
case OP_LTF:
|
||||
case OP_LEF:
|
||||
case OP_GTF:
|
||||
case OP_GEF:
|
||||
case OP_BLOCK_COPY:
|
||||
codeBase[pc+0] = loadWord(&code[pc]);
|
||||
pc += 4;
|
||||
break;
|
||||
case OP_ARG:
|
||||
codeBase[pc+0] = code[pc];
|
||||
pc += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
pc = 0;
|
||||
instruction = 0;
|
||||
code = (byte *)header + header->codeOffset;
|
||||
codeBase = (int *)vm->codeBase;
|
||||
|
||||
while ( instruction < header->instructionCount ) {
|
||||
op = code[ pc ];
|
||||
instruction++;
|
||||
pc++;
|
||||
switch ( op ) {
|
||||
case OP_ENTER:
|
||||
case OP_CONST:
|
||||
case OP_LOCAL:
|
||||
case OP_LEAVE:
|
||||
case OP_EQ:
|
||||
case OP_NE:
|
||||
case OP_LTI:
|
||||
case OP_LEI:
|
||||
case OP_GTI:
|
||||
case OP_GEI:
|
||||
case OP_LTU:
|
||||
case OP_LEU:
|
||||
case OP_GTU:
|
||||
case OP_GEU:
|
||||
case OP_EQF:
|
||||
case OP_NEF:
|
||||
case OP_LTF:
|
||||
case OP_LEF:
|
||||
case OP_GTF:
|
||||
case OP_GEF:
|
||||
case OP_BLOCK_COPY:
|
||||
switch(op) {
|
||||
case OP_EQ:
|
||||
case OP_NE:
|
||||
case OP_LTI:
|
||||
case OP_LEI:
|
||||
case OP_GTI:
|
||||
case OP_GEI:
|
||||
case OP_LTU:
|
||||
case OP_LEU:
|
||||
case OP_GTU:
|
||||
case OP_GEU:
|
||||
case OP_EQF:
|
||||
case OP_NEF:
|
||||
case OP_LTF:
|
||||
case OP_LEF:
|
||||
case OP_GTF:
|
||||
case OP_GEF:
|
||||
codeBase[pc] = vm->instructionPointers[codeBase[pc]];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pc += 4;
|
||||
break;
|
||||
case OP_ARG:
|
||||
pc += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
VM_Call
|
||||
|
||||
|
||||
Upon a system call, the stack will look like:
|
||||
|
||||
sp+32 parm1
|
||||
sp+28 parm0
|
||||
sp+24 return stack
|
||||
sp+20 return address
|
||||
sp+16 local1
|
||||
sp+14 local0
|
||||
sp+12 arg1
|
||||
sp+8 arg0
|
||||
sp+4 return stack
|
||||
sp return address
|
||||
|
||||
An interpreted function will immediately execute
|
||||
an OP_ENTER instruction, which will subtract space for
|
||||
locals from sp
|
||||
==============
|
||||
*/
|
||||
#define MAX_STACK 256
|
||||
#define STACK_MASK (MAX_STACK-1)
|
||||
|
||||
#define DEBUGSTR va("%s%i", VM_Indent(vm), opStack-stack )
|
||||
|
||||
int VM_CallInterpreted( vm_t *vm, int *args ) {
|
||||
int stack[MAX_STACK];
|
||||
int *opStack;
|
||||
int programCounter;
|
||||
int programStack;
|
||||
int stackOnEntry;
|
||||
byte *image;
|
||||
int *codeImage;
|
||||
int v1;
|
||||
int dataMask;
|
||||
#ifdef DEBUG_VM
|
||||
vmSymbol_t *profileSymbol;
|
||||
#endif
|
||||
|
||||
// interpret the code
|
||||
vm->currentlyInterpreting = qtrue;
|
||||
|
||||
// we might be called recursively, so this might not be the very top
|
||||
programStack = stackOnEntry = vm->programStack;
|
||||
|
||||
#ifdef DEBUG_VM
|
||||
profileSymbol = VM_ValueToFunctionSymbol( vm, 0 );
|
||||
// uncomment this for debugging breakpoints
|
||||
vm->breakFunction = 0;
|
||||
#endif
|
||||
// set up the stack frame
|
||||
|
||||
image = vm->dataBase;
|
||||
codeImage = (int *)vm->codeBase;
|
||||
dataMask = vm->dataMask;
|
||||
|
||||
// leave a free spot at start of stack so
|
||||
// that as long as opStack is valid, opStack-1 will
|
||||
// not corrupt anything
|
||||
opStack = stack;
|
||||
programCounter = 0;
|
||||
|
||||
programStack -= 48;
|
||||
|
||||
*(int *)&image[ programStack + 44] = args[9];
|
||||
*(int *)&image[ programStack + 40] = args[8];
|
||||
*(int *)&image[ programStack + 36] = args[7];
|
||||
*(int *)&image[ programStack + 32] = args[6];
|
||||
*(int *)&image[ programStack + 28] = args[5];
|
||||
*(int *)&image[ programStack + 24] = args[4];
|
||||
*(int *)&image[ programStack + 20] = args[3];
|
||||
*(int *)&image[ programStack + 16] = args[2];
|
||||
*(int *)&image[ programStack + 12] = args[1];
|
||||
*(int *)&image[ programStack + 8 ] = args[0];
|
||||
*(int *)&image[ programStack + 4 ] = 0; // return stack
|
||||
*(int *)&image[ programStack ] = -1; // will terminate the loop on return
|
||||
|
||||
vm->callLevel = 0;
|
||||
|
||||
VM_Debug(0);
|
||||
|
||||
// vm_debugLevel=2;
|
||||
// main interpreter loop, will exit when a LEAVE instruction
|
||||
// grabs the -1 program counter
|
||||
|
||||
#define r2 codeImage[programCounter]
|
||||
|
||||
while ( 1 ) {
|
||||
int opcode, r0, r1;
|
||||
// unsigned int r2;
|
||||
|
||||
nextInstruction:
|
||||
r0 = ((int *)opStack)[0];
|
||||
r1 = ((int *)opStack)[-1];
|
||||
nextInstruction2:
|
||||
#ifdef DEBUG_VM
|
||||
if ( (unsigned)programCounter >= vm->codeLength ) {
|
||||
Com_Error( ERR_DROP, "VM pc out of range" );
|
||||
}
|
||||
|
||||
if ( opStack < stack ) {
|
||||
Com_Error( ERR_DROP, "VM opStack underflow" );
|
||||
}
|
||||
if ( opStack >= stack+MAX_STACK ) {
|
||||
Com_Error( ERR_DROP, "VM opStack overflow" );
|
||||
}
|
||||
|
||||
if ( programStack <= vm->stackBottom ) {
|
||||
Com_Error( ERR_DROP, "VM stack overflow" );
|
||||
}
|
||||
|
||||
if ( programStack & 3 ) {
|
||||
Com_Error( ERR_DROP, "VM program stack misaligned" );
|
||||
}
|
||||
|
||||
if ( vm_debugLevel > 1 ) {
|
||||
Com_Printf( "%s %s\n", DEBUGSTR, opnames[opcode] );
|
||||
}
|
||||
profileSymbol->profileCount++;
|
||||
#endif
|
||||
opcode = codeImage[ programCounter++ ];
|
||||
|
||||
switch ( opcode ) {
|
||||
#ifdef DEBUG_VM
|
||||
default:
|
||||
Com_Error( ERR_DROP, "Bad VM instruction" ); // this should be scanned on load!
|
||||
#endif
|
||||
case OP_BREAK:
|
||||
vm->breakCount++;
|
||||
goto nextInstruction2;
|
||||
case OP_CONST:
|
||||
opStack++;
|
||||
r1 = r0;
|
||||
r0 = *opStack = r2;
|
||||
|
||||
programCounter += 4;
|
||||
goto nextInstruction2;
|
||||
case OP_LOCAL:
|
||||
opStack++;
|
||||
r1 = r0;
|
||||
r0 = *opStack = r2+programStack;
|
||||
|
||||
programCounter += 4;
|
||||
goto nextInstruction2;
|
||||
|
||||
case OP_LOAD4:
|
||||
#ifdef DEBUG_VM
|
||||
if ( *opStack & 3 ) {
|
||||
Com_Error( ERR_DROP, "OP_LOAD4 misaligned" );
|
||||
}
|
||||
#endif
|
||||
r0 = *opStack = *(int *)&image[ r0&dataMask ];
|
||||
goto nextInstruction2;
|
||||
case OP_LOAD2:
|
||||
r0 = *opStack = *(unsigned short *)&image[ r0&dataMask ];
|
||||
goto nextInstruction2;
|
||||
case OP_LOAD1:
|
||||
r0 = *opStack = image[ r0&dataMask ];
|
||||
goto nextInstruction2;
|
||||
|
||||
case OP_STORE4:
|
||||
*(int *)&image[ r1&(dataMask & ~3) ] = r0;
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
case OP_STORE2:
|
||||
*(short *)&image[ r1&(dataMask & ~1) ] = r0;
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
case OP_STORE1:
|
||||
image[ r1&dataMask ] = r0;
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
|
||||
case OP_ARG:
|
||||
// single byte offset from programStack
|
||||
*(int *)&image[ codeImage[programCounter] + programStack ] = r0;
|
||||
opStack--;
|
||||
programCounter += 1;
|
||||
goto nextInstruction;
|
||||
|
||||
case OP_BLOCK_COPY:
|
||||
{
|
||||
int *src, *dest;
|
||||
int i, count, srci, desti;
|
||||
|
||||
count = r2;
|
||||
// MrE: copy range check
|
||||
srci = r0 & dataMask;
|
||||
desti = r1 & dataMask;
|
||||
count = ((srci + count) & dataMask) - srci;
|
||||
count = ((desti + count) & dataMask) - desti;
|
||||
|
||||
src = (int *)&image[ r0&dataMask ];
|
||||
dest = (int *)&image[ r1&dataMask ];
|
||||
if ( ( (intptr_t)src | (intptr_t)dest | count ) & 3 ) {
|
||||
// happens in westernq3
|
||||
Com_Printf( S_COLOR_YELLOW "Warning: OP_BLOCK_COPY not dword aligned\n");
|
||||
}
|
||||
count >>= 2;
|
||||
for ( i = count-1 ; i>= 0 ; i-- ) {
|
||||
dest[i] = src[i];
|
||||
}
|
||||
programCounter += 4;
|
||||
opStack -= 2;
|
||||
}
|
||||
goto nextInstruction;
|
||||
|
||||
case OP_CALL:
|
||||
// save current program counter
|
||||
*(int *)&image[ programStack ] = programCounter;
|
||||
|
||||
// jump to the location on the stack
|
||||
programCounter = r0;
|
||||
opStack--;
|
||||
if ( programCounter < 0 ) {
|
||||
// system call
|
||||
int r;
|
||||
int temp;
|
||||
#ifdef DEBUG_VM
|
||||
int stomped;
|
||||
|
||||
if ( vm_debugLevel ) {
|
||||
Com_Printf( "%s---> systemcall(%i)\n", DEBUGSTR, -1 - programCounter );
|
||||
}
|
||||
#endif
|
||||
// save the stack to allow recursive VM entry
|
||||
temp = vm->callLevel;
|
||||
vm->programStack = programStack - 4;
|
||||
#ifdef DEBUG_VM
|
||||
stomped = *(int *)&image[ programStack + 4 ];
|
||||
#endif
|
||||
*(int *)&image[ programStack + 4 ] = -1 - programCounter;
|
||||
|
||||
//VM_LogSyscalls( (int *)&image[ programStack + 4 ] );
|
||||
{
|
||||
intptr_t* argptr = (intptr_t *)&image[ programStack + 4 ];
|
||||
#if __WORDSIZE == 64
|
||||
// the vm has ints on the stack, we expect
|
||||
// longs so we have to convert it
|
||||
intptr_t argarr[16];
|
||||
int i;
|
||||
for (i = 0; i < 16; ++i) {
|
||||
argarr[i] = *(int*)&image[ programStack + 4 + 4*i ];
|
||||
}
|
||||
argptr = argarr;
|
||||
#endif
|
||||
r = vm->systemCall( argptr );
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VM
|
||||
// this is just our stack frame pointer, only needed
|
||||
// for debugging
|
||||
*(int *)&image[ programStack + 4 ] = stomped;
|
||||
#endif
|
||||
|
||||
// save return value
|
||||
opStack++;
|
||||
*opStack = r;
|
||||
programCounter = *(int *)&image[ programStack ];
|
||||
vm->callLevel = temp;
|
||||
#ifdef DEBUG_VM
|
||||
if ( vm_debugLevel ) {
|
||||
Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );
|
||||
}
|
||||
#endif
|
||||
} else if ( (unsigned)programCounter >= vm->codeLength ) {
|
||||
Com_Error( ERR_DROP, "VM program counter out of range in OP_CALL" );
|
||||
} else {
|
||||
programCounter = vm->instructionPointers[ programCounter ];
|
||||
}
|
||||
goto nextInstruction;
|
||||
|
||||
// push and pop are only needed for discarded or bad function return values
|
||||
case OP_PUSH:
|
||||
opStack++;
|
||||
goto nextInstruction;
|
||||
case OP_POP:
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
|
||||
case OP_ENTER:
|
||||
#ifdef DEBUG_VM
|
||||
profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );
|
||||
#endif
|
||||
// get size of stack frame
|
||||
v1 = r2;
|
||||
|
||||
programCounter += 4;
|
||||
programStack -= v1;
|
||||
#ifdef DEBUG_VM
|
||||
// save old stack frame for debugging traces
|
||||
*(int *)&image[programStack+4] = programStack + v1;
|
||||
if ( vm_debugLevel ) {
|
||||
Com_Printf( "%s---> %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter - 5 ) );
|
||||
if ( vm->breakFunction && programCounter - 5 == vm->breakFunction ) {
|
||||
// this is to allow setting breakpoints here in the debugger
|
||||
vm->breakCount++;
|
||||
// vm_debugLevel = 2;
|
||||
// VM_StackTrace( vm, programCounter, programStack );
|
||||
}
|
||||
vm->callLevel++;
|
||||
}
|
||||
#endif
|
||||
goto nextInstruction;
|
||||
case OP_LEAVE:
|
||||
// remove our stack frame
|
||||
v1 = r2;
|
||||
|
||||
programStack += v1;
|
||||
|
||||
// grab the saved program counter
|
||||
programCounter = *(int *)&image[ programStack ];
|
||||
#ifdef DEBUG_VM
|
||||
profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter );
|
||||
if ( vm_debugLevel ) {
|
||||
vm->callLevel--;
|
||||
Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) );
|
||||
}
|
||||
#endif
|
||||
// check for leaving the VM
|
||||
if ( programCounter == -1 ) {
|
||||
goto done;
|
||||
} else if ( (unsigned)programCounter >= vm->codeLength ) {
|
||||
Com_Error( ERR_DROP, "VM program counter out of range in OP_LEAVE" );
|
||||
}
|
||||
goto nextInstruction;
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
BRANCHES
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
case OP_JUMP:
|
||||
programCounter = r0;
|
||||
programCounter = vm->instructionPointers[ programCounter ];
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
|
||||
case OP_EQ:
|
||||
opStack -= 2;
|
||||
if ( r1 == r0 ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_NE:
|
||||
opStack -= 2;
|
||||
if ( r1 != r0 ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_LTI:
|
||||
opStack -= 2;
|
||||
if ( r1 < r0 ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_LEI:
|
||||
opStack -= 2;
|
||||
if ( r1 <= r0 ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_GTI:
|
||||
opStack -= 2;
|
||||
if ( r1 > r0 ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_GEI:
|
||||
opStack -= 2;
|
||||
if ( r1 >= r0 ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_LTU:
|
||||
opStack -= 2;
|
||||
if ( ((unsigned)r1) < ((unsigned)r0) ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_LEU:
|
||||
opStack -= 2;
|
||||
if ( ((unsigned)r1) <= ((unsigned)r0) ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_GTU:
|
||||
opStack -= 2;
|
||||
if ( ((unsigned)r1) > ((unsigned)r0) ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_GEU:
|
||||
opStack -= 2;
|
||||
if ( ((unsigned)r1) >= ((unsigned)r0) ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_EQF:
|
||||
if ( ((float *)opStack)[-1] == *(float *)opStack ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_NEF:
|
||||
if ( ((float *)opStack)[-1] != *(float *)opStack ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_LTF:
|
||||
if ( ((float *)opStack)[-1] < *(float *)opStack ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_LEF:
|
||||
if ( ((float *)opStack)[-1] <= *(float *)opStack ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_GTF:
|
||||
if ( ((float *)opStack)[-1] > *(float *)opStack ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
case OP_GEF:
|
||||
if ( ((float *)opStack)[-1] >= *(float *)opStack ) {
|
||||
programCounter = r2; //vm->instructionPointers[r2];
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
} else {
|
||||
programCounter += 4;
|
||||
opStack -= 2;
|
||||
goto nextInstruction;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
|
||||
case OP_NEGI:
|
||||
*opStack = -r0;
|
||||
goto nextInstruction;
|
||||
case OP_ADD:
|
||||
opStack[-1] = r1 + r0;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_SUB:
|
||||
opStack[-1] = r1 - r0;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_DIVI:
|
||||
opStack[-1] = r1 / r0;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_DIVU:
|
||||
opStack[-1] = ((unsigned)r1) / ((unsigned)r0);
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_MODI:
|
||||
opStack[-1] = r1 % r0;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_MODU:
|
||||
opStack[-1] = ((unsigned)r1) % (unsigned)r0;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_MULI:
|
||||
opStack[-1] = r1 * r0;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_MULU:
|
||||
opStack[-1] = ((unsigned)r1) * ((unsigned)r0);
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
|
||||
case OP_BAND:
|
||||
opStack[-1] = ((unsigned)r1) & ((unsigned)r0);
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_BOR:
|
||||
opStack[-1] = ((unsigned)r1) | ((unsigned)r0);
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_BXOR:
|
||||
opStack[-1] = ((unsigned)r1) ^ ((unsigned)r0);
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_BCOM:
|
||||
*opStack = ~ ((unsigned)r0);
|
||||
goto nextInstruction;
|
||||
|
||||
case OP_LSH:
|
||||
opStack[-1] = r1 << r0;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_RSHI:
|
||||
opStack[-1] = r1 >> r0;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_RSHU:
|
||||
opStack[-1] = ((unsigned)r1) >> r0;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
|
||||
case OP_NEGF:
|
||||
*(float *)opStack = -*(float *)opStack;
|
||||
goto nextInstruction;
|
||||
case OP_ADDF:
|
||||
*(float *)(opStack-1) = *(float *)(opStack-1) + *(float *)opStack;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_SUBF:
|
||||
*(float *)(opStack-1) = *(float *)(opStack-1) - *(float *)opStack;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_DIVF:
|
||||
*(float *)(opStack-1) = *(float *)(opStack-1) / *(float *)opStack;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
case OP_MULF:
|
||||
*(float *)(opStack-1) = *(float *)(opStack-1) * *(float *)opStack;
|
||||
opStack--;
|
||||
goto nextInstruction;
|
||||
|
||||
case OP_CVIF:
|
||||
*(float *)opStack = (float)*opStack;
|
||||
goto nextInstruction;
|
||||
case OP_CVFI:
|
||||
*opStack = (int) *(float *)opStack;
|
||||
goto nextInstruction;
|
||||
case OP_SEX8:
|
||||
*opStack = (signed char)*opStack;
|
||||
goto nextInstruction;
|
||||
case OP_SEX16:
|
||||
*opStack = (short)*opStack;
|
||||
goto nextInstruction;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
vm->currentlyInterpreting = qfalse;
|
||||
|
||||
if ( opStack != &stack[1] ) {
|
||||
Com_Error( ERR_DROP, "Interpreter error: opStack = %ld", (long int) (opStack - stack) );
|
||||
}
|
||||
|
||||
vm->programStack = stackOnEntry;
|
||||
|
||||
// return the result
|
||||
return *opStack;
|
||||
}
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
#include "q_shared.h"
|
||||
#include "qcommon.h"
|
||||
|
||||
typedef enum {
|
||||
OP_UNDEF,
|
||||
|
||||
OP_IGNORE,
|
||||
|
||||
OP_BREAK,
|
||||
|
||||
OP_ENTER,
|
||||
OP_LEAVE,
|
||||
OP_CALL,
|
||||
OP_PUSH,
|
||||
OP_POP,
|
||||
|
||||
OP_CONST,
|
||||
OP_LOCAL,
|
||||
|
||||
OP_JUMP,
|
||||
|
||||
//-------------------
|
||||
|
||||
OP_EQ,
|
||||
OP_NE,
|
||||
|
||||
OP_LTI,
|
||||
OP_LEI,
|
||||
OP_GTI,
|
||||
OP_GEI,
|
||||
|
||||
OP_LTU,
|
||||
OP_LEU,
|
||||
OP_GTU,
|
||||
OP_GEU,
|
||||
|
||||
OP_EQF,
|
||||
OP_NEF,
|
||||
|
||||
OP_LTF,
|
||||
OP_LEF,
|
||||
OP_GTF,
|
||||
OP_GEF,
|
||||
|
||||
//-------------------
|
||||
|
||||
OP_LOAD1,
|
||||
OP_LOAD2,
|
||||
OP_LOAD4,
|
||||
OP_STORE1,
|
||||
OP_STORE2,
|
||||
OP_STORE4, // *(stack[top-1]) = stack[top]
|
||||
OP_ARG,
|
||||
|
||||
OP_BLOCK_COPY,
|
||||
|
||||
//-------------------
|
||||
|
||||
OP_SEX8,
|
||||
OP_SEX16,
|
||||
|
||||
OP_NEGI,
|
||||
OP_ADD,
|
||||
OP_SUB,
|
||||
OP_DIVI,
|
||||
OP_DIVU,
|
||||
OP_MODI,
|
||||
OP_MODU,
|
||||
OP_MULI,
|
||||
OP_MULU,
|
||||
|
||||
OP_BAND,
|
||||
OP_BOR,
|
||||
OP_BXOR,
|
||||
OP_BCOM,
|
||||
|
||||
OP_LSH,
|
||||
OP_RSHI,
|
||||
OP_RSHU,
|
||||
|
||||
OP_NEGF,
|
||||
OP_ADDF,
|
||||
OP_SUBF,
|
||||
OP_DIVF,
|
||||
OP_MULF,
|
||||
|
||||
OP_CVIF,
|
||||
OP_CVFI
|
||||
} opcode_t;
|
||||
|
||||
|
||||
|
||||
typedef int vmptr_t;
|
||||
|
||||
typedef struct vmSymbol_s {
|
||||
struct vmSymbol_s *next;
|
||||
int symValue;
|
||||
int profileCount;
|
||||
char symName[1]; // variable sized
|
||||
} vmSymbol_t;
|
||||
|
||||
#define VM_OFFSET_PROGRAM_STACK 0
|
||||
#define VM_OFFSET_SYSTEM_CALL 4
|
||||
|
||||
struct vm_s {
|
||||
// DO NOT MOVE OR CHANGE THESE WITHOUT CHANGING THE VM_OFFSET_* DEFINES
|
||||
// USED BY THE ASM CODE
|
||||
int programStack; // the vm may be recursively entered
|
||||
intptr_t (*systemCall)( intptr_t *parms );
|
||||
|
||||
//------------------------------------
|
||||
|
||||
char name[MAX_QPATH];
|
||||
|
||||
// for dynamic linked modules
|
||||
void *dllHandle;
|
||||
intptr_t (QDECL *entryPoint)( int callNum, ... );
|
||||
void (*destroy)(vm_t* self);
|
||||
|
||||
// for interpreted modules
|
||||
qboolean currentlyInterpreting;
|
||||
|
||||
qboolean compiled;
|
||||
byte *codeBase;
|
||||
int codeLength;
|
||||
|
||||
int *instructionPointers;
|
||||
int instructionPointersLength;
|
||||
|
||||
byte *dataBase;
|
||||
int dataMask;
|
||||
|
||||
int stackBottom; // if programStack < stackBottom, error
|
||||
|
||||
int numSymbols;
|
||||
struct vmSymbol_s *symbols;
|
||||
|
||||
int callLevel; // for debug indenting
|
||||
int breakFunction; // increment breakCount on function entry to this
|
||||
int breakCount;
|
||||
|
||||
char fqpath[MAX_QPATH+1] ;
|
||||
|
||||
byte *jumpTableTargets;
|
||||
int numJumpTableTargets;
|
||||
};
|
||||
|
||||
|
||||
extern vm_t *currentVM;
|
||||
extern int vm_debugLevel;
|
||||
|
||||
void VM_Compile( vm_t *vm, vmHeader_t *header );
|
||||
int VM_CallCompiled( vm_t *vm, int *args );
|
||||
|
||||
void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header );
|
||||
int VM_CallInterpreted( vm_t *vm, int *args );
|
||||
|
||||
vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value );
|
||||
int VM_SymbolToValue( vm_t *vm, const char *symbol );
|
||||
const char *VM_ValueToSymbol( vm_t *vm, int value );
|
||||
void VM_LogSyscalls( int *args );
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#include "vm_local.h"
|
||||
|
||||
int VM_CallCompiled( vm_t *vm, int *args ) {
|
||||
exit(99);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||
exit(99);
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue