1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2024-12-23 01:59:43 +08:00

Imported tier1 and mathlib code from L4D2 SDK.

This commit is contained in:
Scott Ehlert 2012-05-21 02:48:36 -05:00
parent 5b16d2ec9e
commit d0b0a7a9dd
62 changed files with 30858 additions and 0 deletions

150
linux_sdk/Makefile Normal file
View File

@ -0,0 +1,150 @@
#
# SDK Makefile for x86 Linux
#
#
#############################################################################
# Developer configurable items
#############################################################################
# the name of the mod binary (_i486.so is appended to the end)
NAME = server
# the location of the vcproj that builds the mod
MOD_PROJ = ../game/server/server_scratch-2005.vcproj
# the name of the mod configuration (typically <proj name>_<build type><build target>)
MOD_CONFIG = Server\(SDK\)_ReleaseWin32
# the directory the base binaries (tier0_i486.so, etc) are located
# this should point to your orange box subfolder of where you have srcds installed.
SRCDS_DIR = ~/srcds/orangebox
# the path to your mods directory
# set this so that 'make install' or 'make installrelease' will copy your binary over automatically.
GAME_DIR = $(SRCDS_DIR)/scratchmod
# compiler options (gcc 3.4.1 or above is required - 4.1.2+ recommended)
CC = /usr/bin/gcc
CPLUS = /usr/bin/g++
CLINK = /usr/bin/gcc
CPP_LIB = "libstdc++.a libgcc_eh.a"
# put any compiler flags you want passed here
USER_CFLAGS =
# link flags for your mod, make sure to include any special libraries here
LDFLAGS = "-lm -ldl $(LIB_DIR)/particles_i486.a $(LIB_DIR)/dmxloader_i486.a $(LIB_DIR)/mathlib_i486.a tier0_i486.so vstdlib_i486.so $(LIB_DIR)/tier1_i486.a $(LIB_DIR)/tier2_i486.a $(LIB_DIR)/tier3_i486.a $(LIB_DIR)/choreoobjects_i486.a steam_api_i486.so"
# XERCES 2.6.0 or above ( http://xml.apache.org/xerces-c/ ) is used by the vcproj to makefile converter
# it must be installed before being able to run this makefile
# if you have xerces installed already you should be able to use the two lines below
XERCES_INC_DIR = /usr/include
XERCES_LIB_DIR = /usr/lib
# Change this to true if you want to build debug binaries for everything
# The only exception is the mod/game as MOD_CONFIG determines if it's a debug build or not
DEBUG = false
#############################################################################
# Things below here shouldn't need to be altered
#############################################################################
MAKE = make
AR = "ar rvs"
# the dir we want to put binaries we build into
BUILD_DIR = .
# the place to put object files
BUILD_OBJ_DIR = $(BUILD_DIR)/obj
# the location of the source code
SRC_DIR = ..
# the location of the Linux static libraries
LIB_DIR = $(SRC_DIR)/lib/linux
# the CPU target for the build, must be i486 for now
ARCH = i486
ARCH_CFLAGS = -mtune=i686 -march=pentium3 -mmmx -m32
DEFINES = -D_LINUX -DLINUX -DVPROF_LEVEL=1 -DSWDS -D_finite=finite -Dstricmp=strcasecmp -D_stricmp=strcasecmp \
-D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp
UNDEF = -Usprintf -Ustrncpy -UPROTECTED_THINGS_ENABLE
BASE_CFLAGS = -fno-strict-aliasing -Wall -Werror -Wconversion -Wno-non-virtual-dtor -Wno-invalid-offsetof
SHLIBEXT = so
SHLIBCFLAGS = -fPIC
SHLIBLDFLAGS = -shared -Wl,-Map,$@_map.txt -Wl
# Flags passed to the c compiler
CFLAGS = $(DEFINES) $(ARCH_CFLAGS) -O3 $(BASE_CFLAGS)
ifdef USER_CFLAGS
CFLAGS += $(USER_CFLAGS)
endif
CFLAGS += $(UNDEF)
# Debug flags
DBG_DEFINES = "-D_DEBUG -DDEBUG"
DBG_CFLAGS = "$(DEFINES) $(ARCH_CFLAGS) -g -ggdb $(BASE_CFLAGS) $(UNDEF)"
# define list passed to make for the sub makefile
BASE_DEFINES = CC=$(CC) AR=$(AR) CPLUS=$(CPLUS) CPP_LIB=$(CPP_LIB) DEBUG=$(DEBUG) \
BUILD_DIR=$(BUILD_DIR) BUILD_OBJ_DIR=$(BUILD_OBJ_DIR) SRC_DIR=$(SRC_DIR) \
LIB_DIR=$(LIB_DIR) SHLIBLDFLAGS=$(SHLIBLDFLAGS) SHLIBEXT=$(SHLIBEXT) \
CLINK=$(CLINK) CFLAGS="$(CFLAGS)" DBG_CFLAGS=$(DBG_CFLAGS) LDFLAGS=$(LDFLAGS) \
DEFINES="$(DEFINES)" DBG_DEFINES=$(DBG_DEFINES) \
ARCH=$(ARCH) SRCDS_DIR=$(SRCDS_DIR) MOD_CONFIG=$(MOD_CONFIG) NAME=$(NAME) \
XERCES_INC_DIR=$(XERCES_INC_DIR) XERCES_LIB_DIR=$(XERCES_LIB_DIR)
# Project Makefile
MAKE_SERVER = Makefile.server
MAKE_VCPM = Makefile.vcpm
MAKE_PLUGIN = Makefile.plugin
MAKE_TIER1 = Makefile.tier1
MAKE_MATH = Makefile.mathlib
MAKE_CHOREO = Makefile.choreo
all: check vcpm mod
check:
if [ -z "$(CC)" ]; then echo "Compiler not defined."; exit; fi
if [ ! -d $(BUILD_DIR) ];then mkdir -p $(BUILD_DIR);fi
cd $(BUILD_DIR)
if [ ! -e "$(LIB_DIR)/tier1_i486.a" ]; then $(MAKE) tier1;fi
if [ ! -e "$(LIB_DIR)/mathlib_i486.a" ]; then $(MAKE) mathlib;fi
if [ ! -e "$(LIB_DIR)/choreoobjects_i486.a" ]; then $(MAKE) choreo;fi
if [ ! -f "tier0_i486.so" ]; then ln -s $(SRCDS_DIR)/bin/tier0_i486.so .; fi
if [ ! -f "vstdlib_i486.so" ]; then ln -s $(SRCDS_DIR)/bin/vstdlib_i486.so .; fi
if [ ! -f "steam_api_i486.so" ]; then ln -s $(SRCDS_DIR)/bin/steam_api_i486.so .; fi
vcpm: check
if [ ! -e "vcpm" ]; then $(MAKE) -f $(MAKE_VCPM) $(BASE_DEFINES);fi
mod: check vcpm
./vcpm $(MOD_PROJ)
$(MAKE) -f $(MAKE_SERVER) $(BASE_DEFINES)
plugin: check
$(MAKE) -f $(MAKE_PLUGIN) $(BASE_DEFINES)
tier1:
$(MAKE) -f $(MAKE_TIER1) $(BASE_DEFINES)
mathlib:
$(MAKE) -f $(MAKE_MATH) $(BASE_DEFINES)
choreo:
$(MAKE) -f $(MAKE_CHOREO) $(BASE_DEFINES)
install:
cp -f $(NAME)_$(ARCH).$(SHLIBEXT) $(GAME_DIR)/bin/$(NAME)_$(ARCH).$(SHLIBEXT)
installrelease:
cp -f $(NAME)_$(ARCH).$(SHLIBEXT) $(GAME_DIR)/bin/$(NAME)_$(ARCH).$(SHLIBEXT)
strip $(GAME_DIR)/bin/$(NAME)_$(ARCH).$(SHLIBEXT)
clean:
$(MAKE) -f $(MAKE_VCPM) $(BASE_DEFINES) clean
$(MAKE) -f $(MAKE_PLUGIN) $(BASE_DEFINES) clean
$(MAKE) -f $(MAKE_SERVER) $(BASE_DEFINES) clean
$(MAKE) -f $(MAKE_TIER1) $(BASE_DEFINES) clean
$(MAKE) -f $(MAKE_MATH) $(BASE_DEFINES) clean
$(MAKE) -f $(MAKE_CHOREO) $(BASE_DEFINES) clean

57
linux_sdk/Makefile.choreo Normal file
View File

@ -0,0 +1,57 @@
#
# Choreoobjects Static Library Makefile
#
override NAME = choreoobjects
LIB_SRC_DIR = $(SRC_DIR)/game/shared
PUBLIC_SRC_DIR = $(SRC_DIR)/public
TIER0_PUBLIC_SRC_DIR = $(SRC_DIR)/public/tier0
TIER1_PUBLIC_SRC_DIR = $(SRC_DIR)/public/tier1
UTIL_COMMON_SRC_DIR = $(SRC_DIR)/utils/common
LIB_OBJ_DIR = $(BUILD_OBJ_DIR)/$(NAME)_$(ARCH)
# Extension of linux static library
override SHLIBEXT = a
INCLUDEDIRS = -I$(LIB_SRC_DIR) -I$(PUBLIC_SRC_DIR) -I$(TIER0_PUBLIC_SRC_DIR) -I$(TIER1_PUBLIC_SRC_DIR) -I$(UTIL_COMMON_SRC_DIR) -D_LIB -DCHOREOOBJECTS_STATIC_LIB
DO_CC = $(CPLUS) $(INCLUDEDIRS) -DARCH=$(ARCH)
ifeq "$(DEBUG)" "true"
DO_CC += $(DBG_DEFINES) $(DBG_CFLAGS)
else
DO_CC += -DNDEBUG $(CFLAGS)
endif
DO_CC += -o $@ -c $<
#####################################################################
LIB_OBJS= \
$(LIB_OBJ_DIR)/choreoactor.o \
$(LIB_OBJ_DIR)/choreochannel.o \
$(LIB_OBJ_DIR)/choreoevent.o \
$(LIB_OBJ_DIR)/choreoscene.o \
$(LIB_OBJ_DIR)/sceneimage.o \
all: dirs $(NAME)_$(ARCH).$(SHLIBEXT)
dirs:
-mkdir -p $(BUILD_OBJ_DIR)
-mkdir -p $(LIB_OBJ_DIR)
$(NAME)_$(ARCH).$(SHLIBEXT): $(LIB_OBJS)
$(AR) $(LIB_DIR)/$@ $(LIB_OBJS)
$(LIB_OBJ_DIR)/%.o: $(LIB_SRC_DIR)/%.cpp
$(DO_CC)
install:
cp -f $(NAME)_$(ARCH).$(SHLIBEXT) $(LIB_DIR)/$(NAME)_$(ARCH).$(SHLIBEXT)
clean:
-rm -rf $(LIB_OBJ_DIR)

View File

@ -0,0 +1,71 @@
#
# Mathlin Static Library Makefile
#
override NAME = mathlib
LIB_SRC_DIR = $(SRC_DIR)/$(NAME)
PUBLIC_SRC_DIR = $(SRC_DIR)/public
TIER0_PUBLIC_SRC_DIR = $(SRC_DIR)/public/tier0
TIER1_PUBLIC_SRC_DIR = $(SRC_DIR)/public/tier1
MATHLIB_PUBLIC_SRC_DIR = $(SRC_DIR)/public/mathlib
LIB_OBJ_DIR = $(BUILD_OBJ_DIR)/$(NAME)_$(ARCH)
# Extension of linux static library
override SHLIBEXT = a
INCLUDEDIRS = -I$(PUBLIC_SRC_DIR) -I$(TIER0_PUBLIC_SRC_DIR) -I$(TIER1_PUBLIC_SRC_DIR) -I$(MATHLIB_PUBLIC_SRC_DIR) -D_LIB
DO_CC = $(CPLUS) $(INCLUDEDIRS) -DARCH=$(ARCH)
ifeq "$(DEBUG)" "true"
DO_CC += $(DBG_DEFINES) $(DBG_CFLAGS)
else
DO_CC += -DNDEBUG $(CFLAGS)
endif
DO_CC += -o $@ -c $<
#####################################################################
LIB_OBJS= \
$(LIB_OBJ_DIR)/3dnow.o \
$(LIB_OBJ_DIR)/anorms.o \
$(LIB_OBJ_DIR)/bumpvects.o \
$(LIB_OBJ_DIR)/color_conversion.o \
$(LIB_OBJ_DIR)/halton.o \
$(LIB_OBJ_DIR)/IceKey.o \
$(LIB_OBJ_DIR)/imagequant.o \
$(LIB_OBJ_DIR)/lightdesc.o \
$(LIB_OBJ_DIR)/mathlib_base.o \
$(LIB_OBJ_DIR)/polyhedron.o \
$(LIB_OBJ_DIR)/powsse.o \
$(LIB_OBJ_DIR)/quantize.o \
$(LIB_OBJ_DIR)/randsse.o \
$(LIB_OBJ_DIR)/simdvectormatrix.o \
$(LIB_OBJ_DIR)/sparse_convolution_noise.o \
$(LIB_OBJ_DIR)/sse.o \
$(LIB_OBJ_DIR)/sseconst.o \
$(LIB_OBJ_DIR)/ssenoise.o \
$(LIB_OBJ_DIR)/vector.o \
$(LIB_OBJ_DIR)/vmatrix.o \
all: dirs $(NAME)_$(ARCH).$(SHLIBEXT)
dirs:
-mkdir -p $(BUILD_OBJ_DIR)
-mkdir -p $(LIB_OBJ_DIR)
$(NAME)_$(ARCH).$(SHLIBEXT): $(LIB_OBJS)
$(AR) $(LIB_DIR)/$@ $(LIB_OBJS)
$(LIB_OBJ_DIR)/%.o: $(LIB_SRC_DIR)/%.cpp
$(DO_CC)
install:
cp -f $(NAME)_$(ARCH).$(SHLIBEXT) $(LIB_DIR)/$(NAME)_$(ARCH).$(SHLIBEXT)
clean:
-rm -rf $(LIB_OBJ_DIR)

57
linux_sdk/Makefile.plugin Normal file
View File

@ -0,0 +1,57 @@
#
# Sample server plugin for SRC engine
#
# October 2004, alfred@valvesoftware.com
#
override NAME = serverplugin_empty
PLUGIN_SRC_DIR = $(SRC_DIR)/utils/serverplugin_sample
PUBLIC_SRC_DIR = $(SRC_DIR)/public
TIER0_PUBLIC_SRC_DIR = $(SRC_DIR)/public/tier0
TIER1_PUBLIC_SRC_DIR = $(SRC_DIR)/public/tier1
PLUGIN_OBJ_DIR = $(BUILD_OBJ_DIR)/serverplugin_empty_$(ARCH)
TIER0_OBJ_DIR = $(PLUGIN_OBJ_DIR)/tier0
INCLUDEDIRS = -I$(PUBLIC_SRC_DIR) -I$(TIER0_PUBLIC_SRC_DIR) -I$(TIER1_PUBLIC_SRC_DIR)
LDFLAGS_PLG = -lm -ldl tier0_i486.so vstdlib_i486.so $(LIB_DIR)/mathlib_i486.a $(LIB_DIR)/tier1_i486.a $(LIB_DIR)/tier2_i486.a
DO_CC = $(CPLUS) $(INCLUDEDIRS) -DARCH=$(ARCH)
ifeq "$(DEBUG)" "true"
DO_CC += $(DBG_DEFINES) $(DBG_CFLAGS)
else
DO_CC += -DNDEBUG $(CFLAGS)
endif
DO_CC += -o $@ -c $<
#####################################################################
PLUGIN_OBJS = \
$(PLUGIN_OBJ_DIR)/serverplugin_bot.o \
$(PLUGIN_OBJ_DIR)/serverplugin_empty.o \
TIER0_OBJS = \
$(TIER0_OBJ_DIR)/memoverride.o \
all: dirs $(NAME)_$(ARCH).$(SHLIBEXT)
dirs:
-mkdir -p $(BUILD_OBJ_DIR)
-mkdir -p $(PLUGIN_OBJ_DIR)
-mkdir -p $(TIER0_OBJ_DIR)
$(NAME)_$(ARCH).$(SHLIBEXT): $(PLUGIN_OBJS) $(TIER0_OBJS)
$(CLINK) -o $(BUILD_DIR)/$@ -m32 $(SHLIBLDFLAGS) $(PLUGIN_OBJS) $(TIER0_OBJS) $(PUBLIC_OBJS) $(CPP_LIB) $(LDFLAGS_PLG) $(CPP_LIB)
$(PLUGIN_OBJ_DIR)/%.o: $(PLUGIN_SRC_DIR)/%.cpp
$(DO_CC)
$(TIER0_OBJ_DIR)/%.o: $(TIER0_PUBLIC_SRC_DIR)/%.cpp
$(DO_CC)
clean:
-rm -rf $(PLUGIN_OBJ_DIR)
-rm -f $(NAME)_$(ARCH).$(SHLIBEXT)

28
linux_sdk/Makefile.server Normal file
View File

@ -0,0 +1,28 @@
#
# wrapper Makefile for auto-generated make files
#
#
#############################################################################
# PROJECT MAKEFILES
#############################################################################
MAKE_FILE = Makefile.$(MOD_CONFIG)
-include $(MAKE_FILE)
#############################################################################
# The compiler command line for each src code file to compile
#############################################################################
DO_CC = $(CPLUS) $(INCLUDES) -DARCH=$(ARCH)
ifeq (_DEBUG,$(findstring _DEBUG,$(CFLAGS)))
DO_CC += $(DEFINES) $(DBG_CFLAGS)
else
DO_CC += $(CFLAGS)
endif
DO_CC += -o $@ -c $<
clean:
rm -rf obj/$(NAME)_$(ARCH)
rm -f $(NAME)_$(ARCH).$(SHLIBEXT)

78
linux_sdk/Makefile.tier1 Normal file
View File

@ -0,0 +1,78 @@
#
# Tier1 Static Library Makefile
#
override NAME = tier1
LIB_SRC_DIR = $(SRC_DIR)/$(NAME)
PUBLIC_SRC_DIR = $(SRC_DIR)/public
TIER0_PUBLIC_SRC_DIR = $(SRC_DIR)/public/tier0
TIER1_PUBLIC_SRC_DIR = $(SRC_DIR)/public/tier1
LIB_OBJ_DIR=$(BUILD_OBJ_DIR)/$(NAME)_$(ARCH)
# Extension of linux static library
override SHLIBEXT = a
INCLUDEDIRS = -I$(PUBLIC_SRC_DIR) -I$(TIER0_PUBLIC_SRC_DIR) -I$(TIER1_PUBLIC_SRC_DIR) -D_LIB -DTIER1_STATIC_LIB
DO_CC = $(CPLUS) $(INCLUDEDIRS) -DARCH=$(ARCH)
ifeq "$(DEBUG)" "true"
DO_CC += $(DBG_DEFINES) $(DBG_CFLAGS)
else
DO_CC += -DNDEBUG $(CFLAGS)
endif
DO_CC += -o $@ -c $<
#####################################################################
LIB_OBJS= \
$(LIB_OBJ_DIR)/bitbuf.o \
$(LIB_OBJ_DIR)/byteswap.o \
$(LIB_OBJ_DIR)/characterset.o \
$(LIB_OBJ_DIR)/checksum_crc.o \
$(LIB_OBJ_DIR)/checksum_md5.o \
$(LIB_OBJ_DIR)/commandbuffer.o \
$(LIB_OBJ_DIR)/convar.o \
$(LIB_OBJ_DIR)/datamanager.o \
$(LIB_OBJ_DIR)/diff.o \
$(LIB_OBJ_DIR)/generichash.o \
$(LIB_OBJ_DIR)/interface.o \
$(LIB_OBJ_DIR)/KeyValues.o \
$(LIB_OBJ_DIR)/mempool.o \
$(LIB_OBJ_DIR)/memstack.o \
$(LIB_OBJ_DIR)/NetAdr.o \
$(LIB_OBJ_DIR)/newbitbuf.o \
$(LIB_OBJ_DIR)/processor_detect.o \
$(LIB_OBJ_DIR)/rangecheckedvar.o \
$(LIB_OBJ_DIR)/stringpool.o \
$(LIB_OBJ_DIR)/strtools.o \
$(LIB_OBJ_DIR)/tier1.o \
$(LIB_OBJ_DIR)/tokenreader.o \
$(LIB_OBJ_DIR)/undiff.o \
$(LIB_OBJ_DIR)/uniqueid.o \
$(LIB_OBJ_DIR)/utlbuffer.o \
$(LIB_OBJ_DIR)/utlbufferutil.o \
$(LIB_OBJ_DIR)/utlstring.o \
$(LIB_OBJ_DIR)/utlsymbol.o \
all: dirs $(NAME)_$(ARCH).$(SHLIBEXT)
dirs:
-mkdir -p $(BUILD_OBJ_DIR)
-mkdir -p $(LIB_OBJ_DIR)
$(NAME)_$(ARCH).$(SHLIBEXT): $(LIB_OBJS)
$(AR) $(LIB_DIR)/$@ $(LIB_OBJS)
$(LIB_OBJ_DIR)/%.o: $(LIB_SRC_DIR)/%.cpp
$(DO_CC)
install:
cp -f $(NAME)_$(ARCH).$(SHLIBEXT) $(LIB_DIR)/$(NAME)_$(ARCH).$(SHLIBEXT)
clean:
-rm -rf $(LIB_OBJ_DIR)

50
linux_sdk/Makefile.vcpm Normal file
View File

@ -0,0 +1,50 @@
#
# VCProject file to Makefile converter
#
# November 2004, alfred@valvesoftware.com
#
VCPM_SRC_DIR = $(SRC_DIR)/utils/vprojtomake
PUBLIC_SRC_DIR = $(SRC_DIR)/public
TIER0_PUBLIC_SRC_DIR = $(SRC_DIR)/public/tier0
TIER1_PUBLIC_SRC_DIR = $(SRC_DIR)/public/tier1
UTIL_COMMON_SRC_DIR = $(SRC_DIR)/utils/common
VCPM_OBJ_DIR = $(BUILD_OBJ_DIR)/vcpm
INCLUDEDIRS = -I$(PUBLIC_SRC_DIR) -I$(XERCES_INC_DIR) -I$(TIER0_PUBLIC_SRC_DIR) -I$(TIER1_PUBLIC_SRC_DIR) -I$(UTIL_COMMON_SRC_DIR)
LDFLAGS_VC = -lm -ldl -L$(XERCES_LIB_DIR) -lxerces-c tier0_i486.so vstdlib_i486.so $(LIB_DIR)/tier1_i486.a
DO_CC = $(CPLUS) $(INCLUDEDIRS) -DARCH=$(ARCH)
ifeq "$(DEBUG)" "true"
DO_CC += $(DBG_DEFINES) $(DBG_CFLAGS)
else
DO_CC += -DNDEBUG $(CFLAGS)
endif
DO_CC += -o $@ -c $<
#####################################################################
VCPM_OBJS = \
$(VCPM_OBJ_DIR)/makefilecreator.o \
$(VCPM_OBJ_DIR)/vprojtomake.o \
$(VCPM_OBJ_DIR)/vcprojconvert.o \
all: dirs vcpm
dirs:
-mkdir -p $(BUILD_OBJ_DIR)
-mkdir -p $(VCPM_OBJ_DIR)
vcpm: $(VCPM_OBJS)
$(CLINK) -m32 -o $(BUILD_DIR)/$@ $(VCPM_OBJS) $(CPP_LIB) $(LDFLAGS_VC)
$(VCPM_OBJ_DIR)/%.o: $(VCPM_SRC_DIR)/%.cpp
$(DO_CC)
clean:
-rm -rf $(VCPM_OBJ_DIR)
-rm -f vcpm

193
mathlib/3dnow.cpp Normal file
View File

@ -0,0 +1,193 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: 3DNow Math primitives.
//
//=====================================================================================//
#include <math.h>
#include <float.h> // Needed for FLT_EPSILON
#include "basetypes.h"
#include <memory.h>
#include "tier0/dbg.h"
#include "mathlib/mathlib.h"
#include "mathlib/amd3dx.h"
#include "mathlib/vector.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#ifdef _MSC_VER
#pragma warning(disable:4244) // "conversion from 'const int' to 'float', possible loss of data"
#pragma warning(disable:4730) // "mixing _m64 and floating point expressions may result in incorrect code"
#endif
//-----------------------------------------------------------------------------
// 3D Now Implementations of optimized routines:
//-----------------------------------------------------------------------------
float _3DNow_Sqrt(float x)
{
Assert( s_bMathlibInitialized );
float root = 0.f;
#ifdef _WIN32
_asm
{
femms
movd mm0, x
PFRSQRT (mm1,mm0)
punpckldq mm0, mm0
PFMUL (mm0, mm1)
movd root, mm0
femms
}
#elif defined _LINUX || defined __APPLE__
__asm __volatile__( "femms" );
__asm __volatile__
(
"pfrsqrt %y0, %y1 \n\t"
"punpckldq %y1, %y1 \n\t"
"pfmul %y1, %y0 \n\t"
: "=y" (root), "=y" (x)
:"0" (x)
);
__asm __volatile__( "femms" );
#else
#error
#endif
return root;
}
// NJS FIXME: Need to test Recripricol squareroot performance and accuraccy
// on AMD's before using the specialized instruction.
float _3DNow_RSqrt(float x)
{
Assert( s_bMathlibInitialized );
return 1.f / _3DNow_Sqrt(x);
}
float FASTCALL _3DNow_VectorNormalize (Vector& vec)
{
Assert( s_bMathlibInitialized );
float *v = &vec[0];
float radius = 0.f;
if ( v[0] || v[1] || v[2] )
{
#ifdef _WIN32
_asm
{
mov eax, v
femms
movq mm0, QWORD PTR [eax]
movd mm1, DWORD PTR [eax+8]
movq mm2, mm0
movq mm3, mm1
PFMUL (mm0, mm0)
PFMUL (mm1, mm1)
PFACC (mm0, mm0)
PFADD (mm1, mm0)
PFRSQRT (mm0, mm1)
punpckldq mm1, mm1
PFMUL (mm1, mm0)
PFMUL (mm2, mm0)
PFMUL (mm3, mm0)
movq QWORD PTR [eax], mm2
movd DWORD PTR [eax+8], mm3
movd radius, mm1
femms
}
#elif defined _LINUX || defined __APPLE__
long long a,c;
int b,d;
memcpy(&a,&vec[0],sizeof(a));
memcpy(&b,&vec[2],sizeof(b));
memcpy(&c,&vec[0],sizeof(c));
memcpy(&d,&vec[2],sizeof(d));
__asm __volatile__( "femms" );
__asm __volatile__
(
"pfmul %y3, %y3\n\t"
"pfmul %y0, %y0 \n\t"
"pfacc %y3, %y3 \n\t"
"pfadd %y3, %y0 \n\t"
"pfrsqrt %y0, %y3 \n\t"
"punpckldq %y0, %y0 \n\t"
"pfmul %y3, %y0 \n\t"
"pfmul %y3, %y2 \n\t"
"pfmul %y3, %y1 \n\t"
: "=y" (radius), "=y" (c), "=y" (d)
: "y" (a), "0" (b), "1" (c), "2" (d)
);
memcpy(&vec[0],&c,sizeof(c));
memcpy(&vec[2],&d,sizeof(d));
__asm __volatile__( "femms" );
#else
#error
#endif
}
return radius;
}
void FASTCALL _3DNow_VectorNormalizeFast (Vector& vec)
{
_3DNow_VectorNormalize( vec );
}
// JAY: This complains with the latest processor pack
#ifdef _MSC_VER
#pragma warning(disable: 4730)
#endif
float _3DNow_InvRSquared(const float* v)
{
Assert( s_bMathlibInitialized );
float r2 = 1.f;
#ifdef _WIN32
_asm { // AMD 3DNow only routine
mov eax, v
femms
movq mm0, QWORD PTR [eax]
movd mm1, DWORD PTR [eax+8]
movd mm2, [r2]
PFMUL (mm0, mm0)
PFMUL (mm1, mm1)
PFACC (mm0, mm0)
PFADD (mm1, mm0)
PFMAX (mm1, mm2)
PFRCP (mm0, mm1)
movd [r2], mm0
femms
}
#elif defined _LINUX || defined __APPLE__
long long a,c;
int b;
memcpy(&a,&v[0],sizeof(a));
memcpy(&b,&v[2],sizeof(b));
memcpy(&c,&v[0],sizeof(c));
__asm __volatile__( "femms" );
__asm __volatile__
(
"PFMUL %y2, %y2 \n\t"
"PFMUL %y3, %y3 \n\t"
"PFACC %y2, %y2 \n\t"
"PFADD %y2, %y3 \n\t"
"PFMAX %y3, %y4 \n\t"
"PFRCP %y3, %y2 \n\t"
"movq %y2, %y0 \n\t"
: "=y" (r2)
: "0" (r2), "y" (a), "y" (b), "y" (c)
);
__asm __volatile__( "femms" );
#else
#error
#endif
return r2;
}

16
mathlib/3dnow.h Normal file
View File

@ -0,0 +1,16 @@
//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef _3DNOW_H
#define _3DNOW_H
float _3DNow_Sqrt(float x);
float _3DNow_RSqrt(float x);
float FASTCALL _3DNow_VectorNormalize (Vector& vec);
void FASTCALL _3DNow_VectorNormalizeFast (Vector& vec);
float _3DNow_InvRSquared(const float* v);
#endif // _3DNOW_H

394
mathlib/IceKey.cpp Normal file
View File

@ -0,0 +1,394 @@
// Purpose: C++ implementation of the ICE encryption algorithm.
// Taken from public domain code, as written by Matthew Kwan - July 1996
// http://www.darkside.com.au/ice/
#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB)
#include "mathlib/IceKey.H"
#ifdef _MSC_VER
#pragma warning(disable: 4244)
#endif
/* Structure of a single round subkey */
class IceSubkey {
public:
unsigned long val[3];
};
/* The S-boxes */
static unsigned long ice_sbox[4][1024];
static int ice_sboxes_initialised = 0;
/* Modulo values for the S-boxes */
static const int ice_smod[4][4] = {
{333, 313, 505, 369},
{379, 375, 319, 391},
{361, 445, 451, 397},
{397, 425, 395, 505}};
/* XOR values for the S-boxes */
static const int ice_sxor[4][4] = {
{0x83, 0x85, 0x9b, 0xcd},
{0xcc, 0xa7, 0xad, 0x41},
{0x4b, 0x2e, 0xd4, 0x33},
{0xea, 0xcb, 0x2e, 0x04}};
/* Permutation values for the P-box */
static const unsigned long ice_pbox[32] = {
0x00000001, 0x00000080, 0x00000400, 0x00002000,
0x00080000, 0x00200000, 0x01000000, 0x40000000,
0x00000008, 0x00000020, 0x00000100, 0x00004000,
0x00010000, 0x00800000, 0x04000000, 0x20000000,
0x00000004, 0x00000010, 0x00000200, 0x00008000,
0x00020000, 0x00400000, 0x08000000, 0x10000000,
0x00000002, 0x00000040, 0x00000800, 0x00001000,
0x00040000, 0x00100000, 0x02000000, 0x80000000};
/* The key rotation schedule */
static const int ice_keyrot[16] = {
0, 1, 2, 3, 2, 1, 3, 0,
1, 3, 2, 0, 3, 1, 0, 2};
/*
* 8-bit Galois Field multiplication of a by b, modulo m.
* Just like arithmetic multiplication, except that additions and
* subtractions are replaced by XOR.
*/
static unsigned int
gf_mult (
register unsigned int a,
register unsigned int b,
register unsigned int m
) {
register unsigned int res = 0;
while (b) {
if (b & 1)
res ^= a;
a <<= 1;
b >>= 1;
if (a >= 256)
a ^= m;
}
return (res);
}
/*
* Galois Field exponentiation.
* Raise the base to the power of 7, modulo m.
*/
static unsigned long
gf_exp7 (
register unsigned int b,
unsigned int m
) {
register unsigned int x;
if (b == 0)
return (0);
x = gf_mult (b, b, m);
x = gf_mult (b, x, m);
x = gf_mult (x, x, m);
return (gf_mult (b, x, m));
}
/*
* Carry out the ICE 32-bit P-box permutation.
*/
static unsigned long
ice_perm32 (
register unsigned long x
) {
register unsigned long res = 0;
register const unsigned long *pbox = ice_pbox;
while (x) {
if (x & 1)
res |= *pbox;
pbox++;
x >>= 1;
}
return (res);
}
/*
* Initialise the ICE S-boxes.
* This only has to be done once.
*/
static void
ice_sboxes_init (void)
{
register int i;
for (i=0; i<1024; i++) {
int col = (i >> 1) & 0xff;
int row = (i & 0x1) | ((i & 0x200) >> 8);
unsigned long x;
x = gf_exp7 (col ^ ice_sxor[0][row], ice_smod[0][row]) << 24;
ice_sbox[0][i] = ice_perm32 (x);
x = gf_exp7 (col ^ ice_sxor[1][row], ice_smod[1][row]) << 16;
ice_sbox[1][i] = ice_perm32 (x);
x = gf_exp7 (col ^ ice_sxor[2][row], ice_smod[2][row]) << 8;
ice_sbox[2][i] = ice_perm32 (x);
x = gf_exp7 (col ^ ice_sxor[3][row], ice_smod[3][row]);
ice_sbox[3][i] = ice_perm32 (x);
}
}
/*
* Create a new ICE key.
*/
IceKey::IceKey (int n)
{
if (!ice_sboxes_initialised) {
ice_sboxes_init ();
ice_sboxes_initialised = 1;
}
if (n < 1) {
_size = 1;
_rounds = 8;
} else {
_size = n;
_rounds = n * 16;
}
_keysched = new IceSubkey[_rounds];
}
/*
* Destroy an ICE key.
*/
IceKey::~IceKey ()
{
int i, j;
for (i=0; i<_rounds; i++)
for (j=0; j<3; j++)
_keysched[i].val[j] = 0;
_rounds = _size = 0;
delete[] _keysched;
}
/*
* The single round ICE f function.
*/
static unsigned long
ice_f (
register unsigned long p,
const IceSubkey *sk
) {
unsigned long tl, tr; /* Expanded 40-bit values */
unsigned long al, ar; /* Salted expanded 40-bit values */
/* Left half expansion */
tl = ((p >> 16) & 0x3ff) | (((p >> 14) | (p << 18)) & 0xffc00);
/* Right half expansion */
tr = (p & 0x3ff) | ((p << 2) & 0xffc00);
/* Perform the salt permutation */
// al = (tr & sk->val[2]) | (tl & ~sk->val[2]);
// ar = (tl & sk->val[2]) | (tr & ~sk->val[2]);
al = sk->val[2] & (tl ^ tr);
ar = al ^ tr;
al ^= tl;
al ^= sk->val[0]; /* XOR with the subkey */
ar ^= sk->val[1];
/* S-box lookup and permutation */
return (ice_sbox[0][al >> 10] | ice_sbox[1][al & 0x3ff]
| ice_sbox[2][ar >> 10] | ice_sbox[3][ar & 0x3ff]);
}
/*
* Encrypt a block of 8 bytes of data with the given ICE key.
*/
void
IceKey::encrypt (
const unsigned char *ptext,
unsigned char *ctext
) const
{
register int i;
register unsigned long l, r;
l = (((unsigned long) ptext[0]) << 24)
| (((unsigned long) ptext[1]) << 16)
| (((unsigned long) ptext[2]) << 8) | ptext[3];
r = (((unsigned long) ptext[4]) << 24)
| (((unsigned long) ptext[5]) << 16)
| (((unsigned long) ptext[6]) << 8) | ptext[7];
for (i = 0; i < _rounds; i += 2) {
l ^= ice_f (r, &_keysched[i]);
r ^= ice_f (l, &_keysched[i + 1]);
}
for (i = 0; i < 4; i++) {
ctext[3 - i] = r & 0xff;
ctext[7 - i] = l & 0xff;
r >>= 8;
l >>= 8;
}
}
/*
* Decrypt a block of 8 bytes of data with the given ICE key.
*/
void
IceKey::decrypt (
const unsigned char *ctext,
unsigned char *ptext
) const
{
register int i;
register unsigned long l, r;
l = (((unsigned long) ctext[0]) << 24)
| (((unsigned long) ctext[1]) << 16)
| (((unsigned long) ctext[2]) << 8) | ctext[3];
r = (((unsigned long) ctext[4]) << 24)
| (((unsigned long) ctext[5]) << 16)
| (((unsigned long) ctext[6]) << 8) | ctext[7];
for (i = _rounds - 1; i > 0; i -= 2) {
l ^= ice_f (r, &_keysched[i]);
r ^= ice_f (l, &_keysched[i - 1]);
}
for (i = 0; i < 4; i++) {
ptext[3 - i] = r & 0xff;
ptext[7 - i] = l & 0xff;
r >>= 8;
l >>= 8;
}
}
/*
* Set 8 rounds [n, n+7] of the key schedule of an ICE key.
*/
void
IceKey::scheduleBuild (
unsigned short *kb,
int n,
const int *keyrot
) {
int i;
for (i=0; i<8; i++) {
register int j;
register int kr = keyrot[i];
IceSubkey *isk = &_keysched[n + i];
for (j=0; j<3; j++)
isk->val[j] = 0;
for (j=0; j<15; j++) {
register int k;
unsigned long *curr_sk = &isk->val[j % 3];
for (k=0; k<4; k++) {
unsigned short *curr_kb = &kb[(kr + k) & 3];
register int bit = *curr_kb & 1;
*curr_sk = (*curr_sk << 1) | bit;
*curr_kb = (*curr_kb >> 1) | ((bit ^ 1) << 15);
}
}
}
}
/*
* Set the key schedule of an ICE key.
*/
void
IceKey::set (
const unsigned char *key
) {
int i;
if (_rounds == 8) {
unsigned short kb[4];
for (i=0; i<4; i++)
kb[3 - i] = (key[i*2] << 8) | key[i*2 + 1];
scheduleBuild (kb, 0, ice_keyrot);
return;
}
for (i=0; i<_size; i++) {
int j;
unsigned short kb[4];
for (j=0; j<4; j++)
kb[3 - j] = (key[i*8 + j*2] << 8) | key[i*8 + j*2 + 1];
scheduleBuild (kb, i*8, ice_keyrot);
scheduleBuild (kb, _rounds - 8 - i*8, &ice_keyrot[8]);
}
}
/*
* Return the key size, in bytes.
*/
int
IceKey::keySize () const
{
return (_size * 8);
}
/*
* Return the block size, in bytes.
*/
int
IceKey::blockSize () const
{
return (8);
}
#endif // !_STATIC_LINKED || _SHARED_LIB

181
mathlib/anorms.cpp Normal file
View File

@ -0,0 +1,181 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB)
#include "mathlib/vector.h"
#include "mathlib/anorms.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
Vector g_anorms[NUMVERTEXNORMALS] =
{
Vector(-0.525731, 0.000000, 0.850651),
Vector(-0.442863, 0.238856, 0.864188),
Vector(-0.295242, 0.000000, 0.955423),
Vector(-0.309017, 0.500000, 0.809017),
Vector(-0.162460, 0.262866, 0.951056),
Vector(0.000000, 0.000000, 1.000000),
Vector(0.000000, 0.850651, 0.525731),
Vector(-0.147621, 0.716567, 0.681718),
Vector(0.147621, 0.716567, 0.681718),
Vector(0.000000, 0.525731, 0.850651),
Vector(0.309017, 0.500000, 0.809017),
Vector(0.525731, 0.000000, 0.850651),
Vector(0.295242, 0.000000, 0.955423),
Vector(0.442863, 0.238856, 0.864188),
Vector(0.162460, 0.262866, 0.951056),
Vector(-0.681718, 0.147621, 0.716567),
Vector(-0.809017, 0.309017, 0.500000),
Vector(-0.587785, 0.425325, 0.688191),
Vector(-0.850651, 0.525731, 0.000000),
Vector(-0.864188, 0.442863, 0.238856),
Vector(-0.716567, 0.681718, 0.147621),
Vector(-0.688191, 0.587785, 0.425325),
Vector(-0.500000, 0.809017, 0.309017),
Vector(-0.238856, 0.864188, 0.442863),
Vector(-0.425325, 0.688191, 0.587785),
Vector(-0.716567, 0.681718, -0.147621),
Vector(-0.500000, 0.809017, -0.309017),
Vector(-0.525731, 0.850651, 0.000000),
Vector(0.000000, 0.850651, -0.525731),
Vector(-0.238856, 0.864188, -0.442863),
Vector(0.000000, 0.955423, -0.295242),
Vector(-0.262866, 0.951056, -0.162460),
Vector(0.000000, 1.000000, 0.000000),
Vector(0.000000, 0.955423, 0.295242),
Vector(-0.262866, 0.951056, 0.162460),
Vector(0.238856, 0.864188, 0.442863),
Vector(0.262866, 0.951056, 0.162460),
Vector(0.500000, 0.809017, 0.309017),
Vector(0.238856, 0.864188, -0.442863),
Vector(0.262866, 0.951056, -0.162460),
Vector(0.500000, 0.809017, -0.309017),
Vector(0.850651, 0.525731, 0.000000),
Vector(0.716567, 0.681718, 0.147621),
Vector(0.716567, 0.681718, -0.147621),
Vector(0.525731, 0.850651, 0.000000),
Vector(0.425325, 0.688191, 0.587785),
Vector(0.864188, 0.442863, 0.238856),
Vector(0.688191, 0.587785, 0.425325),
Vector(0.809017, 0.309017, 0.500000),
Vector(0.681718, 0.147621, 0.716567),
Vector(0.587785, 0.425325, 0.688191),
Vector(0.955423, 0.295242, 0.000000),
Vector(1.000000, 0.000000, 0.000000),
Vector(0.951056, 0.162460, 0.262866),
Vector(0.850651, -0.525731, 0.000000),
Vector(0.955423, -0.295242, 0.000000),
Vector(0.864188, -0.442863, 0.238856),
Vector(0.951056, -0.162460, 0.262866),
Vector(0.809017, -0.309017, 0.500000),
Vector(0.681718, -0.147621, 0.716567),
Vector(0.850651, 0.000000, 0.525731),
Vector(0.864188, 0.442863, -0.238856),
Vector(0.809017, 0.309017, -0.500000),
Vector(0.951056, 0.162460, -0.262866),
Vector(0.525731, 0.000000, -0.850651),
Vector(0.681718, 0.147621, -0.716567),
Vector(0.681718, -0.147621, -0.716567),
Vector(0.850651, 0.000000, -0.525731),
Vector(0.809017, -0.309017, -0.500000),
Vector(0.864188, -0.442863, -0.238856),
Vector(0.951056, -0.162460, -0.262866),
Vector(0.147621, 0.716567, -0.681718),
Vector(0.309017, 0.500000, -0.809017),
Vector(0.425325, 0.688191, -0.587785),
Vector(0.442863, 0.238856, -0.864188),
Vector(0.587785, 0.425325, -0.688191),
Vector(0.688191, 0.587785, -0.425325),
Vector(-0.147621, 0.716567, -0.681718),
Vector(-0.309017, 0.500000, -0.809017),
Vector(0.000000, 0.525731, -0.850651),
Vector(-0.525731, 0.000000, -0.850651),
Vector(-0.442863, 0.238856, -0.864188),
Vector(-0.295242, 0.000000, -0.955423),
Vector(-0.162460, 0.262866, -0.951056),
Vector(0.000000, 0.000000, -1.000000),
Vector(0.295242, 0.000000, -0.955423),
Vector(0.162460, 0.262866, -0.951056),
Vector(-0.442863, -0.238856, -0.864188),
Vector(-0.309017, -0.500000, -0.809017),
Vector(-0.162460, -0.262866, -0.951056),
Vector(0.000000, -0.850651, -0.525731),
Vector(-0.147621, -0.716567, -0.681718),
Vector(0.147621, -0.716567, -0.681718),
Vector(0.000000, -0.525731, -0.850651),
Vector(0.309017, -0.500000, -0.809017),
Vector(0.442863, -0.238856, -0.864188),
Vector(0.162460, -0.262866, -0.951056),
Vector(0.238856, -0.864188, -0.442863),
Vector(0.500000, -0.809017, -0.309017),
Vector(0.425325, -0.688191, -0.587785),
Vector(0.716567, -0.681718, -0.147621),
Vector(0.688191, -0.587785, -0.425325),
Vector(0.587785, -0.425325, -0.688191),
Vector(0.000000, -0.955423, -0.295242),
Vector(0.000000, -1.000000, 0.000000),
Vector(0.262866, -0.951056, -0.162460),
Vector(0.000000, -0.850651, 0.525731),
Vector(0.000000, -0.955423, 0.295242),
Vector(0.238856, -0.864188, 0.442863),
Vector(0.262866, -0.951056, 0.162460),
Vector(0.500000, -0.809017, 0.309017),
Vector(0.716567, -0.681718, 0.147621),
Vector(0.525731, -0.850651, 0.000000),
Vector(-0.238856, -0.864188, -0.442863),
Vector(-0.500000, -0.809017, -0.309017),
Vector(-0.262866, -0.951056, -0.162460),
Vector(-0.850651, -0.525731, 0.000000),
Vector(-0.716567, -0.681718, -0.147621),
Vector(-0.716567, -0.681718, 0.147621),
Vector(-0.525731, -0.850651, 0.000000),
Vector(-0.500000, -0.809017, 0.309017),
Vector(-0.238856, -0.864188, 0.442863),
Vector(-0.262866, -0.951056, 0.162460),
Vector(-0.864188, -0.442863, 0.238856),
Vector(-0.809017, -0.309017, 0.500000),
Vector(-0.688191, -0.587785, 0.425325),
Vector(-0.681718, -0.147621, 0.716567),
Vector(-0.442863, -0.238856, 0.864188),
Vector(-0.587785, -0.425325, 0.688191),
Vector(-0.309017, -0.500000, 0.809017),
Vector(-0.147621, -0.716567, 0.681718),
Vector(-0.425325, -0.688191, 0.587785),
Vector(-0.162460, -0.262866, 0.951056),
Vector(0.442863, -0.238856, 0.864188),
Vector(0.162460, -0.262866, 0.951056),
Vector(0.309017, -0.500000, 0.809017),
Vector(0.147621, -0.716567, 0.681718),
Vector(0.000000, -0.525731, 0.850651),
Vector(0.425325, -0.688191, 0.587785),
Vector(0.587785, -0.425325, 0.688191),
Vector(0.688191, -0.587785, 0.425325),
Vector(-0.955423, 0.295242, 0.000000),
Vector(-0.951056, 0.162460, 0.262866),
Vector(-1.000000, 0.000000, 0.000000),
Vector(-0.850651, 0.000000, 0.525731),
Vector(-0.955423, -0.295242, 0.000000),
Vector(-0.951056, -0.162460, 0.262866),
Vector(-0.864188, 0.442863, -0.238856),
Vector(-0.951056, 0.162460, -0.262866),
Vector(-0.809017, 0.309017, -0.500000),
Vector(-0.864188, -0.442863, -0.238856),
Vector(-0.951056, -0.162460, -0.262866),
Vector(-0.809017, -0.309017, -0.500000),
Vector(-0.681718, 0.147621, -0.716567),
Vector(-0.681718, -0.147621, -0.716567),
Vector(-0.850651, 0.000000, -0.525731),
Vector(-0.688191, 0.587785, -0.425325),
Vector(-0.587785, 0.425325, -0.688191),
Vector(-0.425325, 0.688191, -0.587785),
Vector(-0.425325, -0.688191, -0.587785),
Vector(-0.587785, -0.425325, -0.688191),
Vector(-0.688191, -0.587785, -0.425325)
};
#endif // !_STATIC_LINKED || _SHARED_LIB

69
mathlib/bumpvects.cpp Normal file
View File

@ -0,0 +1,69 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#if !defined(_STATIC_LINKED) || defined(_SHARED_LIB)
#ifdef QUIVER
#include "r_local.h"
#endif
#include "mathlib/bumpvects.h"
#include "mathlib/vector.h"
#include <assert.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// z is coming out of the face.
void GetBumpNormals( const Vector& sVect, const Vector& tVect, const Vector& flatNormal,
const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS] )
{
Vector tmpNormal;
bool leftHanded;
int i;
assert( NUM_BUMP_VECTS == 3 );
// Are we left or right handed?
CrossProduct( sVect, tVect, tmpNormal );
if( DotProduct( flatNormal, tmpNormal ) < 0.0f )
{
leftHanded = true;
}
else
{
leftHanded = false;
}
// Build a basis for the face around the phong normal
matrix3x4_t smoothBasis;
CrossProduct( phongNormal.Base(), sVect.Base(), smoothBasis[1] );
VectorNormalize( smoothBasis[1] );
CrossProduct( smoothBasis[1], phongNormal.Base(), smoothBasis[0] );
VectorNormalize( smoothBasis[0] );
VectorCopy( phongNormal.Base(), smoothBasis[2] );
if( leftHanded )
{
VectorNegate( smoothBasis[1] );
}
// move the g_localBumpBasis into world space to create bumpNormals
for( i = 0; i < 3; i++ )
{
VectorIRotate( g_localBumpBasis[i], smoothBasis, bumpNormals[i] );
}
}
#endif // !_STATIC_LINKED || _SHARED_LIB

View File

@ -0,0 +1,645 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Color conversion routines.
//
//=====================================================================================//
#include <math.h>
#include <float.h> // Needed for FLT_EPSILON
#include "basetypes.h"
#include <memory.h>
#include "tier0/dbg.h"
#include "mathlib/mathlib.h"
#include "mathlib/vector.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Gamma conversion support
//-----------------------------------------------------------------------------
static byte texgammatable[256]; // palette is sent through this to convert to screen gamma
static float texturetolinear[256]; // texture (0..255) to linear (0..1)
static int lineartotexture[1024]; // linear (0..1) to texture (0..255)
static int lineartoscreen[1024]; // linear (0..1) to gamma corrected vertex light (0..255)
// build a lightmap texture to combine with surface texture, adjust for src*dst+dst*src, ramp reprogramming, etc
float lineartovertex[4096]; // linear (0..4) to screen corrected vertex space (0..1?)
unsigned char lineartolightmap[4096]; // linear (0..4) to screen corrected texture value (0..255)
static float g_Mathlib_GammaToLinear[256]; // gamma (0..1) to linear (0..1)
static float g_Mathlib_LinearToGamma[256]; // linear (0..1) to gamma (0..1)
// This is aligned to 16-byte boundaries so that we can load it
// onto SIMD registers easily if needed (used by SSE version of lightmaps)
// TODO: move this into the one DLL that actually uses it, instead of statically
// linking it everywhere via mathlib.
ALIGN128 float power2_n[256] = // 2**(index - 128) / 255
{
1.152445441982634800E-041, 2.304890883965269600E-041, 4.609781767930539200E-041, 9.219563535861078400E-041,
1.843912707172215700E-040, 3.687825414344431300E-040, 7.375650828688862700E-040, 1.475130165737772500E-039,
2.950260331475545100E-039, 5.900520662951090200E-039, 1.180104132590218000E-038, 2.360208265180436100E-038,
4.720416530360872100E-038, 9.440833060721744200E-038, 1.888166612144348800E-037, 3.776333224288697700E-037,
7.552666448577395400E-037, 1.510533289715479100E-036, 3.021066579430958200E-036, 6.042133158861916300E-036,
1.208426631772383300E-035, 2.416853263544766500E-035, 4.833706527089533100E-035, 9.667413054179066100E-035,
1.933482610835813200E-034, 3.866965221671626400E-034, 7.733930443343252900E-034, 1.546786088668650600E-033,
3.093572177337301200E-033, 6.187144354674602300E-033, 1.237428870934920500E-032, 2.474857741869840900E-032,
4.949715483739681800E-032, 9.899430967479363700E-032, 1.979886193495872700E-031, 3.959772386991745500E-031,
7.919544773983491000E-031, 1.583908954796698200E-030, 3.167817909593396400E-030, 6.335635819186792800E-030,
1.267127163837358600E-029, 2.534254327674717100E-029, 5.068508655349434200E-029, 1.013701731069886800E-028,
2.027403462139773700E-028, 4.054806924279547400E-028, 8.109613848559094700E-028, 1.621922769711818900E-027,
3.243845539423637900E-027, 6.487691078847275800E-027, 1.297538215769455200E-026, 2.595076431538910300E-026,
5.190152863077820600E-026, 1.038030572615564100E-025, 2.076061145231128300E-025, 4.152122290462256500E-025,
8.304244580924513000E-025, 1.660848916184902600E-024, 3.321697832369805200E-024, 6.643395664739610400E-024,
1.328679132947922100E-023, 2.657358265895844200E-023, 5.314716531791688300E-023, 1.062943306358337700E-022,
2.125886612716675300E-022, 4.251773225433350700E-022, 8.503546450866701300E-022, 1.700709290173340300E-021,
3.401418580346680500E-021, 6.802837160693361100E-021, 1.360567432138672200E-020, 2.721134864277344400E-020,
5.442269728554688800E-020, 1.088453945710937800E-019, 2.176907891421875500E-019, 4.353815782843751100E-019,
8.707631565687502200E-019, 1.741526313137500400E-018, 3.483052626275000900E-018, 6.966105252550001700E-018,
1.393221050510000300E-017, 2.786442101020000700E-017, 5.572884202040001400E-017, 1.114576840408000300E-016,
2.229153680816000600E-016, 4.458307361632001100E-016, 8.916614723264002200E-016, 1.783322944652800400E-015,
3.566645889305600900E-015, 7.133291778611201800E-015, 1.426658355722240400E-014, 2.853316711444480700E-014,
5.706633422888961400E-014, 1.141326684577792300E-013, 2.282653369155584600E-013, 4.565306738311169100E-013,
9.130613476622338300E-013, 1.826122695324467700E-012, 3.652245390648935300E-012, 7.304490781297870600E-012,
1.460898156259574100E-011, 2.921796312519148200E-011, 5.843592625038296500E-011, 1.168718525007659300E-010,
2.337437050015318600E-010, 4.674874100030637200E-010, 9.349748200061274400E-010, 1.869949640012254900E-009,
3.739899280024509800E-009, 7.479798560049019500E-009, 1.495959712009803900E-008, 2.991919424019607800E-008,
5.983838848039215600E-008, 1.196767769607843100E-007, 2.393535539215686200E-007, 4.787071078431372500E-007,
9.574142156862745000E-007, 1.914828431372549000E-006, 3.829656862745098000E-006, 7.659313725490196000E-006,
1.531862745098039200E-005, 3.063725490196078400E-005, 6.127450980392156800E-005, 1.225490196078431400E-004,
2.450980392156862700E-004, 4.901960784313725400E-004, 9.803921568627450800E-004, 1.960784313725490200E-003,
3.921568627450980300E-003, 7.843137254901960700E-003, 1.568627450980392100E-002, 3.137254901960784300E-002,
6.274509803921568500E-002, 1.254901960784313700E-001, 2.509803921568627400E-001, 5.019607843137254800E-001,
1.003921568627451000E+000, 2.007843137254901900E+000, 4.015686274509803900E+000, 8.031372549019607700E+000,
1.606274509803921500E+001, 3.212549019607843100E+001, 6.425098039215686200E+001, 1.285019607843137200E+002,
2.570039215686274500E+002, 5.140078431372548900E+002, 1.028015686274509800E+003, 2.056031372549019600E+003,
4.112062745098039200E+003, 8.224125490196078300E+003, 1.644825098039215700E+004, 3.289650196078431300E+004,
6.579300392156862700E+004, 1.315860078431372500E+005, 2.631720156862745100E+005, 5.263440313725490100E+005,
1.052688062745098000E+006, 2.105376125490196000E+006, 4.210752250980392100E+006, 8.421504501960784200E+006,
1.684300900392156800E+007, 3.368601800784313700E+007, 6.737203601568627400E+007, 1.347440720313725500E+008,
2.694881440627450900E+008, 5.389762881254901900E+008, 1.077952576250980400E+009, 2.155905152501960800E+009,
4.311810305003921500E+009, 8.623620610007843000E+009, 1.724724122001568600E+010, 3.449448244003137200E+010,
6.898896488006274400E+010, 1.379779297601254900E+011, 2.759558595202509800E+011, 5.519117190405019500E+011,
1.103823438081003900E+012, 2.207646876162007800E+012, 4.415293752324015600E+012, 8.830587504648031200E+012,
1.766117500929606200E+013, 3.532235001859212500E+013, 7.064470003718425000E+013, 1.412894000743685000E+014,
2.825788001487370000E+014, 5.651576002974740000E+014, 1.130315200594948000E+015, 2.260630401189896000E+015,
4.521260802379792000E+015, 9.042521604759584000E+015, 1.808504320951916800E+016, 3.617008641903833600E+016,
7.234017283807667200E+016, 1.446803456761533400E+017, 2.893606913523066900E+017, 5.787213827046133800E+017,
1.157442765409226800E+018, 2.314885530818453500E+018, 4.629771061636907000E+018, 9.259542123273814000E+018,
1.851908424654762800E+019, 3.703816849309525600E+019, 7.407633698619051200E+019, 1.481526739723810200E+020,
2.963053479447620500E+020, 5.926106958895241000E+020, 1.185221391779048200E+021, 2.370442783558096400E+021,
4.740885567116192800E+021, 9.481771134232385600E+021, 1.896354226846477100E+022, 3.792708453692954200E+022,
7.585416907385908400E+022, 1.517083381477181700E+023, 3.034166762954363400E+023, 6.068333525908726800E+023,
1.213666705181745400E+024, 2.427333410363490700E+024, 4.854666820726981400E+024, 9.709333641453962800E+024,
1.941866728290792600E+025, 3.883733456581585100E+025, 7.767466913163170200E+025, 1.553493382632634000E+026,
3.106986765265268100E+026, 6.213973530530536200E+026, 1.242794706106107200E+027, 2.485589412212214500E+027,
4.971178824424429000E+027, 9.942357648848857900E+027, 1.988471529769771600E+028, 3.976943059539543200E+028,
7.953886119079086300E+028, 1.590777223815817300E+029, 3.181554447631634500E+029, 6.363108895263269100E+029,
1.272621779052653800E+030, 2.545243558105307600E+030, 5.090487116210615300E+030, 1.018097423242123100E+031,
2.036194846484246100E+031, 4.072389692968492200E+031, 8.144779385936984400E+031, 1.628955877187396900E+032,
3.257911754374793800E+032, 6.515823508749587500E+032, 1.303164701749917500E+033, 2.606329403499835000E+033,
5.212658806999670000E+033, 1.042531761399934000E+034, 2.085063522799868000E+034, 4.170127045599736000E+034,
8.340254091199472000E+034, 1.668050818239894400E+035, 3.336101636479788800E+035, 6.672203272959577600E+035
};
// You can use this to double check the exponent table and assert that
// the precomputation is correct.
#ifdef DBGFLAG_ASSERT
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning( disable : 4189 ) // disable unused local variable warning
#endif
#ifdef __GNUC__
__attribute__((unused)) static void CheckExponentTable()
#else
static void CheckExponentTable()
#endif
{
for( int i = 0; i < 256; i++ )
{
float testAgainst = pow( 2.0f, i - 128 ) / 255.0f;
float diff = testAgainst - power2_n[i] ;
float relativeDiff = diff / testAgainst;
Assert( sizeof(relativeDiff) > 0 && testAgainst == 0 ?
power2_n[i] < 1.16E-041 :
power2_n[i] == testAgainst );
}
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif
void BuildGammaTable( float gamma, float texGamma, float brightness, int overbright )
{
int i, inf;
float g1, g3;
// Con_Printf("BuildGammaTable %.1f %.1f %.1f\n", g, v_lightgamma.GetFloat(), v_texgamma.GetFloat() );
float g = gamma;
if (g > 3.0)
{
g = 3.0;
}
g = 1.0 / g;
g1 = texGamma * g;
if (brightness <= 0.0)
{
g3 = 0.125;
}
else if (brightness > 1.0)
{
g3 = 0.05;
}
else
{
g3 = 0.125 - (brightness * brightness) * 0.075;
}
for (i=0 ; i<256 ; i++)
{
inf = static_cast<int>(255 * pow ( i/255.f, g1 ));
if (inf < 0)
inf = 0;
if (inf > 255)
inf = 255;
texgammatable[i] = inf;
}
for (i=0 ; i<1024 ; i++)
{
float f;
f = i / 1023.0;
// scale up
if (brightness > 1.0)
f = f * brightness;
// shift up
if (f <= g3)
f = (f / g3) * 0.125;
else
f = 0.125 + ((f - g3) / (1.0 - g3)) * 0.875;
// convert linear space to desired gamma space
inf = static_cast<int>(255 * pow ( f, g ));
if (inf < 0)
inf = 0;
if (inf > 255)
inf = 255;
lineartoscreen[i] = inf;
}
/*
for (i=0 ; i<1024 ; i++)
{
// convert from screen gamma space to linear space
lineargammatable[i] = 1023 * pow ( i/1023.0, v_gamma.GetFloat() );
// convert from linear gamma space to screen space
screengammatable[i] = 1023 * pow ( i/1023.0, 1.0 / v_gamma.GetFloat() );
}
*/
for (i=0 ; i<256 ; i++)
{
// convert from nonlinear texture space (0..255) to linear space (0..1)
texturetolinear[i] = pow( i / 255.f, texGamma );
// convert from linear space (0..1) to nonlinear (sRGB) space (0..1)
g_Mathlib_LinearToGamma[i] = LinearToGammaFullRange( i / 255.f );
// convert from sRGB gamma space (0..1) to linear space (0..1)
g_Mathlib_GammaToLinear[i] = GammaToLinearFullRange( i / 255.f );
}
for (i=0 ; i<1024 ; i++)
{
// convert from linear space (0..1) to nonlinear texture space (0..255)
lineartotexture[i] = static_cast<int>(pow( i / 1023.0, 1.0 / texGamma ) * 255);
}
#if 0
for (i=0 ; i<256 ; i++)
{
float f;
// convert from nonlinear lightmap space (0..255) to linear space (0..4)
// f = (i / 255.0) * sqrt( 4 );
f = i * (2.0 / 255.0);
f = f * f;
texlighttolinear[i] = f;
}
#endif
{
float f;
float overbrightFactor = 1.0f;
// Can't do overbright without texcombine
// UNDONE: Add GAMMA ramp to rectify this
if ( overbright == 2 )
{
overbrightFactor = 0.5;
}
else if ( overbright == 4 )
{
overbrightFactor = 0.25;
}
for (i=0 ; i<4096 ; i++)
{
// convert from linear 0..4 (x1024) to screen corrected vertex space (0..1?)
f = pow ( i/1024.0, 1.0 / gamma );
lineartovertex[i] = f * overbrightFactor;
if (lineartovertex[i] > 1)
lineartovertex[i] = 1;
int nLightmap = RoundFloatToInt( f * 255 * overbrightFactor );
nLightmap = clamp( nLightmap, 0, 255 );
lineartolightmap[i] = (unsigned char)nLightmap;
}
}
}
float GammaToLinearFullRange( float gamma )
{
return pow( gamma, 2.2f );
}
float LinearToGammaFullRange( float linear )
{
return pow( linear, 1.0f / 2.2f );
}
float GammaToLinear( float gamma )
{
Assert( s_bMathlibInitialized );
if ( gamma < 0.0f )
{
return 0.0f;
}
if ( gamma >= 0.95f )
{
// Use GammaToLinearFullRange maybe if you trip this.
// X360TEMP
// Assert( gamma <= 1.0f );
return 1.0f;
}
int index = RoundFloatToInt( gamma * 255.0f );
Assert( index >= 0 && index < 256 );
return g_Mathlib_GammaToLinear[index];
}
float LinearToGamma( float linear )
{
Assert( s_bMathlibInitialized );
if ( linear < 0.0f )
{
return 0.0f;
}
if ( linear > 1.0f )
{
// Use LinearToGammaFullRange maybe if you trip this.
Assert( 0 );
return 1.0f;
}
int index = RoundFloatToInt( linear * 255.0f );
Assert( index >= 0 && index < 256 );
return g_Mathlib_LinearToGamma[index];
}
//-----------------------------------------------------------------------------
// Helper functions to convert between sRGB and 360 gamma space
//-----------------------------------------------------------------------------
float SrgbGammaToLinear( float flSrgbGammaValue )
{
float x = clamp( flSrgbGammaValue, 0.0f, 1.0f );
return ( x <= 0.04045f ) ? ( x / 12.92f ) : ( pow( ( x + 0.055f ) / 1.055f, 2.4f ) );
}
float SrgbLinearToGamma( float flLinearValue )
{
float x = clamp( flLinearValue, 0.0f, 1.0f );
return ( x <= 0.0031308f ) ? ( x * 12.92f ) : ( 1.055f * pow( x, ( 1.0f / 2.4f ) ) ) - 0.055f;
}
float X360GammaToLinear( float fl360GammaValue )
{
float flLinearValue;
fl360GammaValue = clamp( fl360GammaValue, 0.0f, 1.0f );
if ( fl360GammaValue < ( 96.0f / 255.0f ) )
{
if ( fl360GammaValue < ( 64.0f / 255.0f ) )
{
flLinearValue = fl360GammaValue * 255.0f;
}
else
{
flLinearValue = fl360GammaValue * ( 255.0f * 2.0f ) - 64.0f;
flLinearValue += floor( flLinearValue * ( 1.0f / 512.0f ) );
}
}
else
{
if( fl360GammaValue < ( 192.0f / 255.0f ) )
{
flLinearValue = fl360GammaValue * ( 255.0f * 4.0f ) - 256.0f;
flLinearValue += floor( flLinearValue * ( 1.0f / 256.0f ) );
}
else
{
flLinearValue = fl360GammaValue * ( 255.0f * 8.0f ) - 1024.0f;
flLinearValue += floor( flLinearValue * ( 1.0f / 128.0f ) );
}
}
flLinearValue *= 1.0f / 1023.0f;
flLinearValue = clamp( flLinearValue, 0.0f, 1.0f );
return flLinearValue;
}
float X360LinearToGamma( float flLinearValue )
{
float fl360GammaValue;
flLinearValue = clamp( flLinearValue, 0.0f, 1.0f );
if ( flLinearValue < ( 128.0f / 1023.0f ) )
{
if ( flLinearValue < ( 64.0f / 1023.0f ) )
{
fl360GammaValue = flLinearValue * ( 1023.0f * ( 1.0f / 255.0f ) );
}
else
{
fl360GammaValue = flLinearValue * ( ( 1023.0f / 2.0f ) * ( 1.0f / 255.0f ) ) + ( 32.0f / 255.0f );
}
}
else
{
if ( flLinearValue < ( 512.0f / 1023.0f ) )
{
fl360GammaValue = flLinearValue * ( ( 1023.0f / 4.0f ) * ( 1.0f / 255.0f ) ) + ( 64.0f / 255.0f );
}
else
{
fl360GammaValue = flLinearValue * ( ( 1023.0f /8.0f ) * ( 1.0f / 255.0f ) ) + ( 128.0f /255.0f ); // 1.0 -> 1.0034313725490196078431372549016
if ( fl360GammaValue > 1.0f )
{
fl360GammaValue = 1.0f;
}
}
}
fl360GammaValue = clamp( fl360GammaValue, 0.0f, 1.0f );
return fl360GammaValue;
}
float SrgbGammaTo360Gamma( float flSrgbGammaValue )
{
float flLinearValue = SrgbGammaToLinear( flSrgbGammaValue );
float fl360GammaValue = X360LinearToGamma( flLinearValue );
return fl360GammaValue;
}
// convert texture to linear 0..1 value
float TextureToLinear( int c )
{
Assert( s_bMathlibInitialized );
if (c < 0)
return 0;
if (c > 255)
return 1.0;
return texturetolinear[c];
}
// convert texture to linear 0..1 value
int LinearToTexture( float f )
{
Assert( s_bMathlibInitialized );
int i;
i = static_cast<int>(f * 1023); // assume 0..1 range
if (i < 0)
i = 0;
if (i > 1023)
i = 1023;
return lineartotexture[i];
}
// converts 0..1 linear value to screen gamma (0..255)
int LinearToScreenGamma( float f )
{
Assert( s_bMathlibInitialized );
int i;
i = static_cast<int>(f * 1023); // assume 0..1 range
if (i < 0)
i = 0;
if (i > 1023)
i = 1023;
return lineartoscreen[i];
}
void ColorRGBExp32ToVector( const ColorRGBExp32& in, Vector& out )
{
Assert( s_bMathlibInitialized );
// FIXME: Why is there a factor of 255 built into this?
out.x = 255.0f * TexLightToLinear( in.r, in.exponent );
out.y = 255.0f * TexLightToLinear( in.g, in.exponent );
out.z = 255.0f * TexLightToLinear( in.b, in.exponent );
}
#if 0
// assumes that the desired mantissa range is 128..255
static int VectorToColorRGBExp32_CalcExponent( float in )
{
int power = 0;
if( in != 0.0f )
{
while( in > 255.0f )
{
power += 1;
in *= 0.5f;
}
while( in < 128.0f )
{
power -= 1;
in *= 2.0f;
}
}
return power;
}
void VectorToColorRGBExp32( const Vector& vin, ColorRGBExp32 &c )
{
Vector v = vin;
Assert( s_bMathlibInitialized );
Assert( v.x >= 0.0f && v.y >= 0.0f && v.z >= 0.0f );
int i;
float max = v[0];
for( i = 1; i < 3; i++ )
{
// Get the maximum value.
if( v[i] > max )
{
max = v[i];
}
}
// figure out the exponent for this luxel.
int exponent = VectorToColorRGBExp32_CalcExponent( max );
// make the exponent fits into a signed byte.
if( exponent < -128 )
{
exponent = -128;
}
else if( exponent > 127 )
{
exponent = 127;
}
// undone: optimize with a table
float scalar = pow( 2.0f, -exponent );
// convert to mantissa x 2^exponent format
for( i = 0; i < 3; i++ )
{
v[i] *= scalar;
// clamp
if( v[i] > 255.0f )
{
v[i] = 255.0f;
}
}
c.r = ( unsigned char )v[0];
c.g = ( unsigned char )v[1];
c.b = ( unsigned char )v[2];
c.exponent = ( signed char )exponent;
}
#else
// given a floating point number f, return an exponent e such that
// for f' = f * 2^e, f is on [128..255].
// Uses IEEE 754 representation to directly extract this information
// from the float.
inline static int VectorToColorRGBExp32_CalcExponent( const float *pin )
{
// The thing we will take advantage of here is that the exponent component
// is stored in the float itself, and because we want to map to 128..255, we
// want an "ideal" exponent of 2^7. So, we compute the difference between the
// input exponent and 7 to work out the normalizing exponent. Thus if you pass in
// 32 (represented in IEEE 754 as 2^5), this function will return 2
// (because 32 * 2^2 = 128)
if (*pin == 0.0f)
return 0;
unsigned int fbits = *reinterpret_cast<const unsigned int *>(pin);
// the exponent component is bits 23..30, and biased by +127
const unsigned int biasedSeven = 7 + 127;
signed int expComponent = ( fbits & 0x7F800000 ) >> 23;
expComponent -= biasedSeven; // now the difference from seven (positive if was less than, etc)
return expComponent;
}
/// Slightly faster version of the function to turn a float-vector color into
/// a compressed-exponent notation 32bit color. However, still not SIMD optimized.
/// PS3 developer: note there is a movement of a float onto an int here, which is
/// bad on the base registers -- consider doing this as Altivec code, or better yet
/// moving it onto the cell.
/// \warning: Assumes an IEEE 754 single-precision float representation! Those of you
/// porting to an 8080 are out of luck.
void VectorToColorRGBExp32( const Vector& vin, ColorRGBExp32 &c )
{
Assert( s_bMathlibInitialized );
Assert( vin.x >= 0.0f && vin.y >= 0.0f && vin.z >= 0.0f );
// work out which of the channels is the largest ( we will use that to map the exponent )
// this is a sluggish branch-based decision tree -- most architectures will offer a [max]
// assembly opcode to do this faster.
const float *pMax;
if (vin.x > vin.y)
{
if (vin.x > vin.z)
{
pMax = &vin.x;
}
else
{
pMax = &vin.z;
}
}
else
{
if (vin.y > vin.z)
{
pMax = &vin.y;
}
else
{
pMax = &vin.z;
}
}
// now work out the exponent for this luxel.
signed int exponent = VectorToColorRGBExp32_CalcExponent( pMax );
// make sure the exponent fits into a signed byte.
// (in single precision format this is assured because it was a signed byte to begin with)
Assert(exponent > -128 && exponent <= 127);
// promote the exponent back onto a scalar that we'll use to normalize all the numbers
float scalar;
{
unsigned int fbits = (127 - exponent) << 23;
scalar = *reinterpret_cast<float *>(&fbits);
}
// we should never need to clamp:
Assert(vin.x * scalar <= 255.0f &&
vin.y * scalar <= 255.0f &&
vin.z * scalar <= 255.0f);
// This awful construction is necessary to prevent VC2005 from using the
// fldcw/fnstcw control words around every float-to-unsigned-char operation.
{
int red = static_cast<int>(vin.x * scalar);
int green = static_cast<int>(vin.y * scalar);
int blue = static_cast<int>(vin.z * scalar);
c.r = red;
c.g = green;
c.b = blue;
}
/*
c.r = ( unsigned char )(vin.x * scalar);
c.g = ( unsigned char )(vin.y * scalar);
c.b = ( unsigned char )(vin.z * scalar);
*/
c.exponent = ( signed char )exponent;
}
#endif

63
mathlib/datagen.pl Normal file
View File

@ -0,0 +1,63 @@
#! perl
use Text::Wrap;
# generate output data for noise generators
srand(31456);
print <<END
//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============//
//
// Purpose: static data for noise() primitives.
//
// \$Workfile: \$
// \$NoKeywords: \$
//=============================================================================//
//
// **** DO NOT EDIT THIS FILE. GENERATED BY DATAGEN.PL ****
//
END
;
@perm_a=0..255;
&fisher_yates_shuffle(\@perm_a);
$Text::Wrap::Columns=78;
$Text::Wrap::break=",";
$Text::Wrap::separator=",\n";
print "static int perm_a[]={\n",wrap(' ',' ',join(",",@perm_a)),"\n};\n\n";
&fisher_yates_shuffle(\@perm_a);
print "static int perm_b[]={\n",wrap(' ',' ',join(",",@perm_a)),"\n};\n\n";
&fisher_yates_shuffle(\@perm_a);
print "static int perm_c[]={\n",wrap(' ',' ',join(",",@perm_a)),"\n};\n\n";
&fisher_yates_shuffle(\@perm_a);
print "static int perm_d[]={\n",wrap(' ',' ',join(",",@perm_a)),"\n};\n\n";
for ($i=0;$i<256;$i++)
{
$float_perm=(1.0/255.0)*$perm_a[$i];
$perm_a[$i] = sprintf("%f",$float_perm);
}
&fisher_yates_shuffle(\@perm_a);
print "static float impulse_xcoords[]={\n",wrap(' ',' ',join(",",@perm_a)),"\n};\n\n";
&fisher_yates_shuffle(\@perm_a);
print "static float impulse_ycoords[]={\n",wrap(' ',' ',join(",",@perm_a)),"\n};\n\n";
&fisher_yates_shuffle(\@perm_a);
print "static float impulse_zcoords[]={\n",wrap(' ',' ',join(",",@perm_a)),"\n};\n\n";
# fisher_yates_shuffle( \@array ) : generate a random permutation
# of @array in place
sub fisher_yates_shuffle {
my $array = shift;
my $i;
for ($i = @$array; --$i; ) {
my $j = int rand ($i+1);
next if $i == $j;
@$array[$i,$j] = @$array[$j,$i];
}
}

30
mathlib/halton.cpp Normal file
View File

@ -0,0 +1,30 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#include <halton.h>
HaltonSequenceGenerator_t::HaltonSequenceGenerator_t(int b)
{
base=b;
fbase=(float) b;
seed=1;
}
float HaltonSequenceGenerator_t::GetElement(int elem)
{
int tmpseed=seed;
float ret=0.0;
float base_inv=1.0/fbase;
while(tmpseed)
{
int dig=tmpseed % base;
ret+=((float) dig)*base_inv;
base_inv/=fbase;
tmpseed/=base;
}
return ret;
}

95
mathlib/imagequant.cpp Normal file
View File

@ -0,0 +1,95 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include <quantize.h>
#define N_EXTRAVALUES 1
#define N_DIMENSIONS (3+N_EXTRAVALUES)
#define PIXEL(x,y,c) Image[4*((x)+((Width*(y))))+c]
static uint8 Weights[]={5,7,4,8};
static int ExtraValueXForms[3*N_EXTRAVALUES]={
76,151,28,
};
#define MAX_QUANTIZE_IMAGE_WIDTH 4096
void ColorQuantize(uint8 const *Image,
int Width,
int Height,
int flags, int ncolors,
uint8 *out_pixels,
uint8 *out_palette,
int firstcolor)
{
int Error[MAX_QUANTIZE_IMAGE_WIDTH+1][3][2];
struct Sample *s=AllocSamples(Width*Height,N_DIMENSIONS);
int x,y,c;
for(y=0;y<Height;y++)
for(x=0;x<Width;x++)
{
for(c=0;c<3;c++)
NthSample(s,y*Width+x,N_DIMENSIONS)->Value[c]=PIXEL(x,y,c);
// now, let's generate extra values to quantize on
for(int i=0;i<N_EXTRAVALUES;i++)
{
int val1=0;
for(c=0;c<3;c++)
val1+=PIXEL(x,y,c)*ExtraValueXForms[i*3+c];
val1>>=8;
NthSample(s,y*Width+x,N_DIMENSIONS)->Value[c]=(uint8)
(MIN(255,MAX(0,val1)));
}
}
struct QuantizedValue *q=Quantize(s,Width*Height,N_DIMENSIONS,
ncolors,Weights,firstcolor);
delete[] s;
memset(out_palette,0x55,768);
for(int p=0;p<256;p++)
{
struct QuantizedValue *v=FindQNode(q,p);
if (v)
for(int c=0;c<3;c++)
out_palette[p*3+c]=v->Mean[c];
}
memset(Error,0,sizeof(Error));
for(y=0;y<Height;y++)
{
int ErrorUse=y & 1;
int ErrorUpdate=ErrorUse^1;
for(x=0;x<Width;x++)
{
uint8 samp[3];
for(c=0;c<3;c++)
{
int tryc=PIXEL(x,y,c);
if (! (flags & QUANTFLAGS_NODITHER))
{
tryc+=Error[x][c][ErrorUse];
Error[x][c][ErrorUse]=0;
}
samp[c]=(uint8) MIN(255,MAX(0,tryc));
}
struct QuantizedValue *f=FindMatch(samp,3,Weights,q);
out_pixels[Width*y+x]=(uint8) (f->value);
if (! (flags & QUANTFLAGS_NODITHER))
for(int i=0;i<3;i++)
{
int newerr=samp[i]-f->Mean[i];
int orthog_error=(newerr*3)/8;
Error[x+1][i][ErrorUse]+=orthog_error;
Error[x][i][ErrorUpdate]=orthog_error;
Error[x+1][i][ErrorUpdate]=newerr-2*orthog_error;
}
}
}
if (q) FreeQuantization(q);
}

320
mathlib/lightdesc.cpp Normal file
View File

@ -0,0 +1,320 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#include <ssemath.h>
#include <lightdesc.h>
#include "mathlib.h"
void LightDesc_t::RecalculateDerivedValues(void)
{
m_Flags=0;
if (m_Attenuation0)
m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0;
if (m_Attenuation1)
m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1;
if (m_Attenuation2)
m_Flags|=LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2;
if (m_Type==MATERIAL_LIGHT_SPOT)
{
m_ThetaDot=cos(m_Theta);
m_PhiDot=cos(m_Phi);
float spread=m_ThetaDot-m_PhiDot;
if (spread>1.0e-10)
{
// note - this quantity is very sensitive to round off error. the sse
// reciprocal approximation won't cut it here.
OneOver_ThetaDot_Minus_PhiDot=1.0/spread;
}
else
{
// hard falloff instead of divide by zero
OneOver_ThetaDot_Minus_PhiDot=1.0;
}
}
if (m_Type==MATERIAL_LIGHT_DIRECTIONAL)
{
// set position to be real far away in the right direction
m_Position=m_Direction;
m_Position *= 2.0e6;
}
m_RangeSquared=m_Range*m_Range;
}
void LightDesc_t::ComputeLightAtPointsForDirectional(
const FourVectors &pos, const FourVectors &normal,
FourVectors &color, bool DoHalfLambert ) const
{
FourVectors delta;
delta.DuplicateVector(m_Direction);
// delta.VectorNormalizeFast();
fltx4 strength=delta*normal;
if (DoHalfLambert)
{
strength=AddSIMD(MulSIMD(strength,Four_PointFives),Four_PointFives);
}
else
strength=MaxSIMD(Four_Zeros,delta*normal);
color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(m_Color.x)));
color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(m_Color.y)));
color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(m_Color.z)));
}
void LightDesc_t::ComputeLightAtPoints( const FourVectors &pos, const FourVectors &normal,
FourVectors &color, bool DoHalfLambert ) const
{
FourVectors delta;
Assert((m_Type==MATERIAL_LIGHT_POINT) || (m_Type==MATERIAL_LIGHT_SPOT) || (m_Type==MATERIAL_LIGHT_DIRECTIONAL));
switch (m_Type)
{
case MATERIAL_LIGHT_POINT:
case MATERIAL_LIGHT_SPOT:
delta.DuplicateVector(m_Position);
delta-=pos;
break;
case MATERIAL_LIGHT_DIRECTIONAL:
ComputeLightAtPointsForDirectional( pos, normal, color, DoHalfLambert );
return;
default:
return;
}
fltx4 dist2 = delta*delta;
dist2=MaxSIMD( Four_Ones, dist2 );
fltx4 falloff;
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 )
{
falloff = ReplicateX4(m_Attenuation0);
}
else
falloff= Four_Epsilons;
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 )
{
falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation1),SqrtEstSIMD(dist2)));
}
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 )
{
falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation2),dist2));
}
falloff=ReciprocalEstSIMD(falloff);
// Cull out light beyond this radius
// now, zero out elements for which dist2 was > range^2. !!speed!! lights should store dist^2 in sse format
if (m_Range != 0.f)
{
fltx4 RangeSquared=ReplicateX4(m_RangeSquared); // !!speed!!
falloff=AndSIMD(falloff,CmpLtSIMD(dist2,RangeSquared));
}
delta.VectorNormalizeFast();
fltx4 strength=delta*normal;
if (DoHalfLambert)
{
strength=AddSIMD(MulSIMD(strength,Four_PointFives),Four_PointFives);
}
else
strength=MaxSIMD(Four_Zeros,delta*normal);
switch(m_Type)
{
case MATERIAL_LIGHT_POINT:
// half-lambert
break;
case MATERIAL_LIGHT_SPOT:
{
fltx4 dot2=SubSIMD(Four_Zeros,delta*m_Direction); // dot position with spot light dir for cone falloff
fltx4 cone_falloff_scale=MulSIMD(ReplicateX4(OneOver_ThetaDot_Minus_PhiDot),
SubSIMD(dot2,ReplicateX4(m_PhiDot)));
cone_falloff_scale=MinSIMD(cone_falloff_scale,Four_Ones);
if ((m_Falloff!=0.0) && (m_Falloff!=1.0))
{
// !!speed!! could compute integer exponent needed by powsimd and store in light
cone_falloff_scale=PowSIMD(cone_falloff_scale,m_Falloff);
}
strength=MulSIMD(cone_falloff_scale,strength);
// now, zero out lighting where dot2<phidot. This will mask out any invalid results
// from pow function, etc
fltx4 OutsideMask=CmpGtSIMD(dot2,ReplicateX4(m_PhiDot)); // outside light cone?
strength=AndSIMD(OutsideMask,strength);
}
break;
default:
break;
}
strength=MulSIMD(strength,falloff);
color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(m_Color.x)));
color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(m_Color.y)));
color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(m_Color.z)));
}
void LightDesc_t::ComputeNonincidenceLightAtPoints( const FourVectors &pos, FourVectors &color ) const
{
FourVectors delta;
Assert((m_Type==MATERIAL_LIGHT_POINT) || (m_Type==MATERIAL_LIGHT_SPOT) || (m_Type==MATERIAL_LIGHT_DIRECTIONAL));
switch (m_Type)
{
case MATERIAL_LIGHT_POINT:
case MATERIAL_LIGHT_SPOT:
delta.DuplicateVector(m_Position);
delta-=pos;
break;
case MATERIAL_LIGHT_DIRECTIONAL:
return;
default:
return;
}
fltx4 dist2 = delta*delta;
dist2=MaxSIMD( Four_Ones, dist2 );
fltx4 falloff;
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 )
{
falloff = ReplicateX4(m_Attenuation0);
}
else
falloff= Four_Epsilons;
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 )
{
falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation1),SqrtEstSIMD(dist2)));
}
if( m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 )
{
falloff=AddSIMD(falloff,MulSIMD(ReplicateX4(m_Attenuation2),dist2));
}
falloff=ReciprocalEstSIMD(falloff);
// Cull out light beyond this radius
// now, zero out elements for which dist2 was > range^2. !!speed!! lights should store dist^2 in sse format
if (m_Range != 0.f)
{
fltx4 RangeSquared=ReplicateX4(m_RangeSquared); // !!speed!!
falloff=AndSIMD(falloff,CmpLtSIMD(dist2,RangeSquared));
}
delta.VectorNormalizeFast();
fltx4 strength = Four_Ones;
//fltx4 strength=delta;
//fltx4 strength = MaxSIMD(Four_Zeros,delta);
switch(m_Type)
{
case MATERIAL_LIGHT_POINT:
// half-lambert
break;
case MATERIAL_LIGHT_SPOT:
{
fltx4 dot2=SubSIMD(Four_Zeros,delta*m_Direction); // dot position with spot light dir for cone falloff
fltx4 cone_falloff_scale=MulSIMD(ReplicateX4(OneOver_ThetaDot_Minus_PhiDot),
SubSIMD(dot2,ReplicateX4(m_PhiDot)));
cone_falloff_scale=MinSIMD(cone_falloff_scale,Four_Ones);
if ((m_Falloff!=0.0) && (m_Falloff!=1.0))
{
// !!speed!! could compute integer exponent needed by powsimd and store in light
cone_falloff_scale=PowSIMD(cone_falloff_scale,m_Falloff);
}
strength=MulSIMD(cone_falloff_scale,strength);
// now, zero out lighting where dot2<phidot. This will mask out any invalid results
// from pow function, etc
fltx4 OutsideMask=CmpGtSIMD(dot2,ReplicateX4(m_PhiDot)); // outside light cone?
strength=AndSIMD(OutsideMask,strength);
}
break;
default:
break;
}
strength=MulSIMD(strength,falloff);
color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(m_Color.x)));
color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(m_Color.y)));
color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(m_Color.z)));
}
void LightDesc_t::SetupOldStyleAttenuation( float fQuadraticAttn, float fLinearAttn, float fConstantAttn )
{
// old-style manually typed quadrtiac coefficients
if ( fQuadraticAttn < EQUAL_EPSILON )
fQuadraticAttn = 0;
if ( fLinearAttn < EQUAL_EPSILON)
fLinearAttn = 0;
if ( fConstantAttn < EQUAL_EPSILON)
fConstantAttn = 0;
if ( ( fConstantAttn < EQUAL_EPSILON ) &&
( fLinearAttn < EQUAL_EPSILON ) &&
( fQuadraticAttn < EQUAL_EPSILON ) )
fConstantAttn = 1;
m_Attenuation2=fQuadraticAttn;
m_Attenuation1=fLinearAttn;
m_Attenuation0=fConstantAttn;
float fScaleFactor = fQuadraticAttn * 10000 + fLinearAttn * 100 + fConstantAttn;
if ( fScaleFactor > 0 )
m_Color *= fScaleFactor;
}
void LightDesc_t::SetupNewStyleAttenuation( float fFiftyPercentDistance,
float fZeroPercentDistance )
{
// new style storing 50% and 0% distances
float d50=fFiftyPercentDistance;
float d0=fZeroPercentDistance;
if (d0<d50)
{
// !!warning in lib code???!!!
Warning("light has _fifty_percent_distance of %f but no zero_percent_distance\n",d50);
d0=2.0*d50;
}
float a=0,b=1,c=0;
if (! SolveInverseQuadraticMonotonic(0,1.0,d50,2.0,d0,256.0,a,b,c))
{
Warning("can't solve quadratic for light %f %f\n",d50,d0);
}
float v50=c+d50*(b+d50*a);
float scale=2.0/v50;
a*=scale;
b*=scale;
c*=scale;
m_Attenuation2=a;
m_Attenuation1=b;
m_Attenuation0=c;
}

407
mathlib/mathlib-2005.vcproj Normal file
View File

@ -0,0 +1,407 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="mathlib"
ProjectGUID="{884C66F2-7F84-4570-AE6C-B634C1113D69}"
RootNamespace="mathlib"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="4"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
CommandLine=""
ExcludedFromBuild="false"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
UseUnicodeResponseFiles="false"
Optimization="0"
AdditionalIncludeDirectories="..\public;..\public\tier0;..\public\tier1;..\public\mathlib"
PreprocessorDefinitions="WIN32;_WIN32;_DEBUG;DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
StringPooling="true"
MinimalRebuild="true"
ExceptionHandling="0"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
BufferSecurityCheck="false"
FloatingPointModel="2"
TreatWChar_tAsBuiltInType="true"
ForceConformanceInForLoopScope="true"
RuntimeTypeInfo="true"
OpenMP="false"
UsePrecompiledHeader="0"
ExpandAttributedSource="false"
AssemblerOutput="0"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/"
GenerateXMLDocumentationFiles="false"
BrowseInformation="0"
BrowseInformationFile="$(IntDir)/"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
CompileAs="2"
ErrorReporting="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
CommandLine=""
ExcludedFromBuild="false"
/>
<Tool
Name="VCLibrarianTool"
UseUnicodeResponseFiles="false"
OutputFile="..\lib\public\mathlib.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
SuppressStartupBanner="true"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile="$(OutDir)/mathlib.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
ExcludedFromBuild="false"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory=".\Release"
ConfigurationType="4"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
CommandLine=""
ExcludedFromBuild="false"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
UseUnicodeResponseFiles="false"
Optimization="2"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
AdditionalIncludeDirectories="..\public;..\public\tier0;..\public\tier1;..\public\mathlib"
PreprocessorDefinitions="WIN32;_WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
StringPooling="true"
ExceptionHandling="0"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="true"
FloatingPointModel="2"
TreatWChar_tAsBuiltInType="true"
ForceConformanceInForLoopScope="true"
RuntimeTypeInfo="true"
OpenMP="false"
UsePrecompiledHeader="0"
ExpandAttributedSource="false"
AssemblerOutput="0"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/"
GenerateXMLDocumentationFiles="false"
BrowseInformation="0"
BrowseInformationFile="$(IntDir)/"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="1"
CompileAs="2"
ErrorReporting="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
CommandLine=""
ExcludedFromBuild="false"
/>
<Tool
Name="VCLibrarianTool"
UseUnicodeResponseFiles="false"
OutputFile="..\lib\public\mathlib.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
SuppressStartupBanner="true"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile="$(OutDir)/mathlib.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
ExcludedFromBuild="false"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath=".\3dnow.cpp"
>
</File>
<File
RelativePath=".\anorms.cpp"
>
</File>
<File
RelativePath=".\bumpvects.cpp"
>
</File>
<File
RelativePath=".\color_conversion.cpp"
>
</File>
<File
RelativePath=".\halton.cpp"
>
</File>
<File
RelativePath=".\IceKey.cpp"
>
</File>
<File
RelativePath=".\imagequant.cpp"
>
</File>
<File
RelativePath=".\lightdesc.cpp"
>
</File>
<File
RelativePath=".\mathlib_base.cpp"
>
</File>
<File
RelativePath=".\polyhedron.cpp"
>
</File>
<File
RelativePath=".\powsse.cpp"
>
</File>
<File
RelativePath=".\quantize.cpp"
>
</File>
<File
RelativePath=".\randsse.cpp"
>
</File>
<File
RelativePath=".\simdvectormatrix.cpp"
>
</File>
<File
RelativePath=".\sparse_convolution_noise.cpp"
>
</File>
<File
RelativePath=".\sse.cpp"
>
</File>
<File
RelativePath=".\sseconst.cpp"
>
</File>
<File
RelativePath=".\ssenoise.cpp"
>
</File>
<File
RelativePath=".\vector.cpp"
>
</File>
<File
RelativePath=".\vmatrix.cpp"
>
</File>
</Filter>
<Filter
Name="Public Header Files"
Filter="h"
>
<File
RelativePath="..\public\mathlib\amd3dx.h"
>
</File>
<File
RelativePath="..\public\mathlib\anorms.h"
>
</File>
<File
RelativePath="..\public\mathlib\bumpvects.h"
>
</File>
<File
RelativePath="..\public\mathlib\compressed_3d_unitvec.h"
>
</File>
<File
RelativePath="..\public\mathlib\compressed_light_cube.h"
>
</File>
<File
RelativePath="..\public\mathlib\compressed_vector.h"
>
</File>
<File
RelativePath="..\public\mathlib\halton.h"
>
</File>
<File
RelativePath="..\public\mathlib\IceKey.H"
>
</File>
<File
RelativePath="..\public\mathlib\lightdesc.h"
>
</File>
<File
RelativePath="..\public\mathlib\math_pfns.h"
>
</File>
<File
RelativePath="..\public\mathlib\mathlib.h"
>
</File>
<File
RelativePath="..\public\mathlib\noise.h"
>
</File>
<File
RelativePath="..\public\mathlib\polyhedron.h"
>
</File>
<File
RelativePath="..\public\mathlib\quantize.h"
>
</File>
<File
RelativePath="..\public\mathlib\simdvectormatrix.h"
>
</File>
<File
RelativePath="..\public\mathlib\ssemath.h"
>
</File>
<File
RelativePath="..\public\mathlib\ssequaternion.h"
>
</File>
<File
RelativePath="..\public\mathlib\vector.h"
>
</File>
<File
RelativePath="..\public\mathlib\vector2d.h"
>
</File>
<File
RelativePath="..\public\mathlib\vector4d.h"
>
</File>
<File
RelativePath="..\public\mathlib\vmatrix.h"
>
</File>
<File
RelativePath="..\public\mathlib\vplane.h"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath=".\3dnow.h"
>
</File>
<File
RelativePath=".\noisedata.h"
>
</File>
<File
RelativePath=".\sse.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

4090
mathlib/mathlib_base.cpp Normal file

File diff suppressed because it is too large Load Diff

180
mathlib/noisedata.h Normal file
View File

@ -0,0 +1,180 @@
//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============//
//
// Purpose: static data for noise() primitives.
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
//
// **** DO NOT EDIT THIS FILE. GENERATED BY DATAGEN.PL ****
//
static const int perm_a[]={
66,147,106,213,89,115,239,25,171,175,9,114,141,226,118,128,41,208,4,56,
180,248,43,82,246,219,94,245,133,131,222,103,160,130,168,145,238,38,23,6,
236,67,99,2,70,232,80,209,1,3,68,65,102,210,13,73,55,252,187,170,22,36,
52,181,117,163,46,79,166,224,148,75,113,95,156,185,220,164,51,142,161,35,
206,251,45,136,197,190,132,32,218,127,63,27,137,93,242,20,189,108,183,
122,139,191,249,253,87,98,69,0,144,64,24,214,97,116,158,42,107,15,53,212,
83,111,152,240,74,237,62,77,205,149,26,151,178,204,91,176,234,49,154,203,
33,221,125,134,165,124,86,39,37,60,150,157,179,109,110,44,159,153,5,100,
10,207,40,186,96,215,143,162,230,184,101,54,174,247,76,59,241,223,192,84,
104,78,169,146,138,30,48,85,233,19,29,92,126,17,199,250,31,81,188,225,28,
112,88,11,182,173,211,129,194,172,14,120,200,167,135,12,177,227,229,155,
201,61,105,195,193,244,235,58,8,196,123,254,16,18,50,121,71,243,90,57,
202,119,255,47,7,198,228,21,217,216,231,140,72,34
};
static const int perm_b[]={
123,108,201,64,40,75,24,221,137,110,191,142,9,69,230,83,7,247,51,54,115,
133,180,248,109,116,62,99,251,55,89,253,65,106,228,167,131,132,58,143,
97,102,163,202,149,234,12,117,174,94,121,74,32,113,20,60,159,182,204,29,
244,118,3,178,255,38,6,114,36,93,30,134,213,90,245,209,88,232,162,125,
84,166,70,136,208,231,27,71,157,80,76,0,170,225,203,176,33,161,196,128,
252,236,246,2,138,1,250,197,77,243,218,242,19,164,68,212,14,237,144,63,
46,103,177,188,85,223,8,160,222,4,216,219,35,15,44,23,126,127,100,226,
235,37,168,101,49,22,11,73,61,135,111,183,72,96,185,239,82,18,50,155,
186,153,17,233,146,156,107,5,254,10,192,198,148,207,104,13,124,48,95,
129,120,206,199,81,249,91,150,210,119,240,122,194,92,34,28,205,175,227,
179,220,140,152,79,26,195,47,66,173,169,241,53,184,187,145,112,238,214,
147,98,171,229,200,151,25,67,78,189,217,130,224,57,172,59,41,43,16,105,
158,165,21,45,56,141,139,215,190,86,42,52,39,87,181,31,154,193,211
};
static const int perm_c[]={
97,65,96,25,122,26,219,85,148,251,102,0,140,130,136,213,138,60,236,52,
178,131,115,183,144,78,147,168,39,45,169,70,57,146,67,142,252,216,28,54,
86,222,194,200,48,5,205,125,214,56,181,255,196,155,37,218,153,208,66,
242,73,248,206,61,62,246,177,2,197,107,162,152,89,41,6,160,94,8,201,38,
235,228,165,93,111,239,74,231,121,47,166,221,157,64,77,244,29,105,150,
123,190,191,225,118,133,42,10,84,185,159,124,132,240,180,44,1,9,19,99,
254,12,207,186,71,234,184,11,20,16,193,139,175,98,59,113,27,170,230,91,
187,46,156,249,108,195,171,114,14,188,82,192,233,24,32,241,87,164,90,43,
163,245,92,40,215,55,226,15,3,112,158,250,172,22,227,137,35,128,145,247,
161,119,80,217,189,81,7,63,202,120,223,83,179,4,106,199,229,95,53,50,33,
182,72,143,23,243,75,18,173,141,167,198,204,58,174,237,17,129,238,127,
31,101,176,36,30,110,209,34,203,135,232,68,149,49,134,126,212,79,76,117,
104,210,211,224,253,100,220,109,116,88,13,151,154,69,21,51,103
};
static const int perm_d[]={
94,234,145,235,151,166,187,238,4,5,128,115,87,107,229,175,190,108,218,
32,17,220,97,90,122,121,71,109,64,227,225,75,81,19,27,162,3,89,139,69,
92,26,48,215,116,191,114,2,104,157,66,39,1,127,96,124,30,0,82,233,219,
42,131,173,35,201,182,144,14,98,148,244,160,159,179,91,31,68,119,154,
205,113,149,167,44,60,18,228,251,245,43,10,80,15,129,67,181,174,6,45,
194,237,213,52,99,232,211,212,164,217,57,153,156,102,134,20,249,132,55,
204,65,33,231,85,61,37,163,193,189,170,226,63,168,236,165,224,242,195,
41,200,40,70,112,100,36,172,130,74,137,252,243,135,230,161,207,16,146,
198,118,150,24,29,250,188,25,209,103,23,105,47,7,46,133,83,184,50,79,
110,120,53,253,206,214,9,240,101,147,152,183,254,59,126,216,197,171,51,
208,248,202,58,176,28,72,177,185,141,12,11,56,222,86,178,155,223,88,111,
73,142,210,138,239,221,199,192,84,93,241,125,76,77,255,95,8,78,247,186,
123,196,13,140,180,143,54,106,136,34,62,169,38,117,22,21,49,203,158,246
};
static const float impulse_xcoords[]={
0.788235,0.541176,0.972549,0.082353,0.352941,0.811765,0.286275,0.752941,
0.203922,0.705882,0.537255,0.886275,0.580392,0.137255,0.800000,0.533333,
0.117647,0.447059,0.129412,0.925490,0.086275,0.478431,0.666667,0.568627,
0.678431,0.313725,0.321569,0.349020,0.988235,0.419608,0.898039,0.219608,
0.243137,0.623529,0.501961,0.772549,0.952941,0.517647,0.949020,0.701961,
0.454902,0.505882,0.564706,0.960784,0.207843,0.007843,0.831373,0.184314,
0.576471,0.462745,0.572549,0.247059,0.262745,0.694118,0.615686,0.121569,
0.384314,0.749020,0.145098,0.717647,0.415686,0.607843,0.105882,0.101961,
0.200000,0.807843,0.521569,0.780392,0.466667,0.552941,0.996078,0.627451,
0.992157,0.529412,0.407843,0.011765,0.709804,0.458824,0.058824,0.819608,
0.176471,0.317647,0.392157,0.223529,0.156863,0.490196,0.325490,0.074510,
0.239216,0.164706,0.890196,0.603922,0.921569,0.839216,0.854902,0.098039,
0.686275,0.843137,0.152941,0.372549,0.062745,0.474510,0.486275,0.227451,
0.400000,0.298039,0.309804,0.274510,0.054902,0.815686,0.647059,0.635294,
0.662745,0.976471,0.094118,0.509804,0.650980,0.211765,0.180392,0.003922,
0.827451,0.278431,0.023529,0.525490,0.450980,0.725490,0.690196,0.941176,
0.639216,0.560784,0.196078,0.364706,0.043137,0.494118,0.796078,0.113725,
0.760784,0.729412,0.258824,0.290196,0.584314,0.674510,0.823529,0.905882,
0.917647,0.070588,0.862745,0.345098,0.913725,0.937255,0.031373,0.215686,
0.768627,0.333333,0.411765,0.423529,0.945098,0.721569,0.039216,0.792157,
0.956863,0.266667,0.254902,0.047059,0.294118,0.658824,0.250980,1.000000,
0.984314,0.756863,0.027451,0.305882,0.835294,0.513725,0.360784,0.776471,
0.611765,0.192157,0.866667,0.858824,0.592157,0.803922,0.141176,0.435294,
0.588235,0.619608,0.341176,0.109804,0.356863,0.270588,0.737255,0.847059,
0.050980,0.764706,0.019608,0.870588,0.933333,0.784314,0.549020,0.337255,
0.631373,0.929412,0.231373,0.427451,0.078431,0.498039,0.968627,0.654902,
0.125490,0.698039,0.015686,0.878431,0.713725,0.368627,0.431373,0.874510,
0.403922,0.556863,0.443137,0.964706,0.909804,0.301961,0.035294,0.850980,
0.882353,0.741176,0.380392,0.133333,0.470588,0.643137,0.282353,0.396078,
0.980392,0.168627,0.149020,0.235294,0.670588,0.596078,0.733333,0.160784,
0.376471,0.682353,0.545098,0.482353,0.745098,0.894118,0.188235,0.329412,
0.439216,0.901961,0.000000,0.600000,0.388235,0.172549,0.090196,0.066667
};
static const float impulse_ycoords[]={
0.827451,0.337255,0.941176,0.886275,0.878431,0.239216,0.400000,0.164706,
0.490196,0.411765,0.964706,0.349020,0.803922,0.317647,0.647059,0.431373,
0.933333,0.156863,0.094118,0.219608,0.039216,0.521569,0.498039,0.705882,
0.717647,0.047059,0.631373,0.517647,0.984314,0.847059,0.482353,0.439216,
0.250980,0.862745,0.690196,0.913725,0.270588,0.070588,0.027451,0.694118,
0.811765,0.000000,0.494118,0.823529,0.800000,0.600000,0.003922,0.443137,
0.639216,0.376471,0.031373,0.035294,0.552941,0.215686,0.305882,0.133333,
0.564706,0.176471,0.211765,0.874510,0.360784,0.654902,0.223529,0.807843,
0.372549,0.137255,0.321569,0.015686,0.007843,0.262745,0.125490,0.078431,
0.396078,0.976471,0.929412,1.000000,0.937255,0.509804,0.188235,0.850980,
0.831373,0.392157,0.741176,0.541176,0.592157,0.286275,0.345098,0.572549,
0.537255,0.725490,0.839216,0.184314,0.772549,0.149020,0.505882,0.423529,
0.780392,0.011765,0.890196,0.086275,0.427451,0.023529,0.788235,0.050980,
0.760784,0.603922,0.066667,0.643137,0.623529,0.960784,0.172549,0.333333,
0.082353,0.290196,0.992157,0.709804,0.894118,0.596078,0.243137,0.752941,
0.486275,0.670588,0.949020,0.784314,0.145098,0.560784,0.513725,0.180392,
0.580392,0.996078,0.380392,0.556863,0.407843,0.945098,0.117647,0.058824,
0.678431,0.129412,0.192157,0.105882,0.968627,0.545098,0.462745,0.227451,
0.019608,0.866667,0.674510,0.207843,0.627451,0.819608,0.921569,0.356863,
0.447059,0.533333,0.435294,0.341176,0.054902,0.529412,0.235294,0.764706,
0.615686,0.043137,0.745098,0.266667,0.501961,0.619608,0.776471,0.450980,
0.309804,0.325490,0.200000,0.635294,0.247059,0.698039,0.721569,0.168627,
0.854902,0.141176,0.611765,0.525490,0.415686,0.298039,0.254902,0.858824,
0.568627,0.329412,0.062745,0.843137,0.588235,0.733333,0.607843,0.478431,
0.576471,0.662745,0.470588,0.666667,0.980392,0.113725,0.898039,0.203922,
0.294118,0.152941,0.098039,0.909804,0.796078,0.768627,0.713725,0.196078,
0.368627,0.419608,0.352941,0.090196,0.749020,0.121569,0.882353,0.278431,
0.388235,0.917647,0.701961,0.729412,0.835294,0.258824,0.301961,0.101961,
0.792157,0.474510,0.686275,0.658824,0.364706,0.682353,0.458824,0.815686,
0.282353,0.160784,0.870588,0.988235,0.756863,0.549020,0.274510,0.384314,
0.650980,0.737255,0.901961,0.956863,0.972549,0.584314,0.925490,0.403922,
0.074510,0.454902,0.952941,0.109804,0.313725,0.905882,0.231373,0.466667
};
static const float impulse_zcoords[]={
0.082353,0.643137,0.415686,0.929412,0.568627,0.509804,0.537255,0.815686,
0.698039,0.941176,0.776471,0.752941,0.737255,0.525490,0.498039,0.423529,
0.792157,0.125490,0.619608,0.164706,0.368627,0.870588,0.137255,0.372549,
0.466667,0.486275,0.501961,0.513725,0.709804,0.576471,0.203922,0.258824,
0.152941,0.556863,0.223529,0.047059,0.235294,0.474510,0.764706,0.552941,
0.847059,0.145098,0.176471,0.937255,0.654902,0.894118,0.729412,0.054902,
0.666667,0.749020,0.262745,0.560784,0.431373,0.286275,0.352941,0.239216,
0.156863,0.839216,0.427451,0.949020,0.384314,0.227451,0.180392,0.074510,
0.172549,0.356863,0.066667,0.517647,0.447059,0.184314,0.062745,0.670588,
0.603922,0.219608,0.270588,0.976471,0.505882,0.627451,0.819608,0.854902,
0.843137,0.019608,0.713725,0.035294,0.925490,0.349020,0.866667,0.701961,
0.909804,0.811765,0.717647,0.141176,0.917647,0.023529,0.098039,0.803922,
0.733333,0.658824,0.827451,0.133333,0.858824,0.800000,0.635294,1.000000,
0.078431,0.450980,0.835294,0.321569,0.360784,0.529412,0.725490,0.572549,
0.639216,0.341176,0.533333,0.094118,0.149020,0.545098,0.101961,0.901961,
0.278431,0.694118,0.521569,0.490196,0.454902,0.329412,0.274510,0.027451,
0.745098,0.933333,0.443137,0.168627,0.192157,0.988235,0.070588,0.972549,
0.768627,0.400000,0.470588,0.207843,0.215686,0.388235,0.439216,0.780392,
0.482353,0.121569,0.964706,0.086275,0.890196,0.337255,0.109804,0.305882,
0.113725,0.435294,0.721569,0.772549,0.807843,0.741176,0.254902,0.596078,
0.494118,0.317647,0.419608,0.000000,0.188235,0.031373,0.376471,0.380392,
0.611765,0.945098,0.411765,0.313725,0.874510,0.588235,0.678431,0.160784,
0.007843,0.090196,0.850980,0.788235,0.705882,0.266667,0.309804,0.541176,
0.231373,0.129412,0.294118,0.243137,0.913725,0.996078,0.117647,0.478431,
0.290196,0.549020,0.682353,0.784314,0.396078,0.831373,0.984314,0.584314,
0.039216,0.250980,0.600000,0.392157,0.298039,0.050980,0.364706,0.105882,
0.623529,0.886275,0.980392,0.325490,0.247059,0.690196,0.674510,0.960784,
0.647059,0.211765,0.882353,0.686275,0.823529,0.058824,0.956863,0.043137,
0.345098,0.301961,0.592157,0.862745,0.607843,0.458824,0.282353,0.003922,
0.580392,0.760784,0.564706,0.011765,0.968627,0.905882,0.756863,0.952941,
0.662745,0.015686,0.898039,0.196078,0.333333,0.992157,0.650980,0.407843,
0.796078,0.615686,0.878431,0.921569,0.631373,0.200000,0.403922,0.462745
};

2294
mathlib/polyhedron.cpp Normal file

File diff suppressed because it is too large Load Diff

39
mathlib/powsse.cpp Normal file
View File

@ -0,0 +1,39 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#include "mathlib/ssemath.h"
fltx4 Pow_FixedPoint_Exponent_SIMD( const fltx4 & x, int exponent)
{
fltx4 rslt=Four_Ones; // x^0=1.0
int xp=abs(exponent);
if (xp & 3) // fraction present?
{
fltx4 sq_rt=SqrtEstSIMD(x);
if (xp & 1) // .25?
rslt=SqrtEstSIMD(sq_rt); // x^.25
if (xp & 2)
rslt=MulSIMD(rslt,sq_rt);
}
xp>>=2; // strip fraction
fltx4 curpower=x; // curpower iterates through x,x^2,x^4,x^8,x^16...
while(1)
{
if (xp & 1)
rslt=MulSIMD(rslt,curpower);
xp>>=1;
if (xp)
curpower=MulSIMD(curpower,curpower);
else
break;
}
if (exponent<0)
return ReciprocalEstSIMD(rslt); // pow(x,-b)=1/pow(x,b)
else
return rslt;
}

678
mathlib/quantize.cpp Normal file
View File

@ -0,0 +1,678 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef STDIO_H
#include <stdio.h>
#endif
#ifndef STRING_H
#include <string.h>
#endif
#ifndef QUANTIZE_H
#include <quantize.h>
#endif
#include <stdlib.h>
#include <math.h>
static int current_ndims;
static struct QuantizedValue *current_root;
static int current_ssize;
static uint8 *current_weights;
double SquaredError;
#define SPLIT_THEN_SORT 1
#define SQ(x) ((x)*(x))
static struct QuantizedValue *AllocQValue(void)
{
struct QuantizedValue *ret=new QuantizedValue;
ret->Samples=0;
ret->Children[0]=ret->Children[1]=0;
ret->NSamples=0;
ret->ErrorMeasure=new double[current_ndims];
ret->Mean=new uint8[current_ndims];
ret->Mins=new uint8[current_ndims];
ret->Maxs=new uint8[current_ndims];
ret->Sums=new int [current_ndims];
memset(ret->Sums,0,sizeof(int)*current_ndims);
ret->NQuant=0;
ret->sortdim=-1;
return ret;
}
void FreeQuantization(struct QuantizedValue *t)
{
if (t)
{
delete[] t->ErrorMeasure;
delete[] t->Mean;
delete[] t->Mins;
delete[] t->Maxs;
FreeQuantization(t->Children[0]);
FreeQuantization(t->Children[1]);
delete[] t->Sums;
delete[] t;
}
}
static int QNumSort(void const *a, void const *b)
{
int32 as=((struct Sample *) a)->QNum;
int32 bs=((struct Sample *) b)->QNum;
if (as==bs) return 0;
return (as>bs)?1:-1;
}
#if SPLIT_THEN_SORT
#else
static int current_sort_dim;
static int samplesort(void const *a, void const *b)
{
uint8 as=((struct Sample *) a)->Value[current_sort_dim];
uint8 bs=((struct Sample *) b)->Value[current_sort_dim];
if (as==bs) return 0;
return (as>bs)?1:-1;
}
#endif
static int sortlong(void const *a, void const *b)
{
// treat the entire vector of values as a long integer for duplicate removal.
return memcmp(((struct Sample *) a)->Value,
((struct Sample *) b)->Value,current_ndims);
}
#define NEXTSAMPLE(s) ( (struct Sample *) (((uint8 *) s)+current_ssize))
#define SAMPLE(s,i) NthSample(s,i,current_ndims)
static void SetNDims(int n)
{
current_ssize=sizeof(struct Sample)+(n-1);
current_ndims=n;
}
int CompressSamples(struct Sample *s, int nsamples, int ndims)
{
SetNDims(ndims);
qsort(s,nsamples,current_ssize,sortlong);
// now, they are all sorted by treating all dimensions as a large number.
// we may now remove duplicates.
struct Sample *src=s;
struct Sample *dst=s;
struct Sample *lastdst=dst;
dst=NEXTSAMPLE(dst); // copy first sample to get the ball rolling
src=NEXTSAMPLE(src);
int noutput=1;
while(--nsamples) // while some remain
{
if (memcmp(src->Value,lastdst->Value,current_ndims))
{
// yikes, a difference has been found!
memcpy(dst,src,current_ssize);
lastdst=dst;
dst=NEXTSAMPLE(dst);
noutput++;
}
else
lastdst->Count++;
src=NEXTSAMPLE(src);
}
return noutput;
}
void PrintSamples(struct Sample const *s, int nsamples, int ndims)
{
SetNDims(ndims);
int cnt=0;
while(nsamples--)
{
printf("sample #%d, count=%d, values=\n { ",cnt++,s->Count);
for(int d=0;d<ndims;d++)
printf("%02x,",s->Value[d]);
printf("}\n");
s=NEXTSAMPLE(s);
}
}
void PrintQTree(struct QuantizedValue const *p,int idlevel)
{
int i;
if (p)
{
for(i=0;i<idlevel;i++)
printf(" ");
printf("node=%p NSamples=%d value=%d Mean={",p,p->NSamples,p->value);
for(i=0;i<current_ndims;i++)
printf("%x,",p->Mean[i]);
printf("}\n");
for(i=0;i<idlevel;i++)
printf(" ");
printf("Errors={");
for(i=0;i<current_ndims;i++)
printf("%f,",p->ErrorMeasure[i]);
printf("}\n");
for(i=0;i<idlevel;i++)
printf(" ");
printf("Mins={");
for(i=0;i<current_ndims;i++)
printf("%d,",p->Mins[i]);
printf("} Maxs={");
for(i=0;i<current_ndims;i++)
printf("%d,",p->Maxs[i]);
printf("}\n");
PrintQTree(p->Children[0],idlevel+2);
PrintQTree(p->Children[1],idlevel+2);
}
}
static void UpdateStats(struct QuantizedValue *v)
{
// first, find mean
int32 Means[MAXDIMS];
double Errors[MAXDIMS];
double WorstError[MAXDIMS];
int i,j;
memset(Means,0,sizeof(Means));
int N=0;
for(i=0;i<v->NSamples;i++)
{
struct Sample *s=SAMPLE(v->Samples,i);
N+=s->Count;
for(j=0;j<current_ndims;j++)
{
uint8 v=s->Value[j];
Means[j]+=v*s->Count;
}
}
for(j=0;j<current_ndims;j++)
{
if (N) v->Mean[j]=(uint8) (Means[j]/N);
Errors[j]=WorstError[j]=0.;
}
for(i=0;i<v->NSamples;i++)
{
struct Sample *s=SAMPLE(v->Samples,i);
double c=s->Count;
for(j=0;j<current_ndims;j++)
{
double diff=SQ(s->Value[j]-v->Mean[j]);
Errors[j]+=c*diff; // charles uses abs not sq()
if (diff>WorstError[j])
WorstError[j]=diff;
}
}
v->TotalError=0.;
double ErrorScale=1.; // /sqrt((double) (N));
for(j=0;j<current_ndims;j++)
{
v->ErrorMeasure[j]=(ErrorScale*Errors[j]*current_weights[j]);
v->TotalError+=v->ErrorMeasure[j];
#if SPLIT_THEN_SORT
v->ErrorMeasure[j]*=WorstError[j];
#endif
}
v->TotSamples=N;
}
static int ErrorDim;
static double ErrorVal;
static struct QuantizedValue *ErrorNode;
static void UpdateWorst(struct QuantizedValue *q)
{
if (q->Children[0])
{
// not a leaf node
UpdateWorst(q->Children[0]);
UpdateWorst(q->Children[1]);
}
else
{
if (q->TotalError>ErrorVal)
{
ErrorVal=q->TotalError;
ErrorNode=q;
ErrorDim=0;
for(int d=0;d<current_ndims;d++)
if (q->ErrorMeasure[d]>q->ErrorMeasure[ErrorDim])
ErrorDim=d;
}
}
}
static int FindWorst(void)
{
ErrorVal=-1.;
UpdateWorst(current_root);
return (ErrorVal>0);
}
static void SubdivideNode(struct QuantizedValue *n, int whichdim)
{
int NAdded=0;
int i;
#if SPLIT_THEN_SORT
// we will try the "split then sort" method. This works by finding the
// means for all samples above and below the mean along the given axis.
// samples are then split into two groups, with the selection based upon
// which of the n-dimensional means the sample is closest to.
double LocalMean[MAXDIMS][2];
int totsamps[2];
for(i=0;i<current_ndims;i++)
LocalMean[i][0]=LocalMean[i][1]=0.;
totsamps[0]=totsamps[1]=0;
uint8 minv=255;
uint8 maxv=0;
struct Sample *minS=0,*maxS=0;
for(i=0;i<n->NSamples;i++)
{
uint8 v;
int whichside=1;
struct Sample *sl;
sl=SAMPLE(n->Samples,i);
v=sl->Value[whichdim];
if (v<minv) { minv=v; minS=sl; }
if (v>maxv) { maxv=v; maxS=sl; }
if (v<n->Mean[whichdim])
whichside=0;
totsamps[whichside]+=sl->Count;
for(int d=0;d<current_ndims;d++)
LocalMean[d][whichside]+=
sl->Count*sl->Value[d];
}
if (totsamps[0] && totsamps[1])
for(i=0;i<current_ndims;i++)
{
LocalMean[i][0]/=totsamps[0];
LocalMean[i][1]/=totsamps[1];
}
else
{
// it is possible that the clustering failed to split the samples.
// this can happen with a heavily biased sample (i.e. all black
// with a few stars). If this happens, we will cluster around the
// extrema instead. LocalMean[i][0] will be the point with the lowest
// value on the dimension and LocalMean[i][1] the one with the lowest
// value.
for(int i=0;i<current_ndims;i++)
{
LocalMean[i][0]=minS->Value[i];
LocalMean[i][1]=maxS->Value[i];
}
}
// now, we have 2 n-dimensional means. We will label each sample
// for which one it is nearer to by using the QNum field.
for(i=0;i<n->NSamples;i++)
{
double dist[2];
dist[0]=dist[1]=0.;
struct Sample *s=SAMPLE(n->Samples,i);
for(int d=0;d<current_ndims;d++)
for(int w=0;w<2;w++)
dist[w]+=current_weights[d]*SQ(LocalMean[d][w]-s->Value[d]);
s->QNum=(dist[0]<dist[1]);
}
// hey ho! we have now labelled each one with a candidate bin. Let's
// sort the array by moving the 0-labelled ones to the head of the array.
n->sortdim=-1;
qsort(n->Samples,n->NSamples,current_ssize,QNumSort);
for(i=0;i<n->NSamples;i++,NAdded++)
if (SAMPLE(n->Samples,i)->QNum)
break;
#else
if (whichdim != n->sortdim)
{
current_sort_dim=whichdim;
qsort(n->Samples,n->NSamples,current_ssize,samplesort);
n->sortdim=whichdim;
}
// now, the samples are sorted along the proper dimension. we need
// to find the place to cut in order to split the node. this is
// complicated by the fact that each sample entry can represent many
// samples. What we will do is start at the beginning of the array,
// adding samples to the first node, until either the number added
// is >=TotSamples/2, or there is only one left.
int TotAdded=0;
for(;;)
{
if (NAdded==n->NSamples-1)
break;
if (TotAdded>=n->TotSamples/2)
break;
TotAdded+=SAMPLE(n->Samples,NAdded)->Count;
NAdded++;
}
#endif
struct QuantizedValue *a=AllocQValue();
a->sortdim=n->sortdim;
a->Samples=n->Samples;
a->NSamples=NAdded;
n->Children[0]=a;
UpdateStats(a);
a=AllocQValue();
a->Samples=SAMPLE(n->Samples,NAdded);
a->NSamples=n->NSamples-NAdded;
a->sortdim=n->sortdim;
n->Children[1]=a;
UpdateStats(a);
}
static int colorid=0;
static void Label(struct QuantizedValue *q, int updatecolor)
{
// fill in max/min values for tree, etc.
if (q)
{
Label(q->Children[0],updatecolor);
Label(q->Children[1],updatecolor);
if (! q->Children[0]) // leaf node?
{
if (updatecolor)
{
q->value=colorid++;
for(int j=0;j<q->NSamples;j++)
{
SAMPLE(q->Samples,j)->QNum=q->value;
SAMPLE(q->Samples,j)->qptr=q;
}
}
for(int i=0;i<current_ndims;i++)
{
q->Mins[i]=q->Mean[i];
q->Maxs[i]=q->Mean[i];
}
}
else
for(int i=0;i<current_ndims;i++)
{
q->Mins[i]=MIN(q->Children[0]->Mins[i],q->Children[1]->Mins[i]);
q->Maxs[i]=MAX(q->Children[0]->Maxs[i],q->Children[1]->Maxs[i]);
}
}
}
struct QuantizedValue *FindQNode(struct QuantizedValue const *q, int32 code)
{
if (! (q->Children[0]))
if (code==q->value) return (struct QuantizedValue *) q;
else return 0;
else
{
struct QuantizedValue *found=FindQNode(q->Children[0],code);
if (! found) found=FindQNode(q->Children[1],code);
return found;
}
}
void CheckInRange(struct QuantizedValue *q, uint8 *max, uint8 *min)
{
if (q)
{
if (q->Children[0])
{
// non-leaf node
CheckInRange(q->Children[0],q->Maxs, q->Mins);
CheckInRange(q->Children[1],q->Maxs, q->Mins);
CheckInRange(q->Children[0],max, min);
CheckInRange(q->Children[1],max, min);
}
for (int i=0;i<current_ndims;i++)
{
if (q->Maxs[i]>max[i]) printf("error1\n");
if (q->Mins[i]<min[i]) printf("error2\n");
}
}
}
struct QuantizedValue *Quantize(struct Sample *s, int nsamples, int ndims,
int nvalues, uint8 *weights, int firstvalue)
{
SetNDims(ndims);
current_weights=weights;
current_root=AllocQValue();
current_root->Samples=s;
current_root->NSamples=nsamples;
UpdateStats(current_root);
while(--nvalues)
{
if (! FindWorst())
break; // if <n unique ones, stop now
SubdivideNode(ErrorNode,ErrorDim);
}
colorid=firstvalue;
Label(current_root,1);
return current_root;
}
double MinimumError(struct QuantizedValue const *q, uint8 const *sample,
int ndims, uint8 const *weights)
{
double err=0;
for(int i=0;i<ndims;i++)
{
int val1;
int val2=sample[i];
if ((q->Mins[i]<=val2) && (q->Maxs[i]>=val2)) val1=val2;
else
{
val1=(val2<=q->Mins[i])?q->Mins[i]:q->Maxs[i];
}
err+=weights[i]*SQ(val1-val2);
}
return err;
}
double MaximumError(struct QuantizedValue const *q, uint8 const *sample,
int ndims, uint8 const *weights)
{
double err=0;
for(int i=0;i<ndims;i++)
{
int val2=sample[i];
int val1=(abs(val2-q->Mins[i])>abs(val2-q->Maxs[i]))?
q->Mins[i]:
q->Maxs[i];
err+=weights[i]*SQ(val2-val1);
}
return err;
}
// heap (priority queue) routines used for nearest-neghbor searches
struct FHeap {
int heap_n;
double *heap[MAXQUANT];
};
void InitHeap(struct FHeap *h)
{
h->heap_n=0;
}
void UpHeap(int k, struct FHeap *h)
{
double *tmpk=h->heap[k];
double tmpkn=*tmpk;
while((k>1) && (tmpkn <= *(h->heap[k/2])))
{
h->heap[k]=h->heap[k/2];
k/=2;
}
h->heap[k]=tmpk;
}
void HeapInsert(struct FHeap *h,double *elem)
{
h->heap_n++;
h->heap[h->heap_n]=elem;
UpHeap(h->heap_n,h);
}
void DownHeap(int k, struct FHeap *h)
{
double *v=h->heap[k];
while(k<=h->heap_n/2)
{
int j=2*k;
if (j<h->heap_n)
if (*(h->heap[j]) >= *(h->heap[j+1]))
j++;
if (*v < *(h->heap[j]))
{
h->heap[k]=v;
return;
}
h->heap[k]=h->heap[j]; k=j;
}
h->heap[k]=v;
}
void *RemoveHeapItem(struct FHeap *h)
{
void *ret=0;
if (h->heap_n!=0)
{
ret=h->heap[1];
h->heap[1]=h->heap[h->heap_n];
h->heap_n--;
DownHeap(1,h);
}
return ret;
}
// now, nearest neighbor finder. Use a heap to traverse the tree, stopping
// when there are no nodes with a minimum error < the current error.
struct FHeap TheQueue;
#define PUSHNODE(a) { \
(a)->MinError=MinimumError(a,sample,ndims,weights); \
if ((a)->MinError < besterror) HeapInsert(&TheQueue,&(a)->MinError); \
}
struct QuantizedValue *FindMatch(uint8 const *sample, int ndims,
uint8 *weights, struct QuantizedValue *q)
{
InitHeap(&TheQueue);
struct QuantizedValue *bestmatch=0;
double besterror=1.0e63;
PUSHNODE(q);
for(;;)
{
struct QuantizedValue *test=(struct QuantizedValue *)
RemoveHeapItem(&TheQueue);
if (! test) break; // heap empty
// printf("got pop node =%p minerror=%f\n",test,test->MinError);
if (test->MinError>besterror) break;
if (test->Children[0])
{
// it's a parent node. put the children on the queue
struct QuantizedValue *c1=test->Children[0];
struct QuantizedValue *c2=test->Children[1];
c1->MinError=MinimumError(c1,sample,ndims,weights);
if (c1->MinError < besterror)
HeapInsert(&TheQueue,&(c1->MinError));
c2->MinError=MinimumError(c2,sample,ndims,weights);
if (c2->MinError < besterror)
HeapInsert(&TheQueue,&(c2->MinError));
}
else
{
// it's a leaf node. This must be a new minimum or the MinError
// test would have failed.
if (test->MinError < besterror)
{
bestmatch=test;
besterror=test->MinError;
}
}
}
if (bestmatch)
{
SquaredError+=besterror;
bestmatch->NQuant++;
for(int i=0;i<ndims;i++)
bestmatch->Sums[i]+=sample[i];
}
return bestmatch;
}
static void RecalcMeans(struct QuantizedValue *q)
{
if (q)
{
if (q->Children[0])
{
// not a leaf, invoke recursively.
RecalcMeans(q->Children[0]);
RecalcMeans(q->Children[0]);
}
else
{
// it's a leaf. Set the means
if (q->NQuant)
{
for(int i=0;i<current_ndims;i++)
{
q->Mean[i]=(uint8) (q->Sums[i]/q->NQuant);
q->Sums[i]=0;
}
q->NQuant=0;
}
}
}
}
void OptimizeQuantizer(struct QuantizedValue *q, int ndims)
{
SetNDims(ndims);
RecalcMeans(q); // reset q values
Label(q,0); // update max/mins
}
static void RecalcStats(struct QuantizedValue *q)
{
if (q)
{
UpdateStats(q);
RecalcStats(q->Children[0]);
RecalcStats(q->Children[1]);
}
}
void RecalculateValues(struct QuantizedValue *q, int ndims)
{
SetNDims(ndims);
RecalcStats(q);
Label(q,0);
}

109
mathlib/randsse.cpp Normal file
View File

@ -0,0 +1,109 @@
//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============//
//
// Purpose: generates 4 randum numbers in the range 0..1 quickly, using SIMD
//
//=====================================================================================//
#include <math.h>
#include <float.h> // Needed for FLT_EPSILON
#include "basetypes.h"
#include <memory.h>
#include "tier0/dbg.h"
#include "mathlib/mathlib.h"
#include "mathlib/vector.h"
#include "mathlib/ssemath.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// see knuth volume 3 for insight.
class SIMDRandStreamContext
{
fltx4 m_RandY[55];
fltx4 *m_pRand_J, *m_pRand_K;
public:
void Seed( uint32 seed )
{
m_pRand_J=m_RandY+23; m_pRand_K=m_RandY+54;
for(int i=0;i<55;i++)
{
for(int j=0;j<4;j++)
{
SubFloat( m_RandY[i], j) = (seed>>16)/65536.0;
seed=(seed+1)*3141592621u;
}
}
}
inline fltx4 RandSIMD( void )
{
// ret= rand[k]+rand[j]
fltx4 retval=AddSIMD( *m_pRand_K, *m_pRand_J );
// if ( ret>=1.0) ret-=1.0
fltx4 overflow_mask=CmpGeSIMD( retval, Four_Ones );
retval=SubSIMD( retval, AndSIMD( Four_Ones, overflow_mask ) );
*m_pRand_K = retval;
// update pointers w/ wrap-around
if ( --m_pRand_J < m_RandY )
m_pRand_J=m_RandY+54;
if ( --m_pRand_K < m_RandY )
m_pRand_K=m_RandY+54;
return retval;
}
};
#define MAX_SIMULTANEOUS_RANDOM_STREAMS 32
static SIMDRandStreamContext s_SIMDRandContexts[MAX_SIMULTANEOUS_RANDOM_STREAMS];
static volatile int s_nRandContextsInUse[MAX_SIMULTANEOUS_RANDOM_STREAMS];
void SeedRandSIMD(uint32 seed)
{
for( int i = 0; i<MAX_SIMULTANEOUS_RANDOM_STREAMS; i++)
s_SIMDRandContexts[i].Seed( seed+i );
}
fltx4 RandSIMD( int nContextIndex )
{
return s_SIMDRandContexts[nContextIndex].RandSIMD();
}
int GetSIMDRandContext( void )
{
for(;;)
{
for(int i=0; i < (int)NELEMS( s_SIMDRandContexts ); i++)
{
if ( ! s_nRandContextsInUse[i] ) // available?
{
// try to take it!
if ( ThreadInterlockedAssignIf( &( s_nRandContextsInUse[i]), 1, 0 ) )
{
return i; // done!
}
}
}
Assert(0); // why don't we have enough buffers?
ThreadSleep();
}
}
void ReleaseSIMDRandContext( int nContext )
{
s_nRandContextsInUse[ nContext ] = 0;
}
fltx4 RandSIMD( void )
{
return s_SIMDRandContexts[0].RandSIMD();
}

View File

@ -0,0 +1,112 @@
//====== Copyright © 1996-2006, Valve Corporation, All rights reserved. =======//
//
// Purpose: Provide a class (SSE/SIMD only) holding a 2d matrix of class FourVectors,
// for high speed processing in tools.
//
// $NoKeywords: $
//
//=============================================================================//
#include "basetypes.h"
#include "mathlib/mathlib.h"
#include "mathlib/simdvectormatrix.h"
#include "mathlib/ssemath.h"
#include "tier0/dbg.h"
void CSIMDVectorMatrix::CreateFromRGBA_FloatImageData(int srcwidth, int srcheight,
float const *srcdata )
{
Assert( srcwidth && srcheight && srcdata );
SetSize( srcwidth, srcheight );
FourVectors *p_write_ptr=m_pData;
int n_vectors_per_source_line=(srcwidth >> 2);
int ntrailing_pixels_per_source_line=(srcwidth & 3);
for(int y=0;y<srcheight;y++)
{
float const *data_in=srcdata;
float *data_out=reinterpret_cast<float *>( p_write_ptr );
// copy full input blocks
for(int x=0;x<n_vectors_per_source_line;x++)
{
for(int c=0;c<3;c++)
{
data_out[0]=data_in[c]; // x0
data_out[1]=data_in[4+c]; // x1
data_out[2]=data_in[8+c]; // x2
data_out[3]=data_in[12+c]; // x3
data_out+=4;
}
data_in += 16;
}
// now, copy trailing data and pad with copies
if (ntrailing_pixels_per_source_line )
{
for(int c=0;c<3;c++)
{
for(int cp=0;cp<4; cp++)
{
int real_cp=MIN( cp, ntrailing_pixels_per_source_line-1 );
data_out[4*c+cp]= data_in[c+4*real_cp];
}
}
}
// advance ptrs to next line
p_write_ptr += m_nPaddedWidth;
srcdata += 4 * srcwidth;
}
}
void CSIMDVectorMatrix::RaiseToPower( float power )
{
int nv=NVectors();
if ( nv )
{
int fixed_point_exp=(int) ( 4.0*power );
FourVectors *src=m_pData;
do
{
src->x=Pow_FixedPoint_Exponent_SIMD( src->x, fixed_point_exp );
src->y=Pow_FixedPoint_Exponent_SIMD( src->y, fixed_point_exp );
src->z=Pow_FixedPoint_Exponent_SIMD( src->z, fixed_point_exp );
src++;
} while (--nv);
}
}
CSIMDVectorMatrix & CSIMDVectorMatrix::operator+=( CSIMDVectorMatrix const &src )
{
Assert( m_nWidth == src.m_nWidth );
Assert( m_nHeight == src.m_nHeight );
int nv=NVectors();
if ( nv )
{
FourVectors *srcv=src.m_pData;
FourVectors *destv=m_pData;
do // !! speed !! inline more iters
{
*( destv++ ) += *( srcv++ );
} while ( --nv );
}
return *this;
}
CSIMDVectorMatrix & CSIMDVectorMatrix::operator*=( Vector const &src )
{
int nv=NVectors();
if ( nv )
{
FourVectors scalevalue;
scalevalue.DuplicateVector( src );
FourVectors *destv=m_pData;
do // !! speed !! inline more iters
{
destv->VProduct( scalevalue );
destv++;
} while ( --nv );
}
return *this;
}

View File

@ -0,0 +1,218 @@
//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============//
//
// Purpose: noise() primitives.
//
//=====================================================================================//
#include <math.h>
#include "basetypes.h"
#include <memory.h>
#include "tier0/dbg.h"
#include "mathlib/mathlib.h"
#include "mathlib/vector.h"
#include "mathlib/noise.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// generate high quality noise based upon "sparse convolution". HIgher quality than perlin noise,
// and no direcitonal artifacts.
#include "noisedata.h"
#define N_IMPULSES_PER_CELL 5
#define NORMALIZING_FACTOR 1.0
//(0.5/N_IMPULSES_PER_CELL)
static inline int LatticeCoord(float x)
{
return ((int) floor(x)) & 0xff;
}
static inline int Hash4D(int ix, int iy, int iz, int idx)
{
int ret=perm_a[ix];
ret=perm_b[(ret+iy) & 0xff];
ret=perm_c[(ret+iz) & 0xff];
ret=perm_d[(ret+idx) & 0xff];
return ret;
}
#define SQ(x) ((x)*(x))
static float CellNoise( int ix, int iy, int iz, float xfrac, float yfrac, float zfrac,
float (*pNoiseShapeFunction)(float) )
{
float ret=0;
for(int idx=0;idx<N_IMPULSES_PER_CELL;idx++)
{
int coord_idx=Hash4D( ix, iy, iz, idx );
float dsq=SQ(impulse_xcoords[coord_idx]-xfrac)+
SQ(impulse_ycoords[coord_idx]-yfrac)+
SQ(impulse_zcoords[coord_idx]-zfrac);
dsq = sqrt( dsq );
if (dsq < 1.0 )
{
ret += (*pNoiseShapeFunction)( 1-dsq );
}
}
return ret;
}
float SparseConvolutionNoise( Vector const &pnt )
{
return SparseConvolutionNoise( pnt, QuinticInterpolatingPolynomial );
}
float FractalNoise( Vector const &pnt, int n_octaves)
{
float scale=1.0;
float iscale=1.0;
float ret=0;
float sumscale=0;
for(int o=0;o<n_octaves;o++)
{
Vector p1=pnt;
p1 *= scale;
ret+=iscale * SparseConvolutionNoise( p1 );
sumscale += iscale;
scale *= 2.0;
iscale *= 0.5;
}
return ret * ( 1.0/sumscale );
}
float Turbulence( Vector const &pnt, int n_octaves)
{
float scale=1.0;
float iscale=1.0;
float ret=0;
float sumscale=0;
for(int o=0;o<n_octaves;o++)
{
Vector p1=pnt;
p1 *= scale;
ret+=iscale * fabs ( 2.0*( SparseConvolutionNoise( p1 )-.5 ) );
sumscale += iscale;
scale *= 2.0;
iscale *= 0.5;
}
return ret * ( 1.0/sumscale );
}
#ifdef MEASURE_RANGE
float fmin1=10000000.0;
float fmax1=-1000000.0;
#endif
float SparseConvolutionNoise(Vector const &pnt, float (*pNoiseShapeFunction)(float) )
{
// computer integer lattice point
int ix=LatticeCoord(pnt.x);
int iy=LatticeCoord(pnt.y);
int iz=LatticeCoord(pnt.z);
// compute offsets within unit cube
float xfrac=pnt.x-floor(pnt.x);
float yfrac=pnt.y-floor(pnt.y);
float zfrac=pnt.z-floor(pnt.z);
float sum_out=0.;
for(int ox=-1; ox<=1; ox++)
for(int oy=-1; oy<=1; oy++)
for(int oz=-1; oz<=1; oz++)
{
sum_out += CellNoise( ix+ox, iy+oy, iz+oz,
xfrac-ox, yfrac-oy, zfrac-oz,
pNoiseShapeFunction );
}
#ifdef MEASURE_RANGE
fmin1=MIN(sum_out,fmin1);
fmax1=MAX(sum_out,fmax1);
#endif
return RemapValClamped( sum_out, .544487, 9.219176, 0.0, 1.0 );
}
// Improved Perlin Noise
// The following code is the c-ification of Ken Perlin's new noise algorithm
// "JAVA REFERENCE IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN"
// as available here: http://mrl.nyu.edu/~perlin/noise/
float NoiseGradient(int hash, float x, float y, float z)
{
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
float u = h<8 ? x : y; // INTO 12 GRADIENT DIRECTIONS.
float v = h<4 ? y : (h==12||h==14 ? x : z);
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
}
int NoiseHashIndex( int i )
{
static int s_permutation[] =
{
151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};
return s_permutation[ i & 0xff ];
}
float ImprovedPerlinNoise( Vector const &pnt )
{
float fx = floor(pnt.x);
float fy = floor(pnt.y);
float fz = floor(pnt.z);
int X = (int)fx & 255; // FIND UNIT CUBE THAT
int Y = (int)fy & 255; // CONTAINS POINT.
int Z = (int)fz & 255;
float x = pnt.x - fx; // FIND RELATIVE X,Y,Z
float y = pnt.y - fy; // OF POINT IN CUBE.
float z = pnt.z - fz;
float u = QuinticInterpolatingPolynomial(x); // COMPUTE FADE CURVES
float v = QuinticInterpolatingPolynomial(y); // FOR EACH OF X,Y,Z.
float w = QuinticInterpolatingPolynomial(z);
int A = NoiseHashIndex( X ) + Y; // HASH COORDINATES OF
int AA = NoiseHashIndex( A ) + Z; // THE 8 CUBE CORNERS,
int AB = NoiseHashIndex( A + 1 ) + Z;
int B = NoiseHashIndex( X + 1 ) + Y;
int BA = NoiseHashIndex( B ) + Z;
int BB = NoiseHashIndex( B + 1 ) + Z;
float g0 = NoiseGradient(NoiseHashIndex(AA ), x , y , z );
float g1 = NoiseGradient(NoiseHashIndex(BA ), x-1, y , z );
float g2 = NoiseGradient(NoiseHashIndex(AB ), x , y-1, z );
float g3 = NoiseGradient(NoiseHashIndex(BB ), x-1, y-1, z );
float g4 = NoiseGradient(NoiseHashIndex(AA+1), x , y , z-1 );
float g5 = NoiseGradient(NoiseHashIndex(BA+1), x-1, y , z-1 );
float g6 = NoiseGradient(NoiseHashIndex(AB+1), x , y-1, z-1 );
float g7 = NoiseGradient(NoiseHashIndex(BB+1), x-1, y-1, z-1 );
// AND ADD BLENDED RESULTS FROM 8 CORNERS OF CUBE
float g01 = Lerp( u, g0, g1 );
float g23 = Lerp( u, g2, g3 );
float g45 = Lerp( u, g4, g5 );
float g67 = Lerp( u, g6, g7 );
float g0123 = Lerp( v, g01, g23 );
float g4567 = Lerp( v, g45, g67 );
return Lerp( w, g0123,g4567 );
}

845
mathlib/sse.cpp Normal file
View File

@ -0,0 +1,845 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: SSE Math primitives.
//
//=====================================================================================//
#include <math.h>
#include <float.h> // Needed for FLT_EPSILON
#include "basetypes.h"
#include <memory.h>
#include "tier0/dbg.h"
#include "mathlib/mathlib.h"
#include "mathlib/vector.h"
#include "sse.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
static const uint32 _sincos_masks[] = { (uint32)0x0, (uint32)~0x0 };
static const uint32 _sincos_inv_masks[] = { (uint32)~0x0, (uint32)0x0 };
//-----------------------------------------------------------------------------
// Macros and constants required by some of the SSE assembly:
//-----------------------------------------------------------------------------
#ifdef _WIN32
#define _PS_EXTERN_CONST(Name, Val) \
const __declspec(align(16)) float _ps_##Name[4] = { Val, Val, Val, Val }
#define _PS_EXTERN_CONST_TYPE(Name, Type, Val) \
const __declspec(align(16)) Type _ps_##Name[4] = { Val, Val, Val, Val }; \
#define _EPI32_CONST(Name, Val) \
static const __declspec(align(16)) __int32 _epi32_##Name[4] = { Val, Val, Val, Val }
#define _PS_CONST(Name, Val) \
static const __declspec(align(16)) float _ps_##Name[4] = { Val, Val, Val, Val }
#elif defined _LINUX || defined __APPLE__
#define _PS_EXTERN_CONST(Name, Val) \
const __attribute__((aligned(16))) float _ps_##Name[4] = { Val, Val, Val, Val }
#define _PS_EXTERN_CONST_TYPE(Name, Type, Val) \
const __attribute__((aligned(16))) Type _ps_##Name[4] = { Val, Val, Val, Val }; \
#define _EPI32_CONST(Name, Val) \
static const __attribute__((aligned(16))) int32 _epi32_##Name[4] = { Val, Val, Val, Val }
#define _PS_CONST(Name, Val) \
static const __attribute__((aligned(16))) float _ps_##Name[4] = { Val, Val, Val, Val }
#endif
_PS_EXTERN_CONST(am_0, 0.0f);
_PS_EXTERN_CONST(am_1, 1.0f);
_PS_EXTERN_CONST(am_m1, -1.0f);
_PS_EXTERN_CONST(am_0p5, 0.5f);
_PS_EXTERN_CONST(am_1p5, 1.5f);
_PS_EXTERN_CONST(am_pi, (float)M_PI);
_PS_EXTERN_CONST(am_pi_o_2, (float)(M_PI / 2.0));
_PS_EXTERN_CONST(am_2_o_pi, (float)(2.0 / M_PI));
_PS_EXTERN_CONST(am_pi_o_4, (float)(M_PI / 4.0));
_PS_EXTERN_CONST(am_4_o_pi, (float)(4.0 / M_PI));
_PS_EXTERN_CONST_TYPE(am_sign_mask, int32, 0x80000000);
_PS_EXTERN_CONST_TYPE(am_inv_sign_mask, int32, ~0x80000000);
_PS_EXTERN_CONST_TYPE(am_min_norm_pos,int32, 0x00800000);
_PS_EXTERN_CONST_TYPE(am_mant_mask, int32, 0x7f800000);
_PS_EXTERN_CONST_TYPE(am_inv_mant_mask, int32, ~0x7f800000);
_EPI32_CONST(1, 1);
_EPI32_CONST(2, 2);
_PS_CONST(sincos_p0, 0.15707963267948963959e1f);
_PS_CONST(sincos_p1, -0.64596409750621907082e0f);
_PS_CONST(sincos_p2, 0.7969262624561800806e-1f);
_PS_CONST(sincos_p3, -0.468175413106023168e-2f);
#ifdef PFN_VECTORMA
void __cdecl _SSE_VectorMA( const float *start, float scale, const float *direction, float *dest );
#endif
//-----------------------------------------------------------------------------
// SSE implementations of optimized routines:
//-----------------------------------------------------------------------------
float _SSE_Sqrt(float x)
{
Assert( s_bMathlibInitialized );
float root = 0.f;
#ifdef _WIN32
_asm
{
sqrtss xmm0, x
movss root, xmm0
}
#elif defined _LINUX || defined __APPLE__
__asm__ __volatile__(
"movss %1,%%xmm2\n"
"sqrtss %%xmm2,%%xmm1\n"
"movss %%xmm1,%0"
: "=m" (root)
: "m" (x)
);
#endif
return root;
}
// Single iteration NewtonRaphson reciprocal square root:
// 0.5 * rsqrtps * (3 - x * rsqrtps(x) * rsqrtps(x))
// Very low error, and fine to use in place of 1.f / sqrtf(x).
#if 0
float _SSE_RSqrtAccurate(float x)
{
Assert( s_bMathlibInitialized );
float rroot;
_asm
{
rsqrtss xmm0, x
movss rroot, xmm0
}
return (0.5f * rroot) * (3.f - (x * rroot) * rroot);
}
#else
// Intel / Kipps SSE RSqrt. Significantly faster than above.
float _SSE_RSqrtAccurate(float a)
{
float x;
float half = 0.5f;
float three = 3.f;
#ifdef _WIN32
__asm
{
movss xmm3, a;
movss xmm1, half;
movss xmm2, three;
rsqrtss xmm0, xmm3;
mulss xmm3, xmm0;
mulss xmm1, xmm0;
mulss xmm3, xmm0;
subss xmm2, xmm3;
mulss xmm1, xmm2;
movss x, xmm1;
}
#elif defined _LINUX || defined __APPLE__
__asm__ __volatile__(
"movss %1, %%xmm3 \n\t"
"movss %2, %%xmm1 \n\t"
"movss %3, %%xmm2 \n\t"
"rsqrtss %%xmm3, %%xmm0 \n\t"
"mulss %%xmm0, %%xmm3 \n\t"
"mulss %%xmm0, %%xmm1 \n\t"
"mulss %%xmm0, %%xmm3 \n\t"
"subss %%xmm3, %%xmm2 \n\t"
"mulss %%xmm2, %%xmm1 \n\t"
"movss %%xmm1, %0 \n\t"
: "=m" (x)
: "m" (a), "m" (half), "m" (three)
);
#else
#error "Not Implemented"
#endif
return x;
}
#endif
// Simple SSE rsqrt. Usually accurate to around 6 (relative) decimal places
// or so, so ok for closed transforms. (ie, computing lighting normals)
float _SSE_RSqrtFast(float x)
{
Assert( s_bMathlibInitialized );
float rroot;
#ifdef _WIN32
_asm
{
rsqrtss xmm0, x
movss rroot, xmm0
}
#elif defined _LINUX || defined __APPLE__
__asm__ __volatile__(
"rsqrtss %1, %%xmm0 \n\t"
"movss %%xmm0, %0 \n\t"
: "=m" (x)
: "m" (rroot)
: "%xmm0"
);
#else
#error
#endif
return rroot;
}
float FASTCALL _SSE_VectorNormalize (Vector& vec)
{
Assert( s_bMathlibInitialized );
// NOTE: This is necessary to prevent an memory overwrite...
// sice vec only has 3 floats, we can't "movaps" directly into it.
#ifdef _WIN32
__declspec(align(16)) float result[4];
#elif defined _LINUX || defined __APPLE__
__attribute__((aligned(16))) float result[4];
#endif
float *v = &vec[0];
float radius = 0.f;
// Blah, get rid of these comparisons ... in reality, if you have all 3 as zero, it shouldn't
// be much of a performance win, considering you will very likely miss 3 branch predicts in a row.
if ( v[0] || v[1] || v[2] )
{
#ifdef _WIN32
float *r = &result[0];
_asm
{
mov eax, v
mov edx, r
#ifdef ALIGNED_VECTOR
movaps xmm4, [eax] // r4 = vx, vy, vz, X
movaps xmm1, xmm4 // r1 = r4
#else
movups xmm4, [eax] // r4 = vx, vy, vz, X
movaps xmm1, xmm4 // r1 = r4
#endif
mulps xmm1, xmm4 // r1 = vx * vx, vy * vy, vz * vz, X
movhlps xmm3, xmm1 // r3 = vz * vz, X, X, X
movaps xmm2, xmm1 // r2 = r1
shufps xmm2, xmm2, 1 // r2 = vy * vy, X, X, X
addss xmm1, xmm2 // r1 = (vx * vx) + (vy * vy), X, X, X
addss xmm1, xmm3 // r1 = (vx * vx) + (vy * vy) + (vz * vz), X, X, X
sqrtss xmm1, xmm1 // r1 = sqrt((vx * vx) + (vy * vy) + (vz * vz)), X, X, X
movss radius, xmm1 // radius = sqrt((vx * vx) + (vy * vy) + (vz * vz))
rcpss xmm1, xmm1 // r1 = 1/radius, X, X, X
shufps xmm1, xmm1, 0 // r1 = 1/radius, 1/radius, 1/radius, X
mulps xmm4, xmm1 // r4 = vx * 1/radius, vy * 1/radius, vz * 1/radius, X
movaps [edx], xmm4 // v = vx * 1/radius, vy * 1/radius, vz * 1/radius, X
}
#elif defined _LINUX || defined __APPLE__
__asm__ __volatile__(
#ifdef ALIGNED_VECTOR
"movaps %2, %%xmm4 \n\t"
"movaps %%xmm4, %%xmm1 \n\t"
#else
"movups %2, %%xmm4 \n\t"
"movaps %%xmm4, %%xmm1 \n\t"
#endif
"mulps %%xmm4, %%xmm1 \n\t"
"movhlps %%xmm1, %%xmm3 \n\t"
"movaps %%xmm1, %%xmm2 \n\t"
"shufps $1, %%xmm2, %%xmm2 \n\t"
"addss %%xmm2, %%xmm1 \n\t"
"addss %%xmm3, %%xmm1 \n\t"
"sqrtss %%xmm1, %%xmm1 \n\t"
"movss %%xmm1, %0 \n\t"
"rcpss %%xmm1, %%xmm1 \n\t"
"shufps $0, %%xmm1, %%xmm1 \n\t"
"mulps %%xmm1, %%xmm4 \n\t"
"movaps %%xmm4, %1 \n\t"
: "=m" (radius), "=m" (result)
: "m" (*v)
);
#else
#error "Not Implemented"
#endif
vec.x = result[0];
vec.y = result[1];
vec.z = result[2];
}
return radius;
}
void FASTCALL _SSE_VectorNormalizeFast (Vector& vec)
{
float ool = _SSE_RSqrtAccurate( FLT_EPSILON + vec.x * vec.x + vec.y * vec.y + vec.z * vec.z );
vec.x *= ool;
vec.y *= ool;
vec.z *= ool;
}
float _SSE_InvRSquared(const float* v)
{
float inv_r2 = 1.f;
#ifdef _WIN32
_asm { // Intel SSE only routine
mov eax, v
movss xmm5, inv_r2 // x5 = 1.0, 0, 0, 0
#ifdef ALIGNED_VECTOR
movaps xmm4, [eax] // x4 = vx, vy, vz, X
#else
movups xmm4, [eax] // x4 = vx, vy, vz, X
#endif
movaps xmm1, xmm4 // x1 = x4
mulps xmm1, xmm4 // x1 = vx * vx, vy * vy, vz * vz, X
movhlps xmm3, xmm1 // x3 = vz * vz, X, X, X
movaps xmm2, xmm1 // x2 = x1
shufps xmm2, xmm2, 1 // x2 = vy * vy, X, X, X
addss xmm1, xmm2 // x1 = (vx * vx) + (vy * vy), X, X, X
addss xmm1, xmm3 // x1 = (vx * vx) + (vy * vy) + (vz * vz), X, X, X
maxss xmm1, xmm5 // x1 = MAX( 1.0, x1 )
rcpss xmm0, xmm1 // x0 = 1 / MAX( 1.0, x1 )
movss inv_r2, xmm0 // inv_r2 = x0
}
#elif defined _LINUX || defined __APPLE__
__asm__ __volatile__(
#ifdef ALIGNED_VECTOR
"movaps %1, %%xmm4 \n\t"
#else
"movups %1, %%xmm4 \n\t"
#endif
"movaps %%xmm4, %%xmm1 \n\t"
"mulps %%xmm4, %%xmm1 \n\t"
"movhlps %%xmm1, %%xmm3 \n\t"
"movaps %%xmm1, %%xmm2 \n\t"
"shufps $1, %%xmm2, %%xmm2 \n\t"
"addss %%xmm2, %%xmm1 \n\t"
"addss %%xmm3, %%xmm1 \n\t"
"maxss %%xmm5, %%xmm1 \n\t"
"rcpss %%xmm1, %%xmm0 \n\t"
"movss %%xmm0, %0 \n\t"
: "=m" (inv_r2)
: "m" (*v), "m" (inv_r2)
);
#else
#error "Not Implemented"
#endif
return inv_r2;
}
void _SSE_SinCos(float x, float* s, float* c)
{
#ifdef _WIN32
float t4, t8, t12;
__asm
{
movss xmm0, x
movss t12, xmm0
movss xmm1, _ps_am_inv_sign_mask
mov eax, t12
mulss xmm0, _ps_am_2_o_pi
andps xmm0, xmm1
and eax, 0x80000000
cvttss2si edx, xmm0
mov ecx, edx
mov t12, esi
mov esi, edx
add edx, 0x1
shl ecx, (31 - 1)
shl edx, (31 - 1)
movss xmm4, _ps_am_1
cvtsi2ss xmm3, esi
mov t8, eax
and esi, 0x1
subss xmm0, xmm3
movss xmm3, _sincos_inv_masks[esi * 4]
minss xmm0, xmm4
subss xmm4, xmm0
movss xmm6, xmm4
andps xmm4, xmm3
and ecx, 0x80000000
movss xmm2, xmm3
andnps xmm3, xmm0
and edx, 0x80000000
movss xmm7, t8
andps xmm0, xmm2
mov t8, ecx
mov t4, edx
orps xmm4, xmm3
mov eax, s //mov eax, [esp + 4 + 16]
mov edx, c //mov edx, [esp + 4 + 16 + 4]
andnps xmm2, xmm6
orps xmm0, xmm2
movss xmm2, t8
movss xmm1, xmm0
movss xmm5, xmm4
xorps xmm7, xmm2
movss xmm3, _ps_sincos_p3
mulss xmm0, xmm0
mulss xmm4, xmm4
movss xmm2, xmm0
movss xmm6, xmm4
orps xmm1, xmm7
movss xmm7, _ps_sincos_p2
mulss xmm0, xmm3
mulss xmm4, xmm3
movss xmm3, _ps_sincos_p1
addss xmm0, xmm7
addss xmm4, xmm7
movss xmm7, _ps_sincos_p0
mulss xmm0, xmm2
mulss xmm4, xmm6
addss xmm0, xmm3
addss xmm4, xmm3
movss xmm3, t4
mulss xmm0, xmm2
mulss xmm4, xmm6
orps xmm5, xmm3
mov esi, t12
addss xmm0, xmm7
addss xmm4, xmm7
mulss xmm0, xmm1
mulss xmm4, xmm5
// use full stores since caller might reload with full loads
movss [eax], xmm0
movss [edx], xmm4
}
#elif defined _LINUX || defined __APPLE__
// #warning "_SSE_sincos NOT implemented!"
#else
#error "Not Implemented"
#endif
}
float _SSE_cos( float x )
{
#ifdef _WIN32
float temp;
__asm
{
movss xmm0, x
movss xmm1, _ps_am_inv_sign_mask
andps xmm0, xmm1
addss xmm0, _ps_am_pi_o_2
mulss xmm0, _ps_am_2_o_pi
cvttss2si ecx, xmm0
movss xmm5, _ps_am_1
mov edx, ecx
shl edx, (31 - 1)
cvtsi2ss xmm1, ecx
and edx, 0x80000000
and ecx, 0x1
subss xmm0, xmm1
movss xmm6, _sincos_masks[ecx * 4]
minss xmm0, xmm5
movss xmm1, _ps_sincos_p3
subss xmm5, xmm0
andps xmm5, xmm6
movss xmm7, _ps_sincos_p2
andnps xmm6, xmm0
mov temp, edx
orps xmm5, xmm6
movss xmm0, xmm5
mulss xmm5, xmm5
movss xmm4, _ps_sincos_p1
movss xmm2, xmm5
mulss xmm5, xmm1
movss xmm1, _ps_sincos_p0
addss xmm5, xmm7
mulss xmm5, xmm2
movss xmm3, temp
addss xmm5, xmm4
mulss xmm5, xmm2
orps xmm0, xmm3
addss xmm5, xmm1
mulss xmm0, xmm5
movss x, xmm0
}
#elif defined _LINUX || defined __APPLE__
// #warning "_SSE_cos NOT implemented!"
#else
#error "Not Implemented"
#endif
return x;
}
//-----------------------------------------------------------------------------
// SSE2 implementations of optimized routines:
//-----------------------------------------------------------------------------
void _SSE2_SinCos(float x, float* s, float* c) // any x
{
#ifdef _WIN32
__asm
{
movss xmm0, x
movaps xmm7, xmm0
movss xmm1, _ps_am_inv_sign_mask
movss xmm2, _ps_am_sign_mask
movss xmm3, _ps_am_2_o_pi
andps xmm0, xmm1
andps xmm7, xmm2
mulss xmm0, xmm3
pxor xmm3, xmm3
movd xmm5, _epi32_1
movss xmm4, _ps_am_1
cvttps2dq xmm2, xmm0
pand xmm5, xmm2
movd xmm1, _epi32_2
pcmpeqd xmm5, xmm3
movd xmm3, _epi32_1
cvtdq2ps xmm6, xmm2
paddd xmm3, xmm2
pand xmm2, xmm1
pand xmm3, xmm1
subss xmm0, xmm6
pslld xmm2, (31 - 1)
minss xmm0, xmm4
mov eax, s // mov eax, [esp + 4 + 16]
mov edx, c // mov edx, [esp + 4 + 16 + 4]
subss xmm4, xmm0
pslld xmm3, (31 - 1)
movaps xmm6, xmm4
xorps xmm2, xmm7
movaps xmm7, xmm5
andps xmm6, xmm7
andnps xmm7, xmm0
andps xmm0, xmm5
andnps xmm5, xmm4
movss xmm4, _ps_sincos_p3
orps xmm6, xmm7
orps xmm0, xmm5
movss xmm5, _ps_sincos_p2
movaps xmm1, xmm0
movaps xmm7, xmm6
mulss xmm0, xmm0
mulss xmm6, xmm6
orps xmm1, xmm2
orps xmm7, xmm3
movaps xmm2, xmm0
movaps xmm3, xmm6
mulss xmm0, xmm4
mulss xmm6, xmm4
movss xmm4, _ps_sincos_p1
addss xmm0, xmm5
addss xmm6, xmm5
movss xmm5, _ps_sincos_p0
mulss xmm0, xmm2
mulss xmm6, xmm3
addss xmm0, xmm4
addss xmm6, xmm4
mulss xmm0, xmm2
mulss xmm6, xmm3
addss xmm0, xmm5
addss xmm6, xmm5
mulss xmm0, xmm1
mulss xmm6, xmm7
// use full stores since caller might reload with full loads
movss [eax], xmm0
movss [edx], xmm6
}
#elif defined _LINUX || defined __APPLE__
// #warning "_SSE2_SinCos NOT implemented!"
#else
#error "Not Implemented"
#endif
}
float _SSE2_cos(float x)
{
#ifdef _WIN32
__asm
{
movss xmm0, x
movss xmm1, _ps_am_inv_sign_mask
movss xmm2, _ps_am_pi_o_2
movss xmm3, _ps_am_2_o_pi
andps xmm0, xmm1
addss xmm0, xmm2
mulss xmm0, xmm3
pxor xmm3, xmm3
movd xmm5, _epi32_1
movss xmm4, _ps_am_1
cvttps2dq xmm2, xmm0
pand xmm5, xmm2
movd xmm1, _epi32_2
pcmpeqd xmm5, xmm3
cvtdq2ps xmm6, xmm2
pand xmm2, xmm1
pslld xmm2, (31 - 1)
subss xmm0, xmm6
movss xmm3, _ps_sincos_p3
minss xmm0, xmm4
subss xmm4, xmm0
andps xmm0, xmm5
andnps xmm5, xmm4
orps xmm0, xmm5
movaps xmm1, xmm0
movss xmm4, _ps_sincos_p2
mulss xmm0, xmm0
movss xmm5, _ps_sincos_p1
orps xmm1, xmm2
movaps xmm7, xmm0
mulss xmm0, xmm3
movss xmm6, _ps_sincos_p0
addss xmm0, xmm4
mulss xmm0, xmm7
addss xmm0, xmm5
mulss xmm0, xmm7
addss xmm0, xmm6
mulss xmm0, xmm1
movss x, xmm0
}
#elif defined _LINUX || defined __APPLE__
// #warning "_SSE2_cos NOT implemented!"
#else
#error "Not Implemented"
#endif
return x;
}
// SSE Version of VectorTransform
void VectorTransformSSE(const float *in1, const matrix3x4_t& in2, float *out1)
{
Assert( s_bMathlibInitialized );
Assert( in1 != out1 );
#ifdef _WIN32
__asm
{
mov eax, in1;
mov ecx, in2;
mov edx, out1;
movss xmm0, [eax];
mulss xmm0, [ecx];
movss xmm1, [eax+4];
mulss xmm1, [ecx+4];
movss xmm2, [eax+8];
mulss xmm2, [ecx+8];
addss xmm0, xmm1;
addss xmm0, xmm2;
addss xmm0, [ecx+12]
movss [edx], xmm0;
add ecx, 16;
movss xmm0, [eax];
mulss xmm0, [ecx];
movss xmm1, [eax+4];
mulss xmm1, [ecx+4];
movss xmm2, [eax+8];
mulss xmm2, [ecx+8];
addss xmm0, xmm1;
addss xmm0, xmm2;
addss xmm0, [ecx+12]
movss [edx+4], xmm0;
add ecx, 16;
movss xmm0, [eax];
mulss xmm0, [ecx];
movss xmm1, [eax+4];
mulss xmm1, [ecx+4];
movss xmm2, [eax+8];
mulss xmm2, [ecx+8];
addss xmm0, xmm1;
addss xmm0, xmm2;
addss xmm0, [ecx+12]
movss [edx+8], xmm0;
}
#elif defined _LINUX || defined __APPLE__
// #warning "VectorTransformSSE C implementation only"
out1[0] = DotProduct(in1, in2[0]) + in2[0][3];
out1[1] = DotProduct(in1, in2[1]) + in2[1][3];
out1[2] = DotProduct(in1, in2[2]) + in2[2][3];
#else
#error "Not Implemented"
#endif
}
void VectorRotateSSE( const float *in1, const matrix3x4_t& in2, float *out1 )
{
Assert( s_bMathlibInitialized );
Assert( in1 != out1 );
#ifdef _WIN32
__asm
{
mov eax, in1;
mov ecx, in2;
mov edx, out1;
movss xmm0, [eax];
mulss xmm0, [ecx];
movss xmm1, [eax+4];
mulss xmm1, [ecx+4];
movss xmm2, [eax+8];
mulss xmm2, [ecx+8];
addss xmm0, xmm1;
addss xmm0, xmm2;
movss [edx], xmm0;
add ecx, 16;
movss xmm0, [eax];
mulss xmm0, [ecx];
movss xmm1, [eax+4];
mulss xmm1, [ecx+4];
movss xmm2, [eax+8];
mulss xmm2, [ecx+8];
addss xmm0, xmm1;
addss xmm0, xmm2;
movss [edx+4], xmm0;
add ecx, 16;
movss xmm0, [eax];
mulss xmm0, [ecx];
movss xmm1, [eax+4];
mulss xmm1, [ecx+4];
movss xmm2, [eax+8];
mulss xmm2, [ecx+8];
addss xmm0, xmm1;
addss xmm0, xmm2;
movss [edx+8], xmm0;
}
#elif defined _LINUX || defined __APPLE__
// #warning "VectorRotateSSE C implementation only"
out1[0] = DotProduct( in1, in2[0] );
out1[1] = DotProduct( in1, in2[1] );
out1[2] = DotProduct( in1, in2[2] );
#else
#error "Not Implemented"
#endif
}
#ifdef _WIN32
void _declspec(naked) _SSE_VectorMA( const float *start, float scale, const float *direction, float *dest )
{
// FIXME: This don't work!! It will overwrite memory in the write to dest
Assert(0);
Assert( s_bMathlibInitialized );
_asm { // Intel SSE only routine
mov eax, DWORD PTR [esp+0x04] ; *start, s0..s2
mov ecx, DWORD PTR [esp+0x0c] ; *direction, d0..d2
mov edx, DWORD PTR [esp+0x10] ; *dest
movss xmm2, [esp+0x08] ; x2 = scale, 0, 0, 0
#ifdef ALIGNED_VECTOR
movaps xmm3, [ecx] ; x3 = dir0,dir1,dir2,X
pshufd xmm2, xmm2, 0 ; x2 = scale, scale, scale, scale
movaps xmm1, [eax] ; x1 = start1, start2, start3, X
mulps xmm3, xmm2 ; x3 *= x2
addps xmm3, xmm1 ; x3 += x1
movaps [edx], xmm3 ; *dest = x3
#else
movups xmm3, [ecx] ; x3 = dir0,dir1,dir2,X
pshufd xmm2, xmm2, 0 ; x2 = scale, scale, scale, scale
movups xmm1, [eax] ; x1 = start1, start2, start3, X
mulps xmm3, xmm2 ; x3 *= x2
addps xmm3, xmm1 ; x3 += x1
movups [edx], xmm3 ; *dest = x3
#endif
}
}
#endif
#ifdef _WIN32
#ifdef PFN_VECTORMA
void _declspec(naked) __cdecl _SSE_VectorMA( const Vector &start, float scale, const Vector &direction, Vector &dest )
{
// FIXME: This don't work!! It will overwrite memory in the write to dest
Assert(0);
Assert( s_bMathlibInitialized );
_asm
{
// Intel SSE only routine
mov eax, DWORD PTR [esp+0x04] ; *start, s0..s2
mov ecx, DWORD PTR [esp+0x0c] ; *direction, d0..d2
mov edx, DWORD PTR [esp+0x10] ; *dest
movss xmm2, [esp+0x08] ; x2 = scale, 0, 0, 0
#ifdef ALIGNED_VECTOR
movaps xmm3, [ecx] ; x3 = dir0,dir1,dir2,X
pshufd xmm2, xmm2, 0 ; x2 = scale, scale, scale, scale
movaps xmm1, [eax] ; x1 = start1, start2, start3, X
mulps xmm3, xmm2 ; x3 *= x2
addps xmm3, xmm1 ; x3 += x1
movaps [edx], xmm3 ; *dest = x3
#else
movups xmm3, [ecx] ; x3 = dir0,dir1,dir2,X
pshufd xmm2, xmm2, 0 ; x2 = scale, scale, scale, scale
movups xmm1, [eax] ; x1 = start1, start2, start3, X
mulps xmm3, xmm2 ; x3 *= x2
addps xmm3, xmm1 ; x3 += x1
movups [edx], xmm3 ; *dest = x3
#endif
}
}
float (__cdecl *pfVectorMA)(Vector& v) = _VectorMA;
#endif
#endif
// SSE DotProduct -- it's a smidgen faster than the asm DotProduct...
// Should be validated too! :)
// NJS: (Nov 1 2002) -NOT- faster. may time a couple cycles faster in a single function like
// this, but when inlined, and instruction scheduled, the C version is faster.
// Verified this via VTune
/*
vec_t DotProduct (const vec_t *a, const vec_t *c)
{
vec_t temp;
__asm
{
mov eax, a;
mov ecx, c;
mov edx, DWORD PTR [temp]
movss xmm0, [eax];
mulss xmm0, [ecx];
movss xmm1, [eax+4];
mulss xmm1, [ecx+4];
movss xmm2, [eax+8];
mulss xmm2, [ecx+8];
addss xmm0, xmm1;
addss xmm0, xmm2;
movss [edx], xmm0;
fld DWORD PTR [edx];
ret
}
}
*/

23
mathlib/sse.h Normal file
View File

@ -0,0 +1,23 @@
//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=====================================================================================//
#ifndef _SSE_H
#define _SSE_H
float _SSE_Sqrt(float x);
float _SSE_RSqrtAccurate(float a);
float _SSE_RSqrtFast(float x);
float FASTCALL _SSE_VectorNormalize(Vector& vec);
void FASTCALL _SSE_VectorNormalizeFast(Vector& vec);
float _SSE_InvRSquared(const float* v);
void _SSE_SinCos(float x, float* s, float* c);
float _SSE_cos( float x);
void _SSE2_SinCos(float x, float* s, float* c);
float _SSE2_cos(float x);
void VectorTransformSSE(const float *in1, const matrix3x4_t& in2, float *out1);
void VectorRotateSSE( const float *in1, const matrix3x4_t& in2, float *out1 );
#endif // _SSE_H

1164
mathlib/sseconst.cpp Normal file

File diff suppressed because it is too large Load Diff

105
mathlib/ssenoise.cpp Normal file
View File

@ -0,0 +1,105 @@
//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============//
//
// Purpose: Fast low quality noise suitable for real time use
//
//=====================================================================================//
#include <math.h>
#include <float.h> // Needed for FLT_EPSILON
#include "basetypes.h"
#include <memory.h>
#include "tier0/dbg.h"
#include "mathlib/mathlib.h"
#include "mathlib/vector.h"
#include "mathlib/ssemath.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#include "noisedata.h"
#define MAGIC_NUMBER (1<<15) // gives 8 bits of fraction
static fltx4 Four_MagicNumbers = { MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER };
static ALIGN16 int32 idx_mask[4]= {0xffff, 0xffff, 0xffff, 0xffff};
#define MASK255 (*((fltx4 *)(& idx_mask )))
// returns 0..1
static inline float GetLatticePointValue( int idx_x, int idx_y, int idx_z )
{
int ret_idx = perm_a[idx_x & 0xff];
ret_idx = perm_b[( idx_y + ret_idx ) & 0xff];
ret_idx = perm_c[( idx_z + ret_idx ) & 0xff];
return impulse_xcoords[ret_idx];
}
fltx4 NoiseSIMD( const fltx4 & x, const fltx4 & y, const fltx4 & z )
{
// use magic to convert to integer index
fltx4 x_idx = AndSIMD( MASK255, AddSIMD( x, Four_MagicNumbers ) );
fltx4 y_idx = AndSIMD( MASK255, AddSIMD( y, Four_MagicNumbers ) );
fltx4 z_idx = AndSIMD( MASK255, AddSIMD( z, Four_MagicNumbers ) );
fltx4 lattice000 = Four_Zeros, lattice001 = Four_Zeros, lattice010 = Four_Zeros, lattice011 = Four_Zeros;
fltx4 lattice100 = Four_Zeros, lattice101 = Four_Zeros, lattice110 = Four_Zeros, lattice111 = Four_Zeros;
// FIXME: Converting the input vectors to int indices will cause load-hit-stores (48 bytes)
// Converting the indexed noise values back to vectors will cause more (128 bytes)
// The noise table could store vectors if we chunked it into 2x2x2 blocks.
fltx4 xfrac = Four_Zeros, yfrac = Four_Zeros, zfrac = Four_Zeros;
#define DOPASS(i) \
{ unsigned int xi = SubInt( x_idx, i ); \
unsigned int yi = SubInt( y_idx, i ); \
unsigned int zi = SubInt( z_idx, i ); \
SubFloat( xfrac, i ) = (xi & 0xff)*(1.0/256.0); \
SubFloat( yfrac, i ) = (yi & 0xff)*(1.0/256.0); \
SubFloat( zfrac, i ) = (zi & 0xff)*(1.0/256.0); \
xi>>=8; \
yi>>=8; \
zi>>=8; \
\
SubFloat( lattice000, i ) = GetLatticePointValue( xi,yi,zi ); \
SubFloat( lattice001, i ) = GetLatticePointValue( xi,yi,zi+1 ); \
SubFloat( lattice010, i ) = GetLatticePointValue( xi,yi+1,zi ); \
SubFloat( lattice011, i ) = GetLatticePointValue( xi,yi+1,zi+1 ); \
SubFloat( lattice100, i ) = GetLatticePointValue( xi+1,yi,zi ); \
SubFloat( lattice101, i ) = GetLatticePointValue( xi+1,yi,zi+1 ); \
SubFloat( lattice110, i ) = GetLatticePointValue( xi+1,yi+1,zi ); \
SubFloat( lattice111, i ) = GetLatticePointValue( xi+1,yi+1,zi+1 ); \
}
DOPASS( 0 );
DOPASS( 1 );
DOPASS( 2 );
DOPASS( 3 );
// now, we have 8 lattice values for each of four points as m128s, and interpolant values for
// each axis in m128 form in [xyz]frac. Perfom the trilinear interpolation as SIMD ops
// first, do x interpolation
fltx4 l2d00 = AddSIMD( lattice000, MulSIMD( xfrac, SubSIMD( lattice100, lattice000 ) ) );
fltx4 l2d01 = AddSIMD( lattice001, MulSIMD( xfrac, SubSIMD( lattice101, lattice001 ) ) );
fltx4 l2d10 = AddSIMD( lattice010, MulSIMD( xfrac, SubSIMD( lattice110, lattice010 ) ) );
fltx4 l2d11 = AddSIMD( lattice011, MulSIMD( xfrac, SubSIMD( lattice111, lattice011 ) ) );
// now, do y interpolation
fltx4 l1d0 = AddSIMD( l2d00, MulSIMD( yfrac, SubSIMD( l2d10, l2d00 ) ) );
fltx4 l1d1 = AddSIMD( l2d01, MulSIMD( yfrac, SubSIMD( l2d11, l2d01 ) ) );
// final z interpolation
fltx4 rslt = AddSIMD( l1d0, MulSIMD( zfrac, SubSIMD( l1d1, l1d0 ) ) );
// map to 0..1
return MulSIMD( Four_Twos, SubSIMD( rslt, Four_PointFives ) );
}
fltx4 NoiseSIMD( FourVectors const &pos )
{
return NoiseSIMD( pos.x, pos.y, pos.z );
}

12
mathlib/vector.cpp Normal file
View File

@ -0,0 +1,12 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "mathlib/vector.h"
Vector vec3_origin(0,0,0);

1263
mathlib/vmatrix.cpp Normal file

File diff suppressed because it is too large Load Diff

2521
tier1/KeyValues.cpp Normal file

File diff suppressed because it is too large Load Diff

331
tier1/NetAdr.cpp Normal file
View File

@ -0,0 +1,331 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// NetAdr.cpp: implementation of the CNetAdr class.
//
//===========================================================================//
#if defined( _WIN32 ) && !defined( _X360 )
#include <windows.h>
#endif
#include "tier0/dbg.h"
#include "netadr.h"
#include "tier1/strtools.h"
#if defined( _WIN32 ) && !defined( _X360 )
#define WIN32_LEAN_AND_MEAN
#include <winsock.h>
typedef int socklen_t;
#elif !defined( _X360 )
#include <netinet/in.h> // ntohs()
#include <netdb.h> // gethostbyname()
#include <sys/socket.h> // getsockname()
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
bool netadr_t::CompareAdr (const netadr_t &a, bool onlyBase) const
{
if ( a.type != type )
return false;
if ( type == NA_LOOPBACK )
return true;
if ( type == NA_BROADCAST )
return true;
if ( type == NA_IP )
{
if ( !onlyBase && (port != a.port) )
return false;
if ( a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2] && a.ip[3] == ip[3] )
return true;
}
return false;
}
bool netadr_t::CompareClassBAdr (const netadr_t &a) const
{
if ( a.type != type )
return false;
if ( type == NA_LOOPBACK )
return true;
if ( type == NA_IP )
{
if (a.ip[0] == ip[0] && a.ip[1] == ip[1] )
return true;
}
return false;
}
bool netadr_t::CompareClassCAdr (const netadr_t &a) const
{
if ( a.type != type )
return false;
if ( type == NA_LOOPBACK )
return true;
if ( type == NA_IP )
{
if (a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2] )
return true;
}
return false;
}
// reserved addresses are not routeable, so they can all be used in a LAN game
bool netadr_t::IsReservedAdr () const
{
if ( type == NA_LOOPBACK )
return true;
if ( type == NA_IP )
{
if ( (ip[0] == 10) || // 10.x.x.x is reserved
(ip[0] == 127) || // 127.x.x.x
(ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) || // 172.16.x.x - 172.31.x.x
(ip[0] == 192 && ip[1] >= 168) ) // 192.168.x.x
return true;
}
return false;
}
const char * netadr_t::ToString(bool baseOnly) const
{
static char s[64];
Q_strncpy (s, "unknown", sizeof( s ) );
if (type == NA_LOOPBACK)
{
Q_strncpy (s, "loopback", sizeof( s ) );
}
else if (type == NA_BROADCAST)
{
Q_strncpy (s, "broadcast", sizeof( s ) );
}
else if (type == NA_IP)
{
if ( baseOnly)
{
Q_snprintf (s, sizeof( s ), "%i.%i.%i.%i", ip[0], ip[1], ip[2], ip[3]);
}
else
{
Q_snprintf (s, sizeof( s ), "%i.%i.%i.%i:%i", ip[0], ip[1], ip[2], ip[3], ntohs(port));
}
}
return s;
}
bool netadr_t::IsLocalhost() const
{
// are we 127.0.0.1 ?
return (ip[0] == 127) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 1);
}
bool netadr_t::IsLoopback() const
{
// are we useding engine loopback buffers
return type == NA_LOOPBACK;
}
void netadr_t::Clear()
{
ip[0] = ip[1] = ip[2] = ip[3] = 0;
port = 0;
type = NA_NULL;
}
void netadr_t::SetIP(uint8 b1, uint8 b2, uint8 b3, uint8 b4)
{
ip[0] = b1;
ip[1] = b2;
ip[2] = b3;
ip[3] = b4;
}
void netadr_t::SetIP(uint unIP)
{
*((uint*)ip) = BigLong( unIP );
}
void netadr_t::SetType(netadrtype_t newtype)
{
type = newtype;
}
netadrtype_t netadr_t::GetType() const
{
return type;
}
unsigned short netadr_t::GetPort() const
{
return BigShort( port );
}
unsigned int netadr_t::GetIP() const
{
return *(unsigned int *)&ip;;
}
unsigned long netadr_t::addr_ntohl() const
{
return ntohl( GetIP() );
}
unsigned long netadr_t::addr_htonl() const
{
return htonl( GetIP() );
}
void netadr_t::ToSockadr (struct sockaddr * s) const
{
Q_memset ( s, 0, sizeof(struct sockaddr));
if (type == NA_BROADCAST)
{
((struct sockaddr_in*)s)->sin_family = AF_INET;
((struct sockaddr_in*)s)->sin_port = port;
((struct sockaddr_in*)s)->sin_addr.s_addr = INADDR_BROADCAST;
}
else if (type == NA_IP)
{
((struct sockaddr_in*)s)->sin_family = AF_INET;
((struct sockaddr_in*)s)->sin_addr.s_addr = *(int *)&ip;
((struct sockaddr_in*)s)->sin_port = port;
}
else if (type == NA_LOOPBACK )
{
((struct sockaddr_in*)s)->sin_family = AF_INET;
((struct sockaddr_in*)s)->sin_port = port;
((struct sockaddr_in*)s)->sin_addr.s_addr = INADDR_LOOPBACK ;
}
}
bool netadr_t::SetFromSockadr(const struct sockaddr * s)
{
if (s->sa_family == AF_INET)
{
type = NA_IP;
*(int *)&ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
port = ((struct sockaddr_in *)s)->sin_port;
return true;
}
else
{
Clear();
return false;
}
}
bool netadr_t::IsValid() const
{
return ( (port !=0 ) && (type != NA_NULL) &&
( ip[0] != 0 || ip[1] != 0 || ip[2] != 0 || ip[3] != 0 ) );
}
#ifdef _WIN32
#undef SetPort // get around stupid WINSPOOL.H macro
#endif
void netadr_t::SetPort(unsigned short newport)
{
port = BigShort( newport );
}
void netadr_t::SetFromString( const char *pch, bool bUseDNS )
{
Clear();
type = NA_IP;
Assert( pch ); // invalid to call this with NULL pointer; fix your code bug!
if ( !pch ) // but let's not crash
return;
if ( pch[0] >= '0' && pch[0] <= '9' && strchr( pch, '.' ) )
{
int n1, n2, n3, n4, n5;
int nRes = sscanf( pch, "%d.%d.%d.%d:%d", &n1, &n2, &n3, &n4, &n5 );
if ( nRes >= 4 )
{
SetIP( n1, n2, n3, n4 );
}
if ( nRes == 5 )
{
SetPort( ( uint16 ) n5 );
}
}
else if ( bUseDNS )
{
// X360TBD:
#if !defined( _X360 )
char szHostName[ 256 ];
Q_strncpy( szHostName, pch, sizeof(szHostName) );
char *pchColon = strchr( szHostName, ':' );
if ( pchColon )
{
*pchColon = 0;
}
// DNS it
struct hostent *h = gethostbyname( szHostName );
if ( !h )
return;
SetIP( ntohl( *(int *)h->h_addr_list[0] ) );
if ( pchColon )
{
SetPort( atoi( ++pchColon ) );
}
#else
Assert( 0 );
#endif
}
}
bool netadr_t::operator<(const netadr_t &netadr) const
{
if ( *((uint *)netadr.ip) < *((uint *)ip) )
return true;
else if ( *((uint *)netadr.ip) > *((uint *)ip) )
return false;
return ( netadr.port < port );
}
void netadr_t::SetFromSocket( int hSocket )
{
#if !defined(_X360)
Clear();
type = NA_IP;
struct sockaddr address;
int namelen = sizeof(address);
if ( getsockname( hSocket, (struct sockaddr *)&address, (socklen_t *)&namelen) == 0 )
{
SetFromSockadr( &address );
}
#else
Assert(0);
#endif
}

1269
tier1/bitbuf.cpp Normal file

File diff suppressed because it is too large Load Diff

90
tier1/byteswap.cpp Normal file
View File

@ -0,0 +1,90 @@
//========= Copyright © 1996-2006, Valve LLC, All rights reserved. ============
//
// Purpose: Low level byte swapping routines.
//
// $NoKeywords: $
//=============================================================================
#include "byteswap.h"
//-----------------------------------------------------------------------------
// Copy a single field from the input buffer to the output buffer, swapping the bytes if necessary
//-----------------------------------------------------------------------------
void CByteswap::SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typedescription_t *pField )
{
switch ( pField->fieldType )
{
case FIELD_CHARACTER:
SwapBufferToTargetEndian<char>( (char*)pOutputBuffer, (char*)pData, pField->fieldSize );
break;
case FIELD_BOOLEAN:
SwapBufferToTargetEndian<bool>( (bool*)pOutputBuffer, (bool*)pData, pField->fieldSize );
break;
case FIELD_SHORT:
SwapBufferToTargetEndian<short>( (short*)pOutputBuffer, (short*)pData, pField->fieldSize );
break;
case FIELD_FLOAT:
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize );
break;
case FIELD_INTEGER:
SwapBufferToTargetEndian<int>( (int*)pOutputBuffer, (int*)pData, pField->fieldSize );
break;
case FIELD_VECTOR:
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 3 );
break;
case FIELD_VECTOR2D:
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 2 );
break;
case FIELD_QUATERNION:
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 4 );
break;
case FIELD_EMBEDDED:
{
typedescription_t *pEmbed = pField->td->dataDesc;
for ( int i = 0; i < pField->fieldSize; ++i )
{
SwapFieldsToTargetEndian( (byte*)pOutputBuffer + pEmbed->fieldOffset,
(byte*)pData + pEmbed->fieldOffset,
pField->td );
pOutputBuffer = (byte*)pOutputBuffer + pField->fieldSizeInBytes;
pData = (byte*)pData + pField->fieldSizeInBytes;
}
}
break;
default:
assert(0);
}
}
//-----------------------------------------------------------------------------
// Write a block of fields. Works a bit like the saverestore code.
//-----------------------------------------------------------------------------
void CByteswap::SwapFieldsToTargetEndian( void *pOutputBuffer, void *pBaseData, datamap_t *pDataMap )
{
// deal with base class first
if ( pDataMap->baseMap )
{
SwapFieldsToTargetEndian( pOutputBuffer, pBaseData, pDataMap->baseMap );
}
typedescription_t *pFields = pDataMap->dataDesc;
int fieldCount = pDataMap->dataNumFields;
for ( int i = 0; i < fieldCount; ++i )
{
typedescription_t *pField = &pFields[i];
SwapFieldToTargetEndian( (BYTE*)pOutputBuffer + pField->fieldOffset,
(BYTE*)pBaseData + pField->fieldOffset,
pField );
}
}

41
tier1/characterset.cpp Normal file
View File

@ -0,0 +1,41 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================
#include <string.h>
#include "characterset.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: builds a simple lookup table of a group of important characters
// Input : *pParseGroup - pointer to the buffer for the group
// *pGroupString - null terminated list of characters to flag
//-----------------------------------------------------------------------------
void CharacterSetBuild( characterset_t *pSetBuffer, const char *pszSetString )
{
int i = 0;
// Test our pointers
if ( !pSetBuffer || !pszSetString )
return;
memset( pSetBuffer->set, 0, sizeof(pSetBuffer->set) );
while ( pszSetString[i] )
{
pSetBuffer->set[ static_cast<size_t>(pszSetString[i]) ] = 1;
i++;
}
}

180
tier1/checksum_crc.cpp Normal file
View File

@ -0,0 +1,180 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Generic CRC functions
//
//=============================================================================//
#include "basetypes.h"
#include "commonmacros.h"
#include "checksum_crc.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define CRC32_INIT_VALUE 0xFFFFFFFFUL
#define CRC32_XOR_VALUE 0xFFFFFFFFUL
#define NUM_BYTES 256
static const CRC32_t pulCRCTable[NUM_BYTES] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
void CRC32_Init(CRC32_t *pulCRC)
{
*pulCRC = CRC32_INIT_VALUE;
}
void CRC32_Final(CRC32_t *pulCRC)
{
*pulCRC ^= CRC32_XOR_VALUE;
}
CRC32_t CRC32_GetTableEntry( unsigned int slot )
{
return pulCRCTable[(unsigned char)slot];
}
void CRC32_ProcessBuffer(CRC32_t *pulCRC, const void *pBuffer, int nBuffer)
{
CRC32_t ulCrc = *pulCRC;
unsigned char *pb = (unsigned char *)pBuffer;
unsigned int nFront;
int nMain;
JustAfew:
switch (nBuffer)
{
case 7:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 6:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 5:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 4:
ulCrc ^= LittleLong( *(CRC32_t *)pb );
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
*pulCRC = ulCrc;
return;
case 3:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 2:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 1:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 0:
*pulCRC = ulCrc;
return;
}
// We may need to do some alignment work up front, and at the end, so that
// the main loop is aligned and only has to worry about 8 byte at a time.
//
// The low-order two bits of pb and nBuffer in total control the
// upfront work.
//
nFront = ((unsigned int)pb) & 3;
nBuffer -= nFront;
switch (nFront)
{
case 3:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 2:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 1:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
}
nMain = nBuffer >> 3;
while (nMain--)
{
ulCrc ^= LittleLong( *(CRC32_t *)pb );
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc ^= LittleLong( *(CRC32_t *)(pb + 4) );
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
pb += 8;
}
nBuffer &= 7;
goto JustAfew;
}

271
tier1/checksum_md5.cpp Normal file
View File

@ -0,0 +1,271 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "basetypes.h"
#include "commonmacros.h"
#include "checksum_md5.h"
#include <string.h>
#include <stdio.h>
#include "tier1/strtools.h"
#include "tier0/dbg.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// The four core functions - F1 is optimized somewhat
// #define F1(x, y, z) (x & y | ~x & z)
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
// This is the central step in the MD5 algorithm.
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
//-----------------------------------------------------------------------------
// Purpose: The core of the MD5 algorithm, this alters an existing MD5 hash to
// reflect the addition of 16 longwords of new data. MD5Update blocks
// the data and converts bytes into longwords for this routine.
// Input : buf[4] -
// in[16] -
// Output : static void
//-----------------------------------------------------------------------------
static void MD5Transform(unsigned int buf[4], unsigned int const in[16])
{
register unsigned int a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
//-----------------------------------------------------------------------------
// Purpose: Start MD5 accumulation. Set bit count to 0 and buffer to mysterious initialization constants.
// Input : *ctx -
//-----------------------------------------------------------------------------
void MD5Init(MD5Context_t *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Update context to reflect the concatenation of another buffer full of bytes.
// Input : *ctx -
// *buf -
// len -
//-----------------------------------------------------------------------------
void MD5Update(MD5Context_t *ctx, unsigned char const *buf, unsigned int len)
{
unsigned int t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((unsigned int) len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if (t)
{
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t)
{
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
//byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64)
{
memcpy(ctx->in, buf, 64);
//byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
//-----------------------------------------------------------------------------
// Purpose: Final wrapup - pad to 64-byte boundary with the bit pattern
// 1 0* (64-bit count of bits processed, MSB-first)
// Input : digest[MD5_DIGEST_LENGTH] -
// *ctx -
//-----------------------------------------------------------------------------
void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5Context_t *ctx)
{
unsigned count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8)
{
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
//byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
}
else
{
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
//byteReverse(ctx->in, 14);
/* Append length in bits and transform */
((unsigned int *) ctx->in)[14] = ctx->bits[0];
((unsigned int *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
//byteReverse((unsigned char *) ctx->buf, 4);
memcpy(digest, ctx->buf, MD5_DIGEST_LENGTH);
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *hash -
// hashlen -
// Output : char
//-----------------------------------------------------------------------------
char *MD5_Print( unsigned char *hash, int hashlen )
{
static char szReturn[64];
Assert( hashlen <= 32 );
Q_binarytohex( hash, hashlen, szReturn, sizeof( szReturn ) );
return szReturn;
}
//-----------------------------------------------------------------------------
// Purpose: generate pseudo random number from a seed number
// Input : seed number
// Output : pseudo random number
//-----------------------------------------------------------------------------
unsigned int MD5_PseudoRandom(unsigned int nSeed)
{
MD5Context_t ctx;
unsigned char digest[MD5_DIGEST_LENGTH]; // The MD5 Hash
memset( &ctx, 0, sizeof( ctx ) );
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char*)&nSeed, sizeof(nSeed) );
MD5Final(digest, &ctx);
return *(unsigned int*)(digest+6); // use 4 middle bytes for random value
}

636
tier1/commandbuffer.cpp Normal file
View File

@ -0,0 +1,636 @@
//===== Copyright © 1996-2006, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//===========================================================================//
#include "tier1/CommandBuffer.h"
#include "tier1/utlbuffer.h"
#include "tier1/strtools.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define MAX_ALIAS_NAME 32
#define MAX_COMMAND_LENGTH 1024
struct cmdalias_t
{
cmdalias_t *next;
char name[ MAX_ALIAS_NAME ];
char *value;
};
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CCommandBuffer::CCommandBuffer( ) : m_Commands( 32, 32 )
{
m_hNextCommand = m_Commands.InvalidIndex();
m_nWaitDelayTicks = 1;
m_nCurrentTick = 0;
m_nLastTickToProcess = -1;
m_nArgSBufferSize = 0;
m_bIsProcessingCommands = false;
m_nMaxArgSBufferLength = ARGS_BUFFER_LENGTH;
}
CCommandBuffer::~CCommandBuffer()
{
}
//-----------------------------------------------------------------------------
// Indicates how long to delay when encoutering a 'wait' command
//-----------------------------------------------------------------------------
void CCommandBuffer::SetWaitDelayTime( int nTickDelay )
{
Assert( nTickDelay >= 0 );
m_nWaitDelayTicks = nTickDelay;
}
//-----------------------------------------------------------------------------
// Specifies a max limit of the args buffer. For unittesting. Size == 0 means use default
//-----------------------------------------------------------------------------
void CCommandBuffer::LimitArgumentBufferSize( int nSize )
{
if ( nSize > ARGS_BUFFER_LENGTH )
{
nSize = ARGS_BUFFER_LENGTH;
}
m_nMaxArgSBufferLength = ( nSize == 0 ) ? ARGS_BUFFER_LENGTH : nSize;
}
//-----------------------------------------------------------------------------
// Parses argv0 out of the buffer
//-----------------------------------------------------------------------------
bool CCommandBuffer::ParseArgV0( CUtlBuffer &buf, char *pArgV0, int nMaxLen, const char **pArgS )
{
pArgV0[0] = 0;
*pArgS = NULL;
if ( !buf.IsValid() )
return false;
int nSize = buf.ParseToken( CCommand::DefaultBreakSet(), pArgV0, nMaxLen );
if ( ( nSize <= 0 ) || ( nMaxLen == nSize ) )
return false;
int nArgSLen = buf.TellMaxPut() - buf.TellGet();
*pArgS = (nArgSLen > 0) ? (const char*)buf.PeekGet() : NULL;
return true;
}
//-----------------------------------------------------------------------------
// Insert a command into the command queue
//-----------------------------------------------------------------------------
void CCommandBuffer::InsertCommandAtAppropriateTime( int hCommand )
{
int i;
Command_t &command = m_Commands[hCommand];
for ( i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) )
{
if ( m_Commands[i].m_nTick > command.m_nTick )
break;
}
m_Commands.LinkBefore( i, hCommand );
}
//-----------------------------------------------------------------------------
// Insert a command into the command queue at the appropriate time
//-----------------------------------------------------------------------------
void CCommandBuffer::InsertImmediateCommand( int hCommand )
{
m_Commands.LinkBefore( m_hNextCommand, hCommand );
}
//-----------------------------------------------------------------------------
// Insert a command into the command queue
//-----------------------------------------------------------------------------
bool CCommandBuffer::InsertCommand( const char *pArgS, int nCommandSize, int nTick )
{
if ( nCommandSize >= CCommand::MaxCommandLength() )
{
Warning( "WARNING: Command too long... ignoring!\n%s\n", pArgS );
return false;
}
// Add one for null termination
if ( m_nArgSBufferSize + nCommandSize + 1 > m_nMaxArgSBufferLength )
{
Compact();
if ( m_nArgSBufferSize + nCommandSize + 1 > m_nMaxArgSBufferLength )
return false;
}
memcpy( &m_pArgSBuffer[m_nArgSBufferSize], pArgS, nCommandSize );
m_pArgSBuffer[m_nArgSBufferSize + nCommandSize] = 0;
++nCommandSize;
int hCommand = m_Commands.Alloc();
Command_t &command = m_Commands[hCommand];
command.m_nTick = nTick;
command.m_nFirstArgS = m_nArgSBufferSize;
command.m_nBufferSize = nCommandSize;
m_nArgSBufferSize += nCommandSize;
if ( !m_bIsProcessingCommands || ( nTick > m_nCurrentTick ) )
{
InsertCommandAtAppropriateTime( hCommand );
}
else
{
InsertImmediateCommand( hCommand );
}
return true;
}
//-----------------------------------------------------------------------------
// Returns the length of the next command
//-----------------------------------------------------------------------------
void CCommandBuffer::GetNextCommandLength( const char *pText, int nMaxLen, int *pCommandLength, int *pNextCommandOffset )
{
int nCommandLength = 0;
int nNextCommandOffset;
bool bIsQuoted = false;
bool bIsCommented = false;
for ( nNextCommandOffset=0; nNextCommandOffset < nMaxLen; ++nNextCommandOffset, nCommandLength += bIsCommented ? 0 : 1 )
{
char c = pText[nNextCommandOffset];
if ( !bIsCommented )
{
if ( c == '"' )
{
bIsQuoted = !bIsQuoted;
continue;
}
// don't break if inside a C++ style comment
if ( !bIsQuoted && c == '/' )
{
bIsCommented = ( nNextCommandOffset < nMaxLen-1 ) && pText[nNextCommandOffset+1] == '/';
if ( bIsCommented )
{
++nNextCommandOffset;
continue;
}
}
// don't break if inside a quoted string
if ( !bIsQuoted && c == ';' )
break;
}
// FIXME: This is legacy behavior; should we not break if a \n is inside a quoted string?
if ( c == '\n' )
break;
}
*pCommandLength = nCommandLength;
*pNextCommandOffset = nNextCommandOffset;
}
//-----------------------------------------------------------------------------
// Add text to command buffer, return false if it couldn't owing to overflow
//-----------------------------------------------------------------------------
bool CCommandBuffer::AddText( const char *pText, int nTickDelay )
{
Assert( nTickDelay >= 0 );
int nLen = Q_strlen( pText );
int nTick = m_nCurrentTick + nTickDelay;
// Parse the text into distinct commands
const char *pCurrentCommand = pText;
int nOffsetToNextCommand;
for( ; nLen > 0; nLen -= nOffsetToNextCommand+1, pCurrentCommand += nOffsetToNextCommand+1 )
{
// find a \n or ; line break
int nCommandLength;
GetNextCommandLength( pCurrentCommand, nLen, &nCommandLength, &nOffsetToNextCommand );
if ( nCommandLength <= 0 )
continue;
const char *pArgS;
char *pArgV0 = (char*)_alloca( nCommandLength+1 );
CUtlBuffer bufParse( pCurrentCommand, nCommandLength, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
ParseArgV0( bufParse, pArgV0, nCommandLength+1, &pArgS );
if ( pArgV0[0] == 0 )
continue;
// Deal with the special 'wait' command
if ( !Q_stricmp( pArgV0, "wait" ) )
{
int nDelay = pArgS ? atoi( pArgS ) : m_nWaitDelayTicks;
nTick += nDelay;
continue;
}
if ( !InsertCommand( pCurrentCommand, nCommandLength, nTick ) )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Are we in the middle of processing commands?
//-----------------------------------------------------------------------------
bool CCommandBuffer::IsProcessingCommands()
{
return m_bIsProcessingCommands;
}
//-----------------------------------------------------------------------------
// Delays all queued commands to execute at a later time
//-----------------------------------------------------------------------------
void CCommandBuffer::DelayAllQueuedCommands( int nDelay )
{
if ( nDelay <= 0 )
return;
for ( int i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) )
{
m_Commands[i].m_nTick += nDelay;
}
}
//-----------------------------------------------------------------------------
// Call this to begin iterating over all commands up to flCurrentTime
//-----------------------------------------------------------------------------
void CCommandBuffer::BeginProcessingCommands( int nDeltaTicks )
{
if ( nDeltaTicks == 0 )
return;
Assert( !m_bIsProcessingCommands );
m_bIsProcessingCommands = true;
m_nLastTickToProcess = m_nCurrentTick + nDeltaTicks - 1;
// Necessary to insert commands while commands are being processed
m_hNextCommand = m_Commands.Head();
}
//-----------------------------------------------------------------------------
// Returns the next command
//-----------------------------------------------------------------------------
bool CCommandBuffer::DequeueNextCommand( )
{
m_CurrentCommand.Reset();
Assert( m_bIsProcessingCommands );
if ( m_Commands.Count() == 0 )
return false;
int nHead = m_Commands.Head();
Command_t &command = m_Commands[ nHead ];
if ( command.m_nTick > m_nLastTickToProcess )
return false;
m_nCurrentTick = command.m_nTick;
// Copy the current command into a temp buffer
// NOTE: This is here to avoid the pointers returned by DequeueNextCommand
// to become invalid by calling AddText. Is there a way we can avoid the memcpy?
if ( command.m_nBufferSize > 0 )
{
m_CurrentCommand.Tokenize( &m_pArgSBuffer[command.m_nFirstArgS] );
}
m_Commands.Remove( nHead );
// Necessary to insert commands while commands are being processed
m_hNextCommand = m_Commands.Head();
// Msg("Dequeue : ");
// for ( int i = 0; i < nArgc; ++i )
// {
// Msg("%s ", m_pCurrentArgv[i] );
// }
// Msg("\n");
return true;
}
//-----------------------------------------------------------------------------
// Returns the next command
//-----------------------------------------------------------------------------
int CCommandBuffer::DequeueNextCommand( const char **& ppArgv )
{
DequeueNextCommand();
ppArgv = ArgV();
return ArgC();
}
//-----------------------------------------------------------------------------
// Compacts the command buffer
//-----------------------------------------------------------------------------
void CCommandBuffer::Compact()
{
// Compress argvbuffer + argv
// NOTE: I'm using this choice instead of calling malloc + free
// per command to allocate arguments because I expect to post a
// bunch of commands but not have many delayed commands;
// avoiding the allocation cost seems more important that the memcpy
// cost here since I expect to not have much to copy.
m_nArgSBufferSize = 0;
char pTempBuffer[ ARGS_BUFFER_LENGTH ];
for ( int i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) )
{
Command_t &command = m_Commands[ i ];
memcpy( &pTempBuffer[m_nArgSBufferSize], &m_pArgSBuffer[command.m_nFirstArgS], command.m_nBufferSize );
command.m_nFirstArgS = m_nArgSBufferSize;
m_nArgSBufferSize += command.m_nBufferSize;
}
// NOTE: We could also store 2 buffers in the command buffer and switch
// between the two to avoid the 2nd memcpy; but again I'm guessing the memory
// tradeoff isn't worth it
memcpy( m_pArgSBuffer, pTempBuffer, m_nArgSBufferSize );
}
//-----------------------------------------------------------------------------
// Call this to finish iterating over all commands
//-----------------------------------------------------------------------------
void CCommandBuffer::EndProcessingCommands()
{
Assert( m_bIsProcessingCommands );
m_bIsProcessingCommands = false;
m_nCurrentTick = m_nLastTickToProcess + 1;
m_hNextCommand = m_Commands.InvalidIndex();
// Extract commands that are before the end time
// NOTE: This is a bug for this to
int i = m_Commands.Head();
if ( i == m_Commands.InvalidIndex() )
{
m_nArgSBufferSize = 0;
return;
}
while ( i != m_Commands.InvalidIndex() )
{
if ( m_Commands[i].m_nTick >= m_nCurrentTick )
break;
AssertMsgOnce( false, "CCommandBuffer::EndProcessingCommands() called before all appropriate commands were dequeued.\n" );
int nNext = i;
Msg( "Warning: Skipping command %s\n", m_pArgSBuffer[ m_Commands[i].m_nFirstArgS ] );
m_Commands.Remove( i );
i = nNext;
}
Compact();
}
//-----------------------------------------------------------------------------
// Returns a handle to the next command to process
//-----------------------------------------------------------------------------
CommandHandle_t CCommandBuffer::GetNextCommandHandle()
{
Assert( m_bIsProcessingCommands );
return m_Commands.Head();
}
#if 0
/*
===============
Cmd_Alias_f
Creates a new command that executes a command string (possibly ; seperated)
===============
*/
void Cmd_Alias_f (void)
{
cmdalias_t *a;
char cmd[MAX_COMMAND_LENGTH];
int i, c;
char *s;
if (Cmd_Argc() == 1)
{
Con_Printf ("Current alias commands:\n");
for (a = cmd_alias ; a ; a=a->next)
Con_Printf ("%s : %s\n", a->name, a->value);
return;
}
s = Cmd_Argv(1);
if (strlen(s) >= MAX_ALIAS_NAME)
{
Con_Printf ("Alias name is too long\n");
return;
}
// copy the rest of the command line
cmd[0] = 0; // start out with a null string
c = Cmd_Argc();
for (i=2 ; i< c ; i++)
{
Q_strncat(cmd, Cmd_Argv(i), sizeof( cmd ), COPY_ALL_CHARACTERS);
if (i != c)
{
Q_strncat (cmd, " ", sizeof( cmd ), COPY_ALL_CHARACTERS );
}
}
Q_strncat (cmd, "\n", sizeof( cmd ), COPY_ALL_CHARACTERS);
// if the alias already exists, reuse it
for (a = cmd_alias ; a ; a=a->next)
{
if (!strcmp(s, a->name))
{
if ( !strcmp( a->value, cmd ) ) // Re-alias the same thing
return;
delete[] a->value;
break;
}
}
if (!a)
{
a = (cmdalias_t *)new cmdalias_t;
a->next = cmd_alias;
cmd_alias = a;
}
Q_strncpy (a->name, s, sizeof( a->name ) );
a->value = COM_StringCopy(cmd);
}
/*
=============================================================================
COMMAND EXECUTION
=============================================================================
*/
#define MAX_ARGS 80
static int cmd_argc;
static char *cmd_argv[MAX_ARGS];
static char *cmd_null_string = "";
static const char *cmd_args = NULL;
cmd_source_t cmd_source;
//-----------------------------------------------------------------------------
// Purpose:
// Output : void Cmd_Init
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void Cmd_Shutdown( void )
{
// TODO, cleanup
while ( cmd_alias )
{
cmdalias_t *next = cmd_alias->next;
delete cmd_alias->value; // created by StringCopy()
delete cmd_alias;
cmd_alias = next;
}
}
/*
============
Cmd_ExecuteString
A complete command line has been parsed, so try to execute it
FIXME: lookupnoadd the token to speed search?
============
*/
const ConCommandBase *Cmd_ExecuteString (const char *text, cmd_source_t src)
{
cmdalias_t *a;
cmd_source = src;
Cmd_TokenizeString (text);
// execute the command line
if (!Cmd_Argc())
return NULL; // no tokens
// check alias
for (a=cmd_alias ; a ; a=a->next)
{
if (!Q_strcasecmp (cmd_argv[0], a->name))
{
Cbuf_InsertText (a->value);
return NULL;
}
}
// check ConCommands
ConCommandBase const *pCommand = ConCommandBase::FindCommand( cmd_argv[ 0 ] );
if ( pCommand && pCommand->IsCommand() )
{
bool isServerCommand = ( pCommand->IsBitSet( FCVAR_GAMEDLL ) &&
// Typed at console
cmd_source == src_command &&
// Not HLDS
!sv.IsDedicated() );
// Hook to allow game .dll to figure out who type the message on a listen server
if ( serverGameClients )
{
// We're actually the server, so set it up locally
if ( sv.IsActive() )
{
g_pServerPluginHandler->SetCommandClient( -1 );
#ifndef SWDS
// Special processing for listen server player
if ( isServerCommand )
{
g_pServerPluginHandler->SetCommandClient( cl.m_nPlayerSlot );
}
#endif
}
// We're not the server, but we've been a listen server (game .dll loaded)
// forward this command tot he server instead of running it locally if we're still
// connected
// Otherwise, things like "say" won't work unless you quit and restart
else if ( isServerCommand )
{
if ( cl.IsConnected() )
{
Cmd_ForwardToServer();
return NULL;
}
else
{
// It's a server command, but we're not connected to a server. Don't try to execute it.
return NULL;
}
}
}
// Allow cheat commands in singleplayer, debug, or multiplayer with sv_cheats on
#ifndef _DEBUG
if ( pCommand->IsBitSet( FCVAR_CHEAT ) )
{
if ( !Host_IsSinglePlayerGame() && sv_cheats.GetInt() == 0 )
{
Msg( "Can't use cheat command %s in multiplayer, unless the server has sv_cheats set to 1.\n", pCommand->GetName() );
return NULL;
}
}
#endif
(( ConCommand * )pCommand )->Dispatch();
return pCommand;
}
// check cvars
if ( cv->IsCommand() )
{
return pCommand;
}
// forward the command line to the server, so the entity DLL can parse it
if ( cmd_source == src_command )
{
if ( cl.IsConnected() )
{
Cmd_ForwardToServer();
return NULL;
}
}
Msg("Unknown command \"%s\"\n", Cmd_Argv(0));
return NULL;
}
#endif

1287
tier1/convar.cpp Normal file

File diff suppressed because it is too large Load Diff

410
tier1/datamanager.cpp Normal file
View File

@ -0,0 +1,410 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "basetypes.h"
#include "datamanager.h"
DECLARE_POINTER_HANDLE( memhandle_t );
#define AUTO_LOCK_DM() AUTO_LOCK_( CDataManagerBase, *this )
CDataManagerBase::CDataManagerBase( unsigned int maxSize )
{
m_targetMemorySize = maxSize;
m_memUsed = 0;
m_lruList = m_memoryLists.CreateList();
m_lockList = m_memoryLists.CreateList();
m_freeList = m_memoryLists.CreateList();
m_listsAreFreed = 0;
}
CDataManagerBase::~CDataManagerBase()
{
Assert( m_listsAreFreed );
}
void CDataManagerBase::NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize )
{
Lock();
m_memUsed += (int)newSize - (int)oldSize;
Unlock();
}
void CDataManagerBase::SetTargetSize( unsigned int targetSize )
{
m_targetMemorySize = targetSize;
}
unsigned int CDataManagerBase::FlushAllUnlocked()
{
Lock();
int nFlush = m_memoryLists.Count( m_lruList );
void **pScratch = (void **)_alloca( nFlush * sizeof(void *) );
CUtlVector<void *> destroyList( pScratch, nFlush );
unsigned nBytesInitial = MemUsed_Inline();
int node = m_memoryLists.Head(m_lruList);
while ( node != m_memoryLists.InvalidIndex() )
{
int next = m_memoryLists.Next(node);
m_memoryLists.Unlink( m_lruList, node );
destroyList.AddToTail( GetForFreeByIndex( node ) );
node = next;
}
Unlock();
for ( int i = 0; i < nFlush; i++ )
{
DestroyResourceStorage( destroyList[i] );
}
return ( nBytesInitial - MemUsed_Inline() );
}
unsigned int CDataManagerBase::FlushToTargetSize()
{
return EnsureCapacity(0);
}
// Frees everything! The LRU AND the LOCKED items. This is only used to forcibly free the resources,
// not to make space.
unsigned int CDataManagerBase::FlushAll()
{
Lock();
int nFlush = m_memoryLists.Count( m_lruList ) + m_memoryLists.Count( m_lockList );
void **pScratch = (void **)_alloca( nFlush * sizeof(void *) );
CUtlVector<void *> destroyList( pScratch, nFlush );
unsigned result = MemUsed_Inline();
int node;
int nextNode;
node = m_memoryLists.Head(m_lruList);
while ( node != m_memoryLists.InvalidIndex() )
{
nextNode = m_memoryLists.Next(node);
m_memoryLists.Unlink( m_lruList, node );
destroyList.AddToTail( GetForFreeByIndex( node ) );
node = nextNode;
}
node = m_memoryLists.Head(m_lockList);
while ( node != m_memoryLists.InvalidIndex() )
{
nextNode = m_memoryLists.Next(node);
m_memoryLists.Unlink( m_lockList, node );
m_memoryLists[node].lockCount = 0;
destroyList.AddToTail( GetForFreeByIndex( node ) );
node = nextNode;
}
m_listsAreFreed = false;
Unlock();
for ( int i = 0; i < nFlush; i++ )
{
DestroyResourceStorage( destroyList[i] );
}
return result;
}
unsigned int CDataManagerBase::Purge( unsigned int nBytesToPurge )
{
unsigned int nTargetSize = MemUsed_Inline() - nBytesToPurge;
if ( nTargetSize < 0 )
nTargetSize = 0;
unsigned int nImpliedCapacity = MemTotal_Inline() - nTargetSize;
return EnsureCapacity( nImpliedCapacity );
}
void CDataManagerBase::DestroyResource( memhandle_t handle )
{
Lock();
unsigned short index = FromHandle( handle );
if ( !m_memoryLists.IsValidIndex(index) )
{
Unlock();
return;
}
Assert( m_memoryLists[index].lockCount == 0 );
if ( m_memoryLists[index].lockCount )
BreakLock( handle );
m_memoryLists.Unlink( m_lruList, index );
void *p = GetForFreeByIndex( index );
Unlock();
DestroyResourceStorage( p );
}
void *CDataManagerBase::LockResource( memhandle_t handle )
{
AUTO_LOCK_DM();
unsigned short memoryIndex = FromHandle(handle);
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
if ( m_memoryLists[memoryIndex].lockCount == 0 )
{
m_memoryLists.Unlink( m_lruList, memoryIndex );
m_memoryLists.LinkToTail( m_lockList, memoryIndex );
}
Assert(m_memoryLists[memoryIndex].lockCount != (unsigned short)-1);
m_memoryLists[memoryIndex].lockCount++;
return m_memoryLists[memoryIndex].pStore;
}
return NULL;
}
int CDataManagerBase::UnlockResource( memhandle_t handle )
{
AUTO_LOCK_DM();
unsigned short memoryIndex = FromHandle(handle);
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
Assert( m_memoryLists[memoryIndex].lockCount > 0 );
if ( m_memoryLists[memoryIndex].lockCount > 0 )
{
m_memoryLists[memoryIndex].lockCount--;
if ( m_memoryLists[memoryIndex].lockCount == 0 )
{
m_memoryLists.Unlink( m_lockList, memoryIndex );
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
}
}
return m_memoryLists[memoryIndex].lockCount;
}
return 0;
}
void *CDataManagerBase::GetResource_NoLockNoLRUTouch( memhandle_t handle )
{
AUTO_LOCK_DM();
unsigned short memoryIndex = FromHandle(handle);
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
return m_memoryLists[memoryIndex].pStore;
}
return NULL;
}
void *CDataManagerBase::GetResource_NoLock( memhandle_t handle )
{
AUTO_LOCK_DM();
unsigned short memoryIndex = FromHandle(handle);
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
TouchByIndex( memoryIndex );
return m_memoryLists[memoryIndex].pStore;
}
return NULL;
}
void CDataManagerBase::TouchResource( memhandle_t handle )
{
AUTO_LOCK_DM();
TouchByIndex( FromHandle(handle) );
}
void CDataManagerBase::MarkAsStale( memhandle_t handle )
{
AUTO_LOCK_DM();
unsigned short memoryIndex = FromHandle(handle);
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
if ( m_memoryLists[memoryIndex].lockCount == 0 )
{
m_memoryLists.Unlink( m_lruList, memoryIndex );
m_memoryLists.LinkToHead( m_lruList, memoryIndex );
}
}
}
int CDataManagerBase::BreakLock( memhandle_t handle )
{
AUTO_LOCK_DM();
unsigned short memoryIndex = FromHandle(handle);
if ( memoryIndex != m_memoryLists.InvalidIndex() && m_memoryLists[memoryIndex].lockCount )
{
int nBroken = m_memoryLists[memoryIndex].lockCount;
m_memoryLists[memoryIndex].lockCount = 0;
m_memoryLists.Unlink( m_lockList, memoryIndex );
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
return nBroken;
}
return 0;
}
int CDataManagerBase::BreakAllLocks()
{
AUTO_LOCK_DM();
int nBroken = 0;
int node;
int nextNode;
node = m_memoryLists.Head(m_lockList);
while ( node != m_memoryLists.InvalidIndex() )
{
nBroken++;
nextNode = m_memoryLists.Next(node);
m_memoryLists[node].lockCount = 0;
m_memoryLists.Unlink( m_lockList, node );
m_memoryLists.LinkToTail( m_lruList, node );
node = nextNode;
}
return nBroken;
}
unsigned short CDataManagerBase::CreateHandle( bool bCreateLocked )
{
AUTO_LOCK_DM();
int memoryIndex = m_memoryLists.Head(m_freeList);
unsigned short list = ( bCreateLocked ) ? m_lockList : m_lruList;
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
m_memoryLists.Unlink( m_freeList, memoryIndex );
m_memoryLists.LinkToTail( list, memoryIndex );
}
else
{
memoryIndex = m_memoryLists.AddToTail( list );
}
if ( bCreateLocked )
{
m_memoryLists[memoryIndex].lockCount++;
}
return memoryIndex;
}
memhandle_t CDataManagerBase::StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize )
{
AUTO_LOCK_DM();
resource_lru_element_t &mem = m_memoryLists[memoryIndex];
mem.pStore = pStore;
m_memUsed += realSize;
return ToHandle(memoryIndex);
}
void CDataManagerBase::TouchByIndex( unsigned short memoryIndex )
{
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
if ( m_memoryLists[memoryIndex].lockCount == 0 )
{
m_memoryLists.Unlink( m_lruList, memoryIndex );
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
}
}
}
memhandle_t CDataManagerBase::ToHandle( unsigned short index )
{
unsigned int hiword = m_memoryLists.Element(index).serial;
hiword <<= 16;
index++;
return (memhandle_t)( hiword|index );
}
unsigned int CDataManagerBase::TargetSize()
{
return MemTotal_Inline();
}
unsigned int CDataManagerBase::AvailableSize()
{
return MemAvailable_Inline();
}
unsigned int CDataManagerBase::UsedSize()
{
return MemUsed_Inline();
}
// free resources until there is enough space to hold "size"
unsigned int CDataManagerBase::EnsureCapacity( unsigned int size )
{
unsigned nBytesInitial = MemUsed_Inline();
while ( MemUsed_Inline() > MemTotal_Inline() || MemAvailable_Inline() < size )
{
Lock();
int lruIndex = m_memoryLists.Head( m_lruList );
if ( lruIndex == m_memoryLists.InvalidIndex() )
{
Unlock();
break;
}
m_memoryLists.Unlink( m_lruList, lruIndex );
void *p = GetForFreeByIndex( lruIndex );
Unlock();
DestroyResourceStorage( p );
}
return ( nBytesInitial - MemUsed_Inline() );
}
// free this resource and move the handle to the free list
void *CDataManagerBase::GetForFreeByIndex( unsigned short memoryIndex )
{
void *p = NULL;
if ( memoryIndex != m_memoryLists.InvalidIndex() )
{
Assert( m_memoryLists[memoryIndex].lockCount == 0 );
resource_lru_element_t &mem = m_memoryLists[memoryIndex];
unsigned size = GetRealSize( mem.pStore );
if ( size > m_memUsed )
{
ExecuteOnce( Warning( "Data manager 'used' memory incorrect\n" ) );
size = m_memUsed;
}
m_memUsed -= size;
p = mem.pStore;
mem.pStore = NULL;
mem.serial++;
m_memoryLists.LinkToTail( m_freeList, memoryIndex );
}
return p;
}
// get a list of everything in the LRU
void CDataManagerBase::GetLRUHandleList( CUtlVector< memhandle_t >& list )
{
for ( int node = m_memoryLists.Tail(m_lruList);
node != m_memoryLists.InvalidIndex();
node = m_memoryLists.Previous(node) )
{
list.AddToTail( ToHandle( node ) );
}
}
// get a list of everything locked
void CDataManagerBase::GetLockHandleList( CUtlVector< memhandle_t >& list )
{
for ( int node = m_memoryLists.Head(m_lockList);
node != m_memoryLists.InvalidIndex();
node = m_memoryLists.Next(node) )
{
list.AddToTail( ToHandle( node ) );
}
}

547
tier1/diff.cpp Normal file
View File

@ -0,0 +1,547 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier1/diff.h"
#include "mathlib/mathlib.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// format of diff output:
// 0NN (N=1..127) copy next N literaly
//
// 1NN (N=1..127) ofs (-128..127) copy next N bytes from original, changin offset by N bytes from
// last copy end
// 100 N ofs(-32768..32767) copy next N, with larger delta offset
// 00 NNNN(1..65535) ofs(-32768..32767) big copy from old
// 80 00 NN NN NN big raw copy
//
// available codes (could be used for additonal compression ops)
// long offset form whose offset could have fit in short offset
// note - this algorithm uses storage equal to 8* the old buffer size. 64k=.5mb
#define MIN_MATCH_LEN 8
#define ACCEPTABLE_MATCH_LEN 4096
struct BlockPtr
{
BlockPtr *Next;
uint8 const *dataptr;
};
template<class T,class V> static inline void AddToHead(T * & head, V * node)
{
node->Next=head;
head=node;
}
void Fail(char const *msg)
{
Assert(0);
}
void ApplyDiffs(uint8 const *OldBlock, uint8 const *DiffList,
int OldSize, int DiffListSize, int &ResultListSize,uint8 *Output,uint32 OutSize)
{
uint8 const *copy_src=OldBlock;
uint8 const *end_of_diff_list=DiffList+DiffListSize;
uint8 const *obuf=Output;
while(DiffList<end_of_diff_list)
{
// printf("dptr=%x ",DiffList-d);
uint8 op=*(DiffList++);
if (op==0)
{
uint16 copy_sz=DiffList[0]+256*DiffList[1];
int copy_ofs=DiffList[2]+DiffList[3]*256;
if (copy_ofs>32767)
copy_ofs|=0xffff0000;
// printf("long cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
memcpy(Output,copy_src+copy_ofs,copy_sz);
Output+=copy_sz;
copy_src=copy_src+copy_ofs+copy_sz;
DiffList+=4;
}
else
{
if (op & 0x80)
{
int copy_sz=op & 0x7f;
int copy_ofs;
if (copy_sz==0)
{
copy_sz=DiffList[0];
if (copy_sz==0)
{
// big raw copy
copy_sz=DiffList[1]+256*DiffList[2]+65536*DiffList[3];
memcpy(Output,DiffList+4,copy_sz);
// printf("big rawcopy to %x len=%d\n", Output-obuf,copy_sz);
DiffList+=copy_sz+4;
Output+=copy_sz;
}
else
{
copy_ofs=DiffList[1]+(DiffList[2]*256);
if (copy_ofs>32767)
copy_ofs|=0xffff0000;
// printf("long ofs cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
memcpy(Output,copy_src+copy_ofs,copy_sz);
Output+=copy_sz;
copy_src=copy_src+copy_ofs+copy_sz;
DiffList+=3;
}
}
else
{
copy_ofs=DiffList[0];
if (copy_ofs>127)
copy_ofs|=0xffffff80;
// printf("cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
memcpy(Output,copy_src+copy_ofs,copy_sz);
Output+=copy_sz;
copy_src=copy_src+copy_ofs+copy_sz;
DiffList++;
}
}
else
{
// printf("raw copy %d to %x\n",op & 127,Output-obuf);
memcpy(Output,DiffList,op & 127);
Output+=op & 127;
DiffList+=(op & 127);
}
}
}
ResultListSize=Output-obuf;
}
static void CopyPending(int len, uint8 const *rawbytes,uint8 * &outbuf, uint8 const *limit)
{
// printf("copy raw len=%d\n",len);
if (len<128)
{
if (limit-outbuf < len+1)
Fail("diff buffer overrun");
*(outbuf++)=len;
memcpy(outbuf,rawbytes,len);
outbuf+=len;
}
else
{
if (limit-outbuf < len+5)
Fail("diff buffer overrun");
*(outbuf++)=0x80;
*(outbuf++)=0x00;
*(outbuf++)=(len & 255);
*(outbuf++)=((len>>8) & 255);
*(outbuf++)=((len>>16) & 255);
memcpy(outbuf,rawbytes,len);
outbuf+=len;
}
}
static uint32 hasher(uint8 const *mdata)
{
// attempt to scramble the bits of h1 and h2 together
uint32 ret=0;
for(int i=0;i<MIN_MATCH_LEN;i++)
{
ret=ret<<4;
ret+=(*mdata++);
}
return ret;
}
int FindDiffsForLargeFiles(uint8 const *NewBlock, uint8 const *OldBlock,
int NewSize, int OldSize, int &DiffListSize,uint8 *Output,
uint32 OutSize,
int hashsize)
{
int ret=0;
if (OldSize!=NewSize)
ret=1;
// first, build the hash table
BlockPtr **HashedMatches=new BlockPtr* [hashsize];
memset(HashedMatches,0,sizeof(HashedMatches[0])*hashsize);
BlockPtr *Blocks=0;
if (OldSize)
Blocks=new BlockPtr[OldSize];
BlockPtr *FreeList=Blocks;
// now, build the hash table
uint8 const *walk=OldBlock;
if (OldBlock && OldSize)
while(walk<OldBlock+OldSize-MIN_MATCH_LEN)
{
uint32 hash1=hasher(walk);
hash1 &=(hashsize-1);
BlockPtr *newnode=FreeList;
FreeList++;
newnode->dataptr=walk;
AddToHead(HashedMatches[hash1],newnode);
walk++;
}
else
ret=1;
// now, we have the hash table which may be used to search. begin the output step
int pending_raw_len=0;
walk=NewBlock;
uint8 *outbuf=Output;
uint8 const *lastmatchend=OldBlock;
while(walk<NewBlock+NewSize)
{
int longest=0;
BlockPtr *longest_block=0;
if (walk<NewBlock+NewSize-MIN_MATCH_LEN)
{
// check for a match
uint32 hash1=hasher(walk);
hash1 &= (hashsize-1);
// now, find the longest match in the hash table. If we find one >MIN_MATCH_LEN, take it
for(BlockPtr *b=HashedMatches[hash1];b;b=b->Next)
{
// find the match length
int match_of=b->dataptr-lastmatchend;
if ((match_of>-32768) && (match_of<32767))
{
int max_mlength=MIN(65535,OldBlock+OldSize-b->dataptr);
max_mlength=MIN(max_mlength,NewBlock+NewSize-walk);
int i;
for(i=0;i<max_mlength;i++)
if (walk[i]!=b->dataptr[i])
break;
if ((i>MIN_MATCH_LEN) && (i>longest))
{
longest=i;
longest_block=b;
if (longest>ACCEPTABLE_MATCH_LEN)
break;
}
}
}
}
// now, we have a match maybe
if (longest_block)
{
if (pending_raw_len) // must output
{
ret=1;
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
pending_raw_len=0;
}
// now, output copy block
int match_of=longest_block->dataptr-lastmatchend;
int nremaining=OutSize-(outbuf-Output);
if (match_of)
ret=1;
// printf("copy from %x to %x len=%d\n", match_of,outbuf-Output,longest);
if (longest>127)
{
// use really long encoding
if (nremaining<5)
Fail("diff buff needs increase");
*(outbuf++)=00;
*(outbuf++)=(longest & 255);
*(outbuf++)=((longest>>8) & 255);
*(outbuf++)=(match_of & 255);
*(outbuf++)=((match_of>>8) & 255);
}
else
{
if ((match_of>=-128) && (match_of<128))
{
if (nremaining<2)
Fail("diff buff needs increase");
*(outbuf++)=128+longest;
*(outbuf++)=(match_of&255);
}
else
{
// use long encoding
if (nremaining<4)
Fail("diff buff needs increase");
*(outbuf++)=0x80;
*(outbuf++)=longest;
*(outbuf++)=(match_of & 255);
*(outbuf++)=((match_of>>8) & 255);
}
}
lastmatchend=longest_block->dataptr+longest;
walk+=longest;
}
else
{
walk++;
pending_raw_len++;
}
}
// now, flush pending raw copy
if (pending_raw_len) // must output
{
ret=1;
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
pending_raw_len=0;
}
delete[] HashedMatches;
if (Blocks)
delete[] Blocks;
DiffListSize=outbuf-Output;
return ret;
}
int FindDiffs(uint8 const *NewBlock, uint8 const *OldBlock,
int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize)
{
int ret=0;
if (OldSize!=NewSize)
ret=1;
// first, build the hash table
BlockPtr *HashedMatches[65536];
memset(HashedMatches,0,sizeof(HashedMatches));
BlockPtr *Blocks=0;
if (OldSize)
Blocks=new BlockPtr[OldSize];
BlockPtr *FreeList=Blocks;
// now, build the hash table
uint8 const *walk=OldBlock;
if (OldBlock && OldSize)
while(walk<OldBlock+OldSize-MIN_MATCH_LEN)
{
uint16 hash1=*((uint16 const *) walk)+*((uint16 const *) walk+2);
BlockPtr *newnode=FreeList;
FreeList++;
newnode->dataptr=walk;
AddToHead(HashedMatches[hash1],newnode);
walk++;
}
else
ret=1;
// now, we have the hash table which may be used to search. begin the output step
int pending_raw_len=0;
walk=NewBlock;
uint8 *outbuf=Output;
uint8 const *lastmatchend=OldBlock;
while(walk<NewBlock+NewSize)
{
int longest=0;
BlockPtr *longest_block=0;
if (walk<NewBlock+NewSize-MIN_MATCH_LEN)
{
// check for a match
uint16 hash1=*((uint16 const *) walk)+*((uint16 const *) walk+2);
// now, find the longest match in the hash table. If we find one >MIN_MATCH_LEN, take it
for(BlockPtr *b=HashedMatches[hash1];b;b=b->Next)
{
// find the match length
int match_of=b->dataptr-lastmatchend;
if ((match_of>-32768) && (match_of<32767))
{
int max_mlength=MIN(65535,OldBlock+OldSize-b->dataptr);
max_mlength=MIN(max_mlength,NewBlock+NewSize-walk);
int i;
for(i=0;i<max_mlength;i++)
if (walk[i]!=b->dataptr[i])
break;
if ((i>MIN_MATCH_LEN) && (i>longest))
{
longest=i;
longest_block=b;
}
}
}
}
// now, we have a match maybe
if (longest_block)
{
if (pending_raw_len) // must output
{
ret=1;
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
pending_raw_len=0;
}
// now, output copy block
int match_of=longest_block->dataptr-lastmatchend;
int nremaining=OutSize-(outbuf-Output);
if (match_of)
ret=1;
if (longest>127)
{
// use really long encoding
if (nremaining<5)
Fail("diff buff needs increase");
*(outbuf++)=00;
*(outbuf++)=(longest & 255);
*(outbuf++)=((longest>>8) & 255);
*(outbuf++)=(match_of & 255);
*(outbuf++)=((match_of>>8) & 255);
}
else
{
if ((match_of>=-128) && (match_of<128))
{
if (nremaining<2)
Fail("diff buff needs increase");
*(outbuf++)=128+longest;
*(outbuf++)=(match_of&255);
}
else
{
// use long encoding
if (nremaining<4)
Fail("diff buff needs increase");
*(outbuf++)=0x80;
*(outbuf++)=longest;
*(outbuf++)=(match_of & 255);
*(outbuf++)=((match_of>>8) & 255);
}
}
lastmatchend=longest_block->dataptr+longest;
walk+=longest;
}
else
{
walk++;
pending_raw_len++;
}
}
// now, flush pending raw copy
if (pending_raw_len) // must output
{
ret=1;
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
pending_raw_len=0;
}
if (Blocks)
delete[] Blocks;
DiffListSize=outbuf-Output;
return ret;
}
int FindDiffsLowMemory(uint8 const *NewBlock, uint8 const *OldBlock,
int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize)
{
int ret=0;
if (OldSize!=NewSize)
ret=1;
uint8 const *old_data_hash[256];
memset(old_data_hash,0,sizeof(old_data_hash));
int pending_raw_len=0;
uint8 const *walk=NewBlock;
uint8 const *oldptr=OldBlock;
uint8 *outbuf=Output;
uint8 const *lastmatchend=OldBlock;
while(walk<NewBlock+NewSize)
{
while( (oldptr-OldBlock<walk-NewBlock+40) && (oldptr-OldBlock<OldSize-MIN_MATCH_LEN))
{
uint16 hash1=(oldptr[0]+oldptr[1]+oldptr[2]+oldptr[3]) & (NELEMS(old_data_hash)-1);
old_data_hash[hash1]=oldptr;
oldptr++;
}
int longest=0;
uint8 const *longest_block=0;
if (walk<NewBlock+NewSize-MIN_MATCH_LEN)
{
// check for a match
uint16 hash1=(walk[0]+walk[1]+walk[2]+walk[3]) & (NELEMS(old_data_hash)-1);
if (old_data_hash[hash1])
{
int max_bytes_to_compare=MIN(NewBlock+NewSize-walk,OldBlock+OldSize-old_data_hash[hash1]);
int nmatches;
for(nmatches=0;nmatches<max_bytes_to_compare;nmatches++)
if (walk[nmatches]!=old_data_hash[hash1][nmatches])
break;
if (nmatches>MIN_MATCH_LEN)
{
longest_block=old_data_hash[hash1];
longest=nmatches;
}
}
}
// now, we have a match maybe
if (longest_block)
{
if (pending_raw_len) // must output
{
ret=1;
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
pending_raw_len=0;
}
// now, output copy block
int match_of=longest_block-lastmatchend;
int nremaining=OutSize-(outbuf-Output);
if (match_of)
ret=1;
if (longest>127)
{
// use really long encoding
if (nremaining<5)
Fail("diff buff needs increase");
*(outbuf++)=00;
*(outbuf++)=(longest & 255);
*(outbuf++)=((longest>>8) & 255);
*(outbuf++)=(match_of & 255);
*(outbuf++)=((match_of>>8) & 255);
}
else
{
if ((match_of>=-128) && (match_of<128))
{
if (nremaining<2)
Fail("diff buff needs increase");
*(outbuf++)=128+longest;
*(outbuf++)=(match_of&255);
}
else
{
// use long encoding
if (nremaining<4)
Fail("diff buff needs increase");
*(outbuf++)=0x80;
*(outbuf++)=longest;
*(outbuf++)=(match_of & 255);
*(outbuf++)=((match_of>>8) & 255);
}
}
lastmatchend=longest_block+longest;
walk+=longest;
}
else
{
walk++;
pending_raw_len++;
}
}
// now, flush pending raw copy
if (pending_raw_len) // must output
{
ret=1;
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
pending_raw_len=0;
}
DiffListSize=outbuf-Output;
return ret;
}

303
tier1/generichash.cpp Normal file
View File

@ -0,0 +1,303 @@
//======= Copyright © 2005, , Valve Corporation, All rights reserved. =========
//
// Purpose: Variant Pearson Hash general purpose hashing algorithm described
// by Cargill in C++ Report 1994. Generates a 16-bit result.
//
//=============================================================================
#include <stdlib.h>
#include "tier0/basetypes.h"
#include "tier0/platform.h"
#include "generichash.h"
#include <ctype.h>
//-----------------------------------------------------------------------------
//
// Table of randomly shuffled values from 0-255 generated by:
//
//-----------------------------------------------------------------------------
/*
void MakeRandomValues()
{
int i, j, r;
unsigned t;
srand( 0xdeadbeef );
for ( i = 0; i < 256; i++ )
{
g_nRandomValues[i] = (unsigned )i;
}
for (j = 0; j < 8; j++)
{
for (i = 0; i < 256; i++)
{
r = rand() & 0xff;
t = g_nRandomValues[i];
g_nRandomValues[i] = g_nRandomValues[r];
g_nRandomValues[r] = t;
}
}
printf("static unsigned g_nRandomValues[256] =\n{\n");
for (i = 0; i < 256; i += 16)
{
printf("\t");
for (j = 0; j < 16; j++)
printf(" %3d,", g_nRandomValues[i+j]);
printf("\n");
}
printf("};\n");
}
*/
static unsigned g_nRandomValues[256] =
{
238, 164, 191, 168, 115, 16, 142, 11, 213, 214, 57, 151, 248, 252, 26, 198,
13, 105, 102, 25, 43, 42, 227, 107, 210, 251, 86, 66, 83, 193, 126, 108,
131, 3, 64, 186, 192, 81, 37, 158, 39, 244, 14, 254, 75, 30, 2, 88,
172, 176, 255, 69, 0, 45, 116, 139, 23, 65, 183, 148, 33, 46, 203, 20,
143, 205, 60, 197, 118, 9, 171, 51, 233, 135, 220, 49, 71, 184, 82, 109,
36, 161, 169, 150, 63, 96, 173, 125, 113, 67, 224, 78, 232, 215, 35, 219,
79, 181, 41, 229, 149, 153, 111, 217, 21, 72, 120, 163, 133, 40, 122, 140,
208, 231, 211, 200, 160, 182, 104, 110, 178, 237, 15, 101, 27, 50, 24, 189,
177, 130, 187, 92, 253, 136, 100, 212, 19, 174, 70, 22, 170, 206, 162, 74,
247, 5, 47, 32, 179, 117, 132, 195, 124, 123, 245, 128, 236, 223, 12, 84,
54, 218, 146, 228, 157, 94, 106, 31, 17, 29, 194, 34, 56, 134, 239, 246,
241, 216, 127, 98, 7, 204, 154, 152, 209, 188, 48, 61, 87, 97, 225, 85,
90, 167, 155, 112, 145, 114, 141, 93, 250, 4, 201, 156, 38, 89, 226, 196,
1, 235, 44, 180, 159, 121, 119, 166, 190, 144, 10, 91, 76, 230, 221, 80,
207, 55, 58, 53, 175, 8, 6, 52, 68, 242, 18, 222, 103, 249, 147, 129,
138, 243, 28, 185, 62, 59, 240, 202, 234, 99, 77, 73, 199, 137, 95, 165,
};
//-----------------------------------------------------------------------------
// String
//-----------------------------------------------------------------------------
unsigned FASTCALL HashString( const char *pszKey )
{
const uint8 *k = (const uint8 *)pszKey;
unsigned even = 0,
odd = 0,
n;
while ((n = *k++) != 0)
{
even = g_nRandomValues[odd ^ n];
if ((n = *k++) != 0)
odd = g_nRandomValues[even ^ n];
else
break;
}
return (even << 8) | odd ;
}
//-----------------------------------------------------------------------------
// Case-insensitive string
//-----------------------------------------------------------------------------
unsigned FASTCALL HashStringCaseless( const char *pszKey )
{
const uint8 *k = (const uint8 *) pszKey;
unsigned even = 0,
odd = 0,
n;
while ((n = toupper(*k++)) != 0)
{
even = g_nRandomValues[odd ^ n];
if ((n = toupper(*k++)) != 0)
odd = g_nRandomValues[even ^ n];
else
break;
}
return (even << 8) | odd;
}
//-----------------------------------------------------------------------------
// 32 bit conventional case-insensitive string
//-----------------------------------------------------------------------------
unsigned FASTCALL HashStringCaselessConventional( const char *pszKey )
{
unsigned hash = 0xAAAAAAAA; // Alternating 1's and 0's to maximize the effect of the later multiply and add
for( ; *pszKey ; pszKey++ )
{
hash = ( ( hash << 5 ) + hash ) + (uint8)tolower(*pszKey);
}
return hash;
}
//-----------------------------------------------------------------------------
// int hash
//-----------------------------------------------------------------------------
unsigned FASTCALL HashInt( const int n )
{
register unsigned even, odd;
even = g_nRandomValues[n & 0xff];
odd = g_nRandomValues[((n >> 8) & 0xff)];
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
return (even << 8) | odd;
}
//-----------------------------------------------------------------------------
// 4-byte hash
//-----------------------------------------------------------------------------
unsigned FASTCALL Hash4( const void *pKey )
{
register const uint32 * p = (const uint32 *) pKey;
register unsigned even,
odd,
n;
n = *p;
even = g_nRandomValues[n & 0xff];
odd = g_nRandomValues[((n >> 8) & 0xff)];
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
return (even << 8) | odd;
}
//-----------------------------------------------------------------------------
// 8-byte hash
//-----------------------------------------------------------------------------
unsigned FASTCALL Hash8( const void *pKey )
{
register const uint32 * p = (const uint32 *) pKey;
register unsigned even,
odd,
n;
n = *p;
even = g_nRandomValues[n & 0xff];
odd = g_nRandomValues[((n >> 8) & 0xff)];
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
n = *(p+1);
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
return (even << 8) | odd;
}
//-----------------------------------------------------------------------------
// 12-byte hash
//-----------------------------------------------------------------------------
unsigned FASTCALL Hash12( const void *pKey )
{
register const uint32 * p = (const uint32 *) pKey;
register unsigned even,
odd,
n;
n = *p;
even = g_nRandomValues[n & 0xff];
odd = g_nRandomValues[((n >> 8) & 0xff)];
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
n = *(p+1);
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
n = *(p+2);
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
return (even << 8) | odd;
}
//-----------------------------------------------------------------------------
// 16-byte hash
//-----------------------------------------------------------------------------
unsigned FASTCALL Hash16( const void *pKey )
{
register const uint32 * p = (const uint32 *) pKey;
register unsigned even,
odd,
n;
n = *p;
even = g_nRandomValues[n & 0xff];
odd = g_nRandomValues[((n >> 8) & 0xff)];
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
n = *(p+1);
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
n = *(p+2);
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
n = *(p+3);
even = g_nRandomValues[odd ^ (n >> 24)];
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
odd = g_nRandomValues[even ^ (n & 0xff)];
return (even << 8) | odd;
}
//-----------------------------------------------------------------------------
// Arbitrary fixed length hash
//-----------------------------------------------------------------------------
unsigned FASTCALL HashBlock( const void *pKey, unsigned size )
{
const uint8 * k = (const uint8 *) pKey;
unsigned even = 0,
odd = 0,
n;
while (size)
{
--size;
n = *k++;
even = g_nRandomValues[odd ^ n];
if (size)
{
--size;
n = *k++;
odd = g_nRandomValues[even ^ n];
}
else
break;
}
return (even << 8) | odd;
}

465
tier1/interface.cpp Normal file
View File

@ -0,0 +1,465 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#if defined( _WIN32 ) && !defined( _X360 )
#include <windows.h>
#endif
#if !defined( DONT_PROTECT_FILEIO_FUNCTIONS )
#define DONT_PROTECT_FILEIO_FUNCTIONS // for protected_things.h
#endif
#if defined( PROTECTED_THINGS_ENABLE )
#undef PROTECTED_THINGS_ENABLE // from protected_things.h
#endif
#include <stdio.h>
#include "interface.h"
#include "basetypes.h"
#include "tier0/dbg.h"
#include <string.h>
#include <stdlib.h>
#include "tier1/strtools.h"
#include "tier0/icommandline.h"
#include "tier0/dbg.h"
#include "tier0/threadtools.h"
#ifdef _WIN32
#include <direct.h> // getcwd
#elif defined _LINUX || defined __APPLE__
#define _getcwd getcwd
#endif
#if defined( _X360 )
#include "xbox/xbox_win32stubs.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// ------------------------------------------------------------------------------------ //
// InterfaceReg.
// ------------------------------------------------------------------------------------ //
InterfaceReg *InterfaceReg::s_pInterfaceRegs = NULL;
InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) :
m_pName(pName)
{
m_CreateFn = fn;
m_pNext = s_pInterfaceRegs;
s_pInterfaceRegs = this;
}
// ------------------------------------------------------------------------------------ //
// CreateInterface.
// This is the primary exported function by a dll, referenced by name via dynamic binding
// that exposes an opqaue function pointer to the interface.
// ------------------------------------------------------------------------------------ //
void* CreateInterface( const char *pName, int *pReturnCode )
{
InterfaceReg *pCur;
for (pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext)
{
if (strcmp(pCur->m_pName, pName) == 0)
{
if (pReturnCode)
{
*pReturnCode = IFACE_OK;
}
return pCur->m_CreateFn();
}
}
if (pReturnCode)
{
*pReturnCode = IFACE_FAILED;
}
return NULL;
}
#if defined _LINUX || defined __APPLE__
// Linux doesn't have this function so this emulates its functionality
void *GetModuleHandle(const char *name)
{
void *handle;
if( name == NULL )
{
// hmm, how can this be handled under linux....
// is it even needed?
return NULL;
}
if( (handle=dlopen(name, RTLD_NOW))==NULL)
{
printf("DLOPEN Error:%s\n",dlerror());
// couldn't open this file
return NULL;
}
// read "man dlopen" for details
// in short dlopen() inc a ref count
// so dec the ref count by performing the close
dlclose(handle);
return handle;
}
#endif
#if defined( _WIN32 ) && !defined( _X360 )
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
//-----------------------------------------------------------------------------
// Purpose: returns a pointer to a function, given a module
// Input : pModuleName - module name
// *pName - proc name
//-----------------------------------------------------------------------------
static void *Sys_GetProcAddress( const char *pModuleName, const char *pName )
{
HMODULE hModule = GetModuleHandle( pModuleName );
return GetProcAddress( hModule, pName );
}
static void *Sys_GetProcAddress( HMODULE hModule, const char *pName )
{
return GetProcAddress( hModule, pName );
}
bool Sys_IsDebuggerPresent()
{
return Plat_IsInDebugSession();
}
struct ThreadedLoadLibaryContext_t
{
const char *m_pLibraryName;
HMODULE m_hLibrary;
};
#ifdef _WIN32
// wraps LoadLibraryEx() since 360 doesn't support that
static HMODULE InternalLoadLibrary( const char *pName )
{
#if defined(_X360)
return LoadLibrary( pName );
#else
return LoadLibraryEx( pName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
#endif
}
unsigned ThreadedLoadLibraryFunc( void *pParam )
{
ThreadedLoadLibaryContext_t *pContext = (ThreadedLoadLibaryContext_t*)pParam;
pContext->m_hLibrary = InternalLoadLibrary(pContext->m_pLibraryName);
return 0;
}
#endif
HMODULE Sys_LoadLibrary( const char *pLibraryName )
{
char str[1024];
#if defined( _WIN32 ) && !defined( _X360 )
const char *pModuleExtension = ".dll";
const char *pModuleAddition = pModuleExtension;
#elif defined( _X360 )
const char *pModuleExtension = "_360.dll";
const char *pModuleAddition = pModuleExtension;
#elif defined( _LINUX )
const char *pModuleExtension = ".so";
const char *pModuleAddition = ".so";
#elif defined( __APPLE__ )
const char *pModuleExtension = ".dylib";
const char *pModuleAddition = ".dylib";
#endif
Q_strncpy( str, pLibraryName, sizeof(str) );
if ( !Q_stristr( str, pModuleExtension ) )
{
if ( IsX360() )
{
Q_StripExtension( str, str, sizeof(str) );
}
Q_strncat( str, pModuleAddition, sizeof(str) );
}
Q_FixSlashes( str );
#ifdef _WIN32
ThreadedLoadLibraryFunc_t threadFunc = GetThreadedLoadLibraryFunc();
if ( !threadFunc )
return InternalLoadLibrary( str );
ThreadedLoadLibaryContext_t context;
context.m_pLibraryName = str;
context.m_hLibrary = 0;
ThreadHandle_t h = CreateSimpleThread( ThreadedLoadLibraryFunc, &context );
#ifdef _X360
ThreadSetAffinity( h, XBOX_PROCESSOR_3 );
#endif
unsigned int nTimeout = 0;
while( ThreadWaitForObject( h, true, nTimeout ) == TW_TIMEOUT )
{
nTimeout = threadFunc();
}
ReleaseThreadHandle( h );
return context.m_hLibrary;
#elif defined _LINUX || defined __APPLE__
HMODULE ret = dlopen( str, RTLD_NOW );
if ( ! ret )
{
const char *pError = dlerror();
if ( pError && ( strstr( pError, "No such file" ) == 0 ) )
{
Msg( " failed to dlopen %s error=%s\n", str, pError );
}
}
return ret;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Loads a DLL/component from disk and returns a handle to it
// Input : *pModuleName - filename of the component
// Output : opaque handle to the module (hides system dependency)
//-----------------------------------------------------------------------------
CSysModule *Sys_LoadModule( const char *pModuleName )
{
// If using the Steam filesystem, either the DLL must be a minimum footprint
// file in the depot (MFP) or a filesystem GetLocalCopy() call must be made
// prior to the call to this routine.
char szCwd[1024];
HMODULE hDLL = NULL;
if ( !Q_IsAbsolutePath( pModuleName ) )
{
// full path wasn't passed in, using the current working dir
_getcwd( szCwd, sizeof( szCwd ) );
if ( IsX360() )
{
int i = CommandLine()->FindParm( "-basedir" );
if ( i )
{
strcpy( szCwd, CommandLine()->GetParm( i+1 ) );
}
}
if (szCwd[strlen(szCwd) - 1] == '/' || szCwd[strlen(szCwd) - 1] == '\\' )
{
szCwd[strlen(szCwd) - 1] = 0;
}
char szAbsoluteModuleName[1024];
if ( strstr( pModuleName, "bin/") == pModuleName )
{
// don't make bin/bin path
Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName );
}
else
{
Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/bin/%s", szCwd, pModuleName );
}
hDLL = Sys_LoadLibrary( szAbsoluteModuleName );
}
if ( !hDLL )
{
// full path failed, let LoadLibrary() try to search the PATH now
hDLL = Sys_LoadLibrary( pModuleName );
#if defined( _DEBUG )
if ( !hDLL )
{
// So you can see what the error is in the debugger...
#if defined( _WIN32 ) && !defined( _X360 )
char *lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
LocalFree( (HLOCAL)lpMsgBuf );
#elif defined( _X360 )
Msg( "Failed to load %s:\n", pModuleName );
#else
Error( "Failed to load %s: %s\n", pModuleName, dlerror() );
#endif // _WIN32
}
#endif // DEBUG
}
// If running in the debugger, assume debug binaries are okay, otherwise they must run with -allowdebug
if ( !IsX360() && hDLL &&
!CommandLine()->FindParm( "-allowdebug" ) &&
!Sys_IsDebuggerPresent() )
{
if ( Sys_GetProcAddress( hDLL, "BuiltDebug" ) )
{
Error( "Module %s is a debug build\n", pModuleName );
}
}
return reinterpret_cast<CSysModule *>(hDLL);
}
//-----------------------------------------------------------------------------
// Purpose: Unloads a DLL/component from
// Input : *pModuleName - filename of the component
// Output : opaque handle to the module (hides system dependency)
//-----------------------------------------------------------------------------
void Sys_UnloadModule( CSysModule *pModule )
{
if ( !pModule )
return;
HMODULE hDLL = reinterpret_cast<HMODULE>(pModule);
#ifdef _WIN32
FreeLibrary( hDLL );
#elif defined(_LINUX) || defined(__APPLE__)
dlclose((void *)hDLL);
#endif
}
//-----------------------------------------------------------------------------
// Purpose: returns a pointer to a function, given a module
// Input : module - windows HMODULE from Sys_LoadModule()
// *pName - proc name
// Output : factory for this module
//-----------------------------------------------------------------------------
CreateInterfaceFn Sys_GetFactory( CSysModule *pModule )
{
if ( !pModule )
return NULL;
HMODULE hDLL = reinterpret_cast<HMODULE>(pModule);
#ifdef _WIN32
return reinterpret_cast<CreateInterfaceFn>(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME ));
#elif defined(_LINUX) || defined(__APPLE__)
// Linux gives this error:
//../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory
//(CSysModule *)) (const char *, int *)':
//../public/interface.cpp:154: ISO C++ forbids casting between
//pointer-to-function and pointer-to-object
//
// so lets get around it :)
return (CreateInterfaceFn)(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME ));
#endif
}
//-----------------------------------------------------------------------------
// Purpose: returns the instance of this module
// Output : interface_instance_t
//-----------------------------------------------------------------------------
CreateInterfaceFn Sys_GetFactoryThis( void )
{
return CreateInterface;
}
//-----------------------------------------------------------------------------
// Purpose: returns the instance of the named module
// Input : *pModuleName - name of the module
// Output : interface_instance_t - instance of that module
//-----------------------------------------------------------------------------
CreateInterfaceFn Sys_GetFactory( const char *pModuleName )
{
#ifdef _WIN32
return static_cast<CreateInterfaceFn>( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) );
#elif defined(_LINUX) || defined(__APPLE__)
// see Sys_GetFactory( CSysModule *pModule ) for an explanation
return (CreateInterfaceFn)( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) );
#endif
}
//-----------------------------------------------------------------------------
// Purpose: get the interface for the specified module and version
// Input :
// Output :
//-----------------------------------------------------------------------------
bool Sys_LoadInterface(
const char *pModuleName,
const char *pInterfaceVersionName,
CSysModule **pOutModule,
void **pOutInterface )
{
CSysModule *pMod = Sys_LoadModule( pModuleName );
if ( !pMod )
return false;
CreateInterfaceFn fn = Sys_GetFactory( pMod );
if ( !fn )
{
Sys_UnloadModule( pMod );
return false;
}
*pOutInterface = fn( pInterfaceVersionName, NULL );
if ( !( *pOutInterface ) )
{
Sys_UnloadModule( pMod );
return false;
}
if ( pOutModule )
*pOutModule = pMod;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Place this as a singleton at module scope (e.g.) and use it to get the factory from the specified module name.
//
// When the singleton goes out of scope (.dll unload if at module scope),
// then it'll call Sys_UnloadModule on the module so that the refcount is decremented
// and the .dll actually can unload from memory.
//-----------------------------------------------------------------------------
CDllDemandLoader::CDllDemandLoader( char const *pchModuleName ) :
m_pchModuleName( pchModuleName ),
m_hModule( 0 ),
m_bLoadAttempted( false )
{
}
CDllDemandLoader::~CDllDemandLoader()
{
Unload();
}
CreateInterfaceFn CDllDemandLoader::GetFactory()
{
if ( !m_hModule && !m_bLoadAttempted )
{
m_bLoadAttempted = true;
m_hModule = Sys_LoadModule( m_pchModuleName );
}
if ( !m_hModule )
{
return NULL;
}
return Sys_GetFactory( m_hModule );
}
void CDllDemandLoader::Unload()
{
if ( m_hModule )
{
Sys_UnloadModule( m_hModule );
m_hModule = 0;
}
}

316
tier1/mempool.cpp Normal file
View File

@ -0,0 +1,316 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "mempool.h"
#include <stdio.h>
#ifdef __APPLE__
#include <sys/malloc.h>
#else
#include <malloc.h>
#endif
#include <memory.h>
#include "tier0/dbg.h"
#include <ctype.h>
#include "tier1/strtools.h"
// Should be last include
#include "tier0/memdbgon.h"
MemoryPoolReportFunc_t CMemoryPool::g_ReportFunc = 0;
//-----------------------------------------------------------------------------
// Error reporting... (debug only)
//-----------------------------------------------------------------------------
void CMemoryPool::SetErrorReportFunc( MemoryPoolReportFunc_t func )
{
g_ReportFunc = func;
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CMemoryPool::CMemoryPool( int blockSize, int numElements, int growMode, const char *pszAllocOwner, int nAlignment )
{
#ifdef _X360
if( numElements > 0 && growMode != GROW_NONE )
{
numElements = 1;
}
#endif
m_nAlignment = ( nAlignment != 0 ) ? nAlignment : 1;
Assert( IsPowerOfTwo( m_nAlignment ) );
m_BlockSize = blockSize < (int)sizeof(void*) ? sizeof(void*) : blockSize;
m_BlockSize = AlignValue( m_BlockSize, m_nAlignment );
m_BlocksPerBlob = numElements;
m_PeakAlloc = 0;
m_GrowMode = growMode;
if ( !pszAllocOwner )
{
pszAllocOwner = __FILE__;
}
m_pszAllocOwner = pszAllocOwner;
Init();
AddNewBlob();
}
//-----------------------------------------------------------------------------
// Purpose: Frees the memory contained in the mempool, and invalidates it for
// any further use.
// Input : *memPool - the mempool to shutdown
//-----------------------------------------------------------------------------
CMemoryPool::~CMemoryPool()
{
if (m_BlocksAllocated > 0)
{
ReportLeaks();
}
Clear();
}
//-----------------------------------------------------------------------------
// Resets the pool
//-----------------------------------------------------------------------------
void CMemoryPool::Init()
{
m_NumBlobs = 0;
m_BlocksAllocated = 0;
m_pHeadOfFreeList = 0;
m_BlobHead.m_pNext = m_BlobHead.m_pPrev = &m_BlobHead;
}
//-----------------------------------------------------------------------------
// Frees everything
//-----------------------------------------------------------------------------
void CMemoryPool::Clear()
{
// Free everything..
CBlob *pNext;
for( CBlob *pCur = m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur = pNext )
{
pNext = pCur->m_pNext;
free( pCur );
}
Init();
}
//-----------------------------------------------------------------------------
// Purpose: Reports memory leaks
//-----------------------------------------------------------------------------
void CMemoryPool::ReportLeaks()
{
if (!g_ReportFunc)
return;
g_ReportFunc("Memory leak: mempool blocks left in memory: %d\n", m_BlocksAllocated);
#ifdef _DEBUG
// walk and destroy the free list so it doesn't intefere in the scan
while (m_pHeadOfFreeList != NULL)
{
void *next = *((void**)m_pHeadOfFreeList);
memset(m_pHeadOfFreeList, 0, m_BlockSize);
m_pHeadOfFreeList = next;
}
g_ReportFunc("Dumping memory: \'");
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
{
// scan the memory block and dump the leaks
char *scanPoint = (char *)pCur->m_Data;
char *scanEnd = pCur->m_Data + pCur->m_NumBytes;
bool needSpace = false;
while (scanPoint < scanEnd)
{
// search for and dump any strings
if ((unsigned)(*scanPoint + 1) <= 256 && isprint(*scanPoint))
{
g_ReportFunc("%c", *scanPoint);
needSpace = true;
}
else if (needSpace)
{
needSpace = false;
g_ReportFunc(" ");
}
scanPoint++;
}
}
g_ReportFunc("\'\n");
#endif // _DEBUG
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMemoryPool::AddNewBlob()
{
MEM_ALLOC_CREDIT_(m_pszAllocOwner);
int sizeMultiplier;
if( m_GrowMode == GROW_SLOW )
{
sizeMultiplier = 1;
}
else
{
if ( m_GrowMode == GROW_NONE )
{
// Can only have one allocation when we're in this mode
if( m_NumBlobs != 0 )
{
Assert( !"CMemoryPool::AddNewBlob: mode == GROW_NONE" );
return;
}
}
// GROW_FAST and GROW_NONE use this.
sizeMultiplier = m_NumBlobs + 1;
}
// maybe use something other than malloc?
int nElements = m_BlocksPerBlob * sizeMultiplier;
int blobSize = m_BlockSize * nElements;
CBlob *pBlob = (CBlob*)malloc( sizeof(CBlob) - 1 + blobSize + ( m_nAlignment - 1 ) );
Assert( pBlob );
// Link it in at the end of the blob list.
pBlob->m_NumBytes = blobSize;
pBlob->m_pNext = &m_BlobHead;
pBlob->m_pPrev = pBlob->m_pNext->m_pPrev;
pBlob->m_pNext->m_pPrev = pBlob->m_pPrev->m_pNext = pBlob;
// setup the free list
m_pHeadOfFreeList = AlignValue( pBlob->m_Data, m_nAlignment );
Assert (m_pHeadOfFreeList);
void **newBlob = (void**)m_pHeadOfFreeList;
for (int j = 0; j < nElements-1; j++)
{
newBlob[0] = (char*)newBlob + m_BlockSize;
newBlob = (void**)newBlob[0];
}
// null terminate list
newBlob[0] = NULL;
m_NumBlobs++;
}
void* CMemoryPool::Alloc()
{
return Alloc( m_BlockSize );
}
void* CMemoryPool::AllocZero()
{
return AllocZero( m_BlockSize );
}
//-----------------------------------------------------------------------------
// Purpose: Allocs a single block of memory from the pool.
// Input : amount -
//-----------------------------------------------------------------------------
void *CMemoryPool::Alloc( size_t amount )
{
void *returnBlock;
if ( amount > (unsigned int)m_BlockSize )
return NULL;
if( !m_pHeadOfFreeList )
{
// returning NULL is fine in GROW_NONE
if( m_GrowMode == GROW_NONE )
{
//Assert( !"CMemoryPool::Alloc: tried to make new blob with GROW_NONE" );
return NULL;
}
// overflow
AddNewBlob();
// still failure, error out
if( !m_pHeadOfFreeList )
{
Assert( !"CMemoryPool::Alloc: ran out of memory" );
return NULL;
}
}
m_BlocksAllocated++;
m_PeakAlloc = MAX(m_PeakAlloc, m_BlocksAllocated);
returnBlock = m_pHeadOfFreeList;
// move the pointer the next block
m_pHeadOfFreeList = *((void**)m_pHeadOfFreeList);
return returnBlock;
}
//-----------------------------------------------------------------------------
// Purpose: Allocs a single block of memory from the pool, zeroes the memory before returning
// Input : amount -
//-----------------------------------------------------------------------------
void *CMemoryPool::AllocZero( size_t amount )
{
void *mem = Alloc( amount );
if ( mem )
{
V_memset( mem, 0x00, amount );
}
return mem;
}
//-----------------------------------------------------------------------------
// Purpose: Frees a block of memory
// Input : *memBlock - the memory to free
//-----------------------------------------------------------------------------
void CMemoryPool::Free( void *memBlock )
{
if ( !memBlock )
return; // trying to delete NULL pointer, ignore
#ifdef _DEBUG
// check to see if the memory is from the allocated range
bool bOK = false;
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
{
if (memBlock >= pCur->m_Data && (char*)memBlock < (pCur->m_Data + pCur->m_NumBytes))
{
bOK = true;
}
}
Assert (bOK);
#endif // _DEBUG
#ifdef _DEBUG
// invalidate the memory
memset( memBlock, 0xDD, m_BlockSize );
#endif
m_BlocksAllocated--;
// make the block point to the first item in the list
*((void**)memBlock) = m_pHeadOfFreeList;
// the list head is now the new block
m_pHeadOfFreeList = memBlock;
}

300
tier1/memstack.cpp Normal file
View File

@ -0,0 +1,300 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#if defined( _WIN32 ) && !defined( _X360 )
#define WIN_32_LEAN_AND_MEAN
#include <windows.h>
#define VA_COMMIT_FLAGS MEM_COMMIT
#define VA_RESERVE_FLAGS MEM_RESERVE
#elif defined( _X360 )
#define VA_COMMIT_FLAGS (MEM_COMMIT|MEM_NOZERO|MEM_LARGE_PAGES)
#define VA_RESERVE_FLAGS (MEM_RESERVE|MEM_LARGE_PAGES)
#endif
#include "tier0/dbg.h"
#include "memstack.h"
#include "utlmap.h"
#include "tier0/memdbgon.h"
#ifdef _WIN32
#pragma warning(disable:4073)
#pragma init_seg(lib)
#endif
//-----------------------------------------------------------------------------
MEMALLOC_DEFINE_EXTERNAL_TRACKING(CMemoryStack);
//-----------------------------------------------------------------------------
CMemoryStack::CMemoryStack()
: m_pNextAlloc( NULL ),
m_pCommitLimit( NULL ),
m_pAllocLimit( NULL ),
m_pBase( NULL ),
m_maxSize( 0 ),
#if defined (_LINUX) || defined (__APPLE__)
m_alignment( 16 )
#elif defined(_WIN32)
m_alignment( 16 ),
m_commitSize( 0 ),
m_minCommit( 0 )
#endif
{
}
//-------------------------------------
CMemoryStack::~CMemoryStack()
{
if ( m_pBase )
Term();
}
//-------------------------------------
bool CMemoryStack::Init( unsigned maxSize, unsigned commitSize, unsigned initialCommit, unsigned alignment )
{
Assert( !m_pBase );
#ifdef _X360
m_bPhysical = false;
#endif
m_maxSize = maxSize;
m_alignment = AlignValue( alignment, 4 );
Assert( m_alignment == alignment );
Assert( m_maxSize > 0 );
#if defined(_WIN32)
if ( commitSize != 0 )
{
m_commitSize = commitSize;
}
unsigned pageSize;
#ifndef _X360
SYSTEM_INFO sysInfo;
GetSystemInfo( &sysInfo );
Assert( !( sysInfo.dwPageSize & (sysInfo.dwPageSize-1)) );
pageSize = sysInfo.dwPageSize;
#else
pageSize = 64*1024;
#endif
if ( m_commitSize == 0 )
{
m_commitSize = pageSize;
}
else
{
m_commitSize = AlignValue( m_commitSize, pageSize );
}
m_maxSize = AlignValue( m_maxSize, m_commitSize );
Assert( m_maxSize % pageSize == 0 && m_commitSize % pageSize == 0 && m_commitSize <= m_maxSize );
m_pBase = (unsigned char *)VirtualAlloc( NULL, m_maxSize, VA_RESERVE_FLAGS, PAGE_NOACCESS );
Assert( m_pBase );
m_pCommitLimit = m_pNextAlloc = m_pBase;
if ( initialCommit )
{
initialCommit = AlignValue( initialCommit, m_commitSize );
Assert( initialCommit < m_maxSize );
if ( !VirtualAlloc( m_pCommitLimit, initialCommit, VA_COMMIT_FLAGS, PAGE_READWRITE ) )
return false;
m_minCommit = initialCommit;
m_pCommitLimit += initialCommit;
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
}
#else
m_pBase = (byte *)MemAlloc_AllocAligned( m_maxSize, alignment ? alignment : 1 );
m_pNextAlloc = m_pBase;
m_pCommitLimit = m_pBase + m_maxSize;
#endif
m_pAllocLimit = m_pBase + m_maxSize;
return ( m_pBase != NULL );
}
//-------------------------------------
#ifdef _X360
bool CMemoryStack::InitPhysical( unsigned size, unsigned alignment )
{
m_bPhysical = true;
m_maxSize = m_commitSize = size;
m_alignment = AlignValue( alignment, 4 );
int flags = PAGE_READWRITE;
if ( size >= 16*1024*1024 )
{
flags |= MEM_16MB_PAGES;
}
else
{
flags |= MEM_LARGE_PAGES;
}
m_pBase = (unsigned char *)XPhysicalAlloc( m_maxSize, MAXULONG_PTR, 4096, flags );
Assert( m_pBase );
m_pNextAlloc = m_pBase;
m_pCommitLimit = m_pBase + m_maxSize;
m_pAllocLimit = m_pBase + m_maxSize;
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
return ( m_pBase != NULL );
}
#endif
//-------------------------------------
void CMemoryStack::Term()
{
FreeAll();
if ( m_pBase )
{
#if defined(_WIN32)
VirtualFree( m_pBase, 0, MEM_RELEASE );
#else
MemAlloc_FreeAligned( m_pBase );
#endif
m_pBase = NULL;
}
}
//-------------------------------------
int CMemoryStack::GetSize()
{
#ifdef _WIN32
return m_pCommitLimit - m_pBase;
#else
return m_maxSize;
#endif
}
//-------------------------------------
bool CMemoryStack::CommitTo( byte *pNextAlloc ) RESTRICT
{
#ifdef _X360
if ( m_bPhysical )
{
return NULL;
}
#endif
#if defined(_WIN32)
unsigned char * pNewCommitLimit = AlignValue( pNextAlloc, m_commitSize );
unsigned commitSize = pNewCommitLimit - m_pCommitLimit;
if ( GetSize() )
MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() );
if( m_pCommitLimit + commitSize > m_pAllocLimit )
{
return false;
}
if ( !VirtualAlloc( m_pCommitLimit, commitSize, VA_COMMIT_FLAGS, PAGE_READWRITE ) )
{
Assert( 0 );
return false;
}
m_pCommitLimit = pNewCommitLimit;
if ( GetSize() )
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
return true;
#else
Assert( 0 );
return false;
#endif
}
//-------------------------------------
void CMemoryStack::FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit )
{
void *pAllocPoint = m_pBase + mark;
Assert( pAllocPoint >= m_pBase && pAllocPoint <= m_pNextAlloc );
if ( pAllocPoint >= m_pBase && pAllocPoint < m_pNextAlloc )
{
if ( bDecommit )
{
#if defined(_WIN32)
unsigned char *pDecommitPoint = AlignValue( (unsigned char *)pAllocPoint, m_commitSize );
if ( pDecommitPoint < m_pBase + m_minCommit )
{
pDecommitPoint = m_pBase + m_minCommit;
}
unsigned decommitSize = m_pCommitLimit - pDecommitPoint;
if ( decommitSize > 0 )
{
MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() );
VirtualFree( pDecommitPoint, decommitSize, MEM_DECOMMIT );
m_pCommitLimit = pDecommitPoint;
if ( mark > 0 )
{
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
}
}
#endif
}
m_pNextAlloc = (unsigned char *)pAllocPoint;
}
}
//-------------------------------------
void CMemoryStack::FreeAll( bool bDecommit )
{
if ( m_pBase && m_pCommitLimit - m_pBase > 0 )
{
if ( bDecommit )
{
#if defined(_WIN32)
MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() );
VirtualFree( m_pBase, m_pCommitLimit - m_pBase, MEM_DECOMMIT );
m_pCommitLimit = m_pBase;
#endif
}
m_pNextAlloc = m_pBase;
}
}
//-------------------------------------
void CMemoryStack::Access( void **ppRegion, unsigned *pBytes )
{
*ppRegion = m_pBase;
*pBytes = ( m_pNextAlloc - m_pBase);
}
//-------------------------------------
void CMemoryStack::PrintContents()
{
Msg( "Total used memory: %d\n", GetUsed() );
Msg( "Total committed memory: %d\n", GetSize() );
}
//-----------------------------------------------------------------------------

713
tier1/newbitbuf.cpp Normal file
View File

@ -0,0 +1,713 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "bitbuf.h"
#include "coordsize.h"
#include "mathlib/vector.h"
#include "mathlib/mathlib.h"
#include "tier1/strtools.h"
#include "bitvec.h"
// FIXME: Can't use this until we get multithreaded allocations in tier0 working for tools
// This is used by VVIS and fails to link
// NOTE: This must be the last file included!!!
//#include "tier0/memdbgon.h"
#ifdef _X360
// mandatory ... wary of above comment and isolating, tier0 is built as MT though
#include "tier0/memdbgon.h"
#endif
#include "stdio.h"
void CBitWrite::StartWriting( void *pData, int nBytes, int iStartBit, int nBits )
{
// Make sure it's dword aligned and padded.
Assert( (nBytes % 4) == 0 );
Assert(((unsigned long)pData & 3) == 0);
Assert( iStartBit == 0 );
m_pData = (uint32 *) pData;
m_pDataOut = m_pData;
m_nDataBytes = nBytes;
if ( nBits == -1 )
{
m_nDataBits = nBytes << 3;
}
else
{
Assert( nBits <= nBytes*8 );
m_nDataBits = nBits;
}
m_bOverflow = false;
m_nOutBufWord = 0;
m_nOutBitsAvail = 32;
m_pBufferEnd = m_pDataOut + ( nBytes >> 2 );
}
const uint32 CBitBuffer::s_nMaskTable[33] = {
0,
( 1 << 1 ) - 1,
( 1 << 2 ) - 1,
( 1 << 3 ) - 1,
( 1 << 4 ) - 1,
( 1 << 5 ) - 1,
( 1 << 6 ) - 1,
( 1 << 7 ) - 1,
( 1 << 8 ) - 1,
( 1 << 9 ) - 1,
( 1 << 10 ) - 1,
( 1 << 11 ) - 1,
( 1 << 12 ) - 1,
( 1 << 13 ) - 1,
( 1 << 14 ) - 1,
( 1 << 15 ) - 1,
( 1 << 16 ) - 1,
( 1 << 17 ) - 1,
( 1 << 18 ) - 1,
( 1 << 19 ) - 1,
( 1 << 20 ) - 1,
( 1 << 21 ) - 1,
( 1 << 22 ) - 1,
( 1 << 23 ) - 1,
( 1 << 24 ) - 1,
( 1 << 25 ) - 1,
( 1 << 26 ) - 1,
( 1 << 27 ) - 1,
( 1 << 28 ) - 1,
( 1 << 29 ) - 1,
( 1 << 30 ) - 1,
0x7fffffff,
0xffffffff,
};
bool CBitWrite::WriteString( const char *pStr )
{
if(pStr)
{
while( *pStr )
{
WriteChar( * ( pStr++ ) );
}
}
WriteChar( 0 );
return !IsOverflowed();
}
void CBitWrite::WriteLongLong(int64 val)
{
uint *pLongs = (uint*)&val;
// Insert the two DWORDS according to network endian
const short endianIndex = 0x0100;
byte *idx = (byte*)&endianIndex;
WriteUBitLong(pLongs[*idx++], sizeof(long) << 3);
WriteUBitLong(pLongs[*idx], sizeof(long) << 3);
}
bool CBitWrite::WriteBits(const void *pInData, int nBits)
{
unsigned char *pOut = (unsigned char*)pInData;
int nBitsLeft = nBits;
// Bounds checking..
if ( ( GetNumBitsWritten() + nBits) > m_nDataBits )
{
SetOverflowFlag();
CallErrorHandler( BITBUFERROR_BUFFER_OVERRUN, m_pDebugName );
return false;
}
// !! speed!! need fast paths
// write remaining bytes
while ( nBitsLeft >= 8 )
{
WriteUBitLong( *pOut, 8, false );
++pOut;
nBitsLeft -= 8;
}
// write remaining bits
if ( nBitsLeft )
{
WriteUBitLong( *pOut, nBitsLeft, false );
}
return !IsOverflowed();
}
void CBitWrite::WriteBytes( const void *pBuf, int nBytes )
{
WriteBits(pBuf, nBytes << 3);
}
void CBitWrite::WriteBitCoord (const float f)
{
int signbit = (f <= -COORD_RESOLUTION);
int intval = (int)fabs(f);
int fractval = abs((int)(f*COORD_DENOMINATOR)) & (COORD_DENOMINATOR-1);
// Send the bit flags that indicate whether we have an integer part and/or a fraction part.
WriteOneBit( intval );
WriteOneBit( fractval );
if ( intval || fractval )
{
// Send the sign bit
WriteOneBit( signbit );
// Send the integer if we have one.
if ( intval )
{
// Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1]
intval--;
WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS );
}
// Send the fraction if we have one
if ( fractval )
{
WriteUBitLong( (unsigned int)fractval, COORD_FRACTIONAL_BITS );
}
}
}
void CBitWrite::WriteBitCoordMP (const float f, bool bIntegral, bool bLowPrecision )
{
int signbit = (f <= -( bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION ));
int intval = (int)fabs(f);
int fractval = bLowPrecision ?
( abs((int)(f*COORD_DENOMINATOR_LOWPRECISION)) & (COORD_DENOMINATOR_LOWPRECISION-1) ) :
( abs((int)(f*COORD_DENOMINATOR)) & (COORD_DENOMINATOR-1) );
bool bInBounds = intval < (1 << COORD_INTEGER_BITS_MP );
WriteOneBit( bInBounds );
if ( bIntegral )
{
// Send the sign bit
WriteOneBit( intval );
if ( intval )
{
WriteOneBit( signbit );
// Send the integer if we have one.
// Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1]
intval--;
if ( bInBounds )
{
WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS_MP );
}
else
{
WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS );
}
}
}
else
{
// Send the bit flags that indicate whether we have an integer part and/or a fraction part.
WriteOneBit( intval );
// Send the sign bit
WriteOneBit( signbit );
// Send the integer if we have one.
if ( intval )
{
// Adjust the integers from [1..MAX_COORD_VALUE] to [0..MAX_COORD_VALUE-1]
intval--;
if ( bInBounds )
{
WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS_MP );
}
else
{
WriteUBitLong( (unsigned int)intval, COORD_INTEGER_BITS );
}
}
WriteUBitLong( (unsigned int)fractval, bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS );
}
}
void CBitWrite::SeekToBit( int nBit )
{
TempFlush();
m_pDataOut = m_pData + ( nBit / 32 );
m_nOutBufWord = *( m_pDataOut );
m_nOutBitsAvail = 32 - ( nBit & 31 );
}
void CBitWrite::WriteBitVec3Coord( const Vector& fa )
{
int xflag, yflag, zflag;
xflag = (fa[0] >= COORD_RESOLUTION) || (fa[0] <= -COORD_RESOLUTION);
yflag = (fa[1] >= COORD_RESOLUTION) || (fa[1] <= -COORD_RESOLUTION);
zflag = (fa[2] >= COORD_RESOLUTION) || (fa[2] <= -COORD_RESOLUTION);
WriteOneBit( xflag );
WriteOneBit( yflag );
WriteOneBit( zflag );
if ( xflag )
WriteBitCoord( fa[0] );
if ( yflag )
WriteBitCoord( fa[1] );
if ( zflag )
WriteBitCoord( fa[2] );
}
void CBitWrite::WriteBitNormal( float f )
{
int signbit = (f <= -NORMAL_RESOLUTION);
// NOTE: Since +/-1 are valid values for a normal, I'm going to encode that as all ones
unsigned int fractval = abs( (int)(f*NORMAL_DENOMINATOR) );
// clamp..
if (fractval > NORMAL_DENOMINATOR)
fractval = NORMAL_DENOMINATOR;
// Send the sign bit
WriteOneBit( signbit );
// Send the fractional component
WriteUBitLong( fractval, NORMAL_FRACTIONAL_BITS );
}
void CBitWrite::WriteBitVec3Normal( const Vector& fa )
{
int xflag, yflag;
xflag = (fa[0] >= NORMAL_RESOLUTION) || (fa[0] <= -NORMAL_RESOLUTION);
yflag = (fa[1] >= NORMAL_RESOLUTION) || (fa[1] <= -NORMAL_RESOLUTION);
WriteOneBit( xflag );
WriteOneBit( yflag );
if ( xflag )
WriteBitNormal( fa[0] );
if ( yflag )
WriteBitNormal( fa[1] );
// Write z sign bit
int signbit = (fa[2] <= -NORMAL_RESOLUTION);
WriteOneBit( signbit );
}
void CBitWrite::WriteBitAngle( float fAngle, int numbits )
{
unsigned int shift = GetBitForBitnum(numbits);
unsigned int mask = shift - 1;
int d = (int)( (fAngle / 360.0) * shift );
d &= mask;
WriteUBitLong((unsigned int)d, numbits);
}
bool CBitWrite::WriteBitsFromBuffer( bf_read *pIn, int nBits )
{
// This could be optimized a little by
while ( nBits > 32 )
{
WriteUBitLong( pIn->ReadUBitLong( 32 ), 32 );
nBits -= 32;
}
WriteUBitLong( pIn->ReadUBitLong( nBits ), nBits );
return !IsOverflowed() && !pIn->IsOverflowed();
}
void CBitWrite::WriteBitAngles( const QAngle& fa )
{
// FIXME:
Vector tmp( fa.x, fa.y, fa.z );
WriteBitVec3Coord( tmp );
}
bool CBitRead::Seek( int nPosition )
{
bool bSucc = true;
if ( nPosition < 0 || nPosition > m_nDataBits)
{
SetOverflowFlag();
bSucc = false;
nPosition = m_nDataBits;
}
int nHead = m_nDataBytes & 3; // non-multiple-of-4 bytes at head of buffer. We put the "round off"
// at the head to make reading and detecting the end efficient.
int nByteOfs = nPosition / 8;
if ( ( m_nDataBytes < 4 ) || ( nHead && ( nByteOfs < nHead ) ) )
{
// partial first dword
uint8 const *pPartial = ( uint8 const *) m_pData;
if ( m_pData )
{
m_nInBufWord = *( pPartial++ );
if ( nHead > 1 )
m_nInBufWord |= ( *pPartial++ ) << 8;
if ( nHead > 2 )
m_nInBufWord |= ( *pPartial++ ) << 16;
}
m_pDataIn = ( uint32 const * ) pPartial;
m_nInBufWord >>= ( nPosition & 31 );
m_nBitsAvail = ( nHead << 3 ) - ( nPosition & 31 );
}
else
{
int nAdjPosition = nPosition - ( nHead << 3 );
m_pDataIn = reinterpret_cast<uint32 const *> (
reinterpret_cast<uint8 const *>( m_pData ) + ( ( nAdjPosition / 32 ) << 2 ) + nHead );
if ( m_pData )
{
m_nBitsAvail = 32;
GrabNextDWord();
}
else
{
m_nInBufWord = 0;
m_nBitsAvail = 1;
}
m_nInBufWord >>= ( nAdjPosition & 31 );
m_nBitsAvail = MIN( m_nBitsAvail, 32 - ( nAdjPosition & 31 ) ); // in case grabnextdword overflowed
}
return bSucc;
}
void CBitRead::StartReading( const void *pData, int nBytes, int iStartBit, int nBits )
{
// Make sure it's dword aligned and padded.
Assert(((unsigned long)pData & 3) == 0);
m_pData = (uint32 *) pData;
m_pDataIn = m_pData;
m_nDataBytes = nBytes;
if ( nBits == -1 )
{
m_nDataBits = nBytes << 3;
}
else
{
Assert( nBits <= nBytes*8 );
m_nDataBits = nBits;
}
m_bOverflow = false;
m_pBufferEnd = reinterpret_cast<uint32 const *> ( reinterpret_cast< uint8 const *> (m_pData) + nBytes );
if ( m_pData )
Seek( iStartBit );
}
bool CBitRead::ReadString( char *pStr, int maxLen, bool bLine, int *pOutNumChars )
{
Assert( maxLen != 0 );
bool bTooSmall = false;
int iChar = 0;
while(1)
{
char val = ReadChar();
if ( val == 0 )
break;
else if ( bLine && val == '\n' )
break;
if ( iChar < (maxLen-1) )
{
pStr[iChar] = val;
++iChar;
}
else
{
bTooSmall = true;
}
}
// Make sure it's null-terminated.
Assert( iChar < maxLen );
pStr[iChar] = 0;
if ( pOutNumChars )
*pOutNumChars = iChar;
return !IsOverflowed() && !bTooSmall;
}
char* CBitRead::ReadAndAllocateString( bool *pOverflow )
{
char str[2048];
int nChars;
bool bOverflow = !ReadString( str, sizeof( str ), false, &nChars );
if ( pOverflow )
*pOverflow = bOverflow;
// Now copy into the output and return it;
char *pRet = new char[ nChars + 1 ];
for ( int i=0; i <= nChars; i++ )
pRet[i] = str[i];
return pRet;
}
int64 CBitRead::ReadLongLong( void )
{
int64 retval;
uint *pLongs = (uint*)&retval;
// Read the two DWORDs according to network endian
const short endianIndex = 0x0100;
byte *idx = (byte*)&endianIndex;
pLongs[*idx++] = ReadUBitLong(sizeof(long) << 3);
pLongs[*idx] = ReadUBitLong(sizeof(long) << 3);
return retval;
}
void CBitRead::ReadBits(void *pOutData, int nBits)
{
unsigned char *pOut = (unsigned char*)pOutData;
int nBitsLeft = nBits;
// align output to dword boundary
while( ((unsigned long)pOut & 3) != 0 && nBitsLeft >= 8 )
{
*pOut = (unsigned char)ReadUBitLong(8);
++pOut;
nBitsLeft -= 8;
}
// X360TBD: Can't read dwords in ReadBits because they'll get swapped
if ( IsPC() )
{
// read dwords
while ( nBitsLeft >= 32 )
{
*((unsigned long*)pOut) = ReadUBitLong(32);
pOut += sizeof(unsigned long);
nBitsLeft -= 32;
}
}
// read remaining bytes
while ( nBitsLeft >= 8 )
{
*pOut = ReadUBitLong(8);
++pOut;
nBitsLeft -= 8;
}
// read remaining bits
if ( nBitsLeft )
{
*pOut = ReadUBitLong(nBitsLeft);
}
}
bool CBitRead::ReadBytes(void *pOut, int nBytes)
{
ReadBits(pOut, nBytes << 3);
return !IsOverflowed();
}
float CBitRead::ReadBitAngle( int numbits )
{
float shift = (float)( GetBitForBitnum(numbits) );
int i = ReadUBitLong( numbits );
float fReturn = (float)i * (360.0 / shift);
return fReturn;
}
// Basic Coordinate Routines (these contain bit-field size AND fixed point scaling constants)
float CBitRead::ReadBitCoord (void)
{
int intval=0,fractval=0,signbit=0;
float value = 0.0;
// Read the required integer and fraction flags
intval = ReadOneBit();
fractval = ReadOneBit();
// If we got either parse them, otherwise it's a zero.
if ( intval || fractval )
{
// Read the sign bit
signbit = ReadOneBit();
// If there's an integer, read it in
if ( intval )
{
// Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1;
}
// If there's a fraction, read it in
if ( fractval )
{
fractval = ReadUBitLong( COORD_FRACTIONAL_BITS );
}
// Calculate the correct floating point value
value = intval + ((float)fractval * COORD_RESOLUTION);
// Fixup the sign if negative.
if ( signbit )
value = -value;
}
return value;
}
float CBitRead::ReadBitCoordMP( bool bIntegral, bool bLowPrecision )
{
int intval=0,fractval=0,signbit=0;
float value = 0.0;
bool bInBounds = ReadOneBit() ? true : false;
if ( bIntegral )
{
// Read the required integer and fraction flags
intval = ReadOneBit();
// If we got either parse them, otherwise it's a zero.
if ( intval )
{
// Read the sign bit
signbit = ReadOneBit();
// If there's an integer, read it in
// Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
if ( bInBounds )
{
value = ReadUBitLong( COORD_INTEGER_BITS_MP ) + 1;
}
else
{
value = ReadUBitLong( COORD_INTEGER_BITS ) + 1;
}
}
}
else
{
// Read the required integer and fraction flags
intval = ReadOneBit();
// Read the sign bit
signbit = ReadOneBit();
// If we got either parse them, otherwise it's a zero.
if ( intval )
{
if ( bInBounds )
{
intval = ReadUBitLong( COORD_INTEGER_BITS_MP ) + 1;
}
else
{
intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1;
}
}
// If there's a fraction, read it in
fractval = ReadUBitLong( bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS );
// Calculate the correct floating point value
value = intval + ((float)fractval * ( bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION ) );
}
// Fixup the sign if negative.
if ( signbit )
value = -value;
return value;
}
void CBitRead::ReadBitVec3Coord( Vector& fa )
{
int xflag, yflag, zflag;
// This vector must be initialized! Otherwise, If any of the flags aren't set,
// the corresponding component will not be read and will be stack garbage.
fa.Init( 0, 0, 0 );
xflag = ReadOneBit();
yflag = ReadOneBit();
zflag = ReadOneBit();
if ( xflag )
fa[0] = ReadBitCoord();
if ( yflag )
fa[1] = ReadBitCoord();
if ( zflag )
fa[2] = ReadBitCoord();
}
float CBitRead::ReadBitNormal (void)
{
// Read the sign bit
int signbit = ReadOneBit();
// Read the fractional part
unsigned int fractval = ReadUBitLong( NORMAL_FRACTIONAL_BITS );
// Calculate the correct floating point value
float value = (float)fractval * NORMAL_RESOLUTION;
// Fixup the sign if negative.
if ( signbit )
value = -value;
return value;
}
void CBitRead::ReadBitVec3Normal( Vector& fa )
{
int xflag = ReadOneBit();
int yflag = ReadOneBit();
if (xflag)
fa[0] = ReadBitNormal();
else
fa[0] = 0.0f;
if (yflag)
fa[1] = ReadBitNormal();
else
fa[1] = 0.0f;
// The first two imply the third (but not its sign)
int znegative = ReadOneBit();
float fafafbfb = fa[0] * fa[0] + fa[1] * fa[1];
if (fafafbfb < 1.0f)
fa[2] = sqrt( 1.0f - fafafbfb );
else
fa[2] = 0.0f;
if (znegative)
fa[2] = -fa[2];
}
void CBitRead::ReadBitAngles( QAngle& fa )
{
Vector tmp;
ReadBitVec3Coord( tmp );
fa.Init( tmp.x, tmp.y, tmp.z );
}

278
tier1/processor_detect.cpp Normal file
View File

@ -0,0 +1,278 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: win32 dependant ASM code for CPU capability detection
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#if defined _LINUX || defined __APPLE__
#include "processor_detect_linux.cpp"
#elif defined( _X360 )
bool CheckMMXTechnology(void) { return false; }
bool CheckSSETechnology(void) { return false; }
bool CheckSSE2Technology(void) { return false; }
bool Check3DNowTechnology(void) { return false; }
#elif defined( _WIN32 ) && !defined( _X360 )
#pragma optimize( "", off )
#pragma warning( disable: 4800 ) //'int' : forcing value to bool 'true' or 'false' (performance warning)
// stuff from windows.h
#ifndef EXCEPTION_EXECUTE_HANDLER
#define EXCEPTION_EXECUTE_HANDLER 1
#endif
bool CheckMMXTechnology(void)
{
int retval = true;
unsigned int RegEDX = 0;
#ifdef CPUID
_asm pushad;
#endif
__try
{
_asm
{
#ifdef CPUID
xor edx, edx // Clue the compiler that EDX is about to be used.
#endif
mov eax, 1 // set up CPUID to return processor version and features
// 0 = vendor string, 1 = version info, 2 = cache info
CPUID // code bytes = 0fh, 0a2h
mov RegEDX, edx // features returned in edx
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
retval = false;
}
// If CPUID not supported, then certainly no MMX extensions.
if (retval)
{
if (RegEDX & 0x800000) // bit 23 is set for MMX technology
{
__try
{
// try executing the MMX instruction "emms"
_asm EMMS
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
retval = false;
}
}
else
retval = false; // processor supports CPUID but does not support MMX technology
// if retval == 0 here, it means the processor has MMX technology but
// floating-point emulation is on; so MMX technology is unavailable
}
#ifdef CPUID
_asm popad;
#endif
return retval;
}
bool CheckSSETechnology(void)
{
int retval = true;
unsigned int RegEDX = 0;
#ifdef CPUID
_asm pushad;
#endif
// Do we have support for the CPUID function?
__try
{
_asm
{
#ifdef CPUID
xor edx, edx // Clue the compiler that EDX is about to be used.
#endif
mov eax, 1 // set up CPUID to return processor version and features
// 0 = vendor string, 1 = version info, 2 = cache info
CPUID // code bytes = 0fh, 0a2h
mov RegEDX, edx // features returned in edx
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
retval = false;
}
// If CPUID not supported, then certainly no SSE extensions.
if (retval)
{
// Do we have support for SSE in this processor?
if ( RegEDX & 0x2000000L ) // bit 25 is set for SSE technology
{
// Make sure that SSE is supported by executing an inline SSE instruction
// BUGBUG, FIXME - Visual C Version 6.0 does not support SSE inline code YET (No macros from Intel either)
// Fix this if VC7 supports inline SSE instructinons like "xorps" as shown below.
#if 1
__try
{
_asm
{
// Attempt execution of a SSE instruction to make sure OS supports SSE FPU context switches
xorps xmm0, xmm0
// This will work on Win2k+ (Including masking SSE FPU exception to "normalized" values)
// This will work on Win98+ (But no "masking" of FPU exceptions provided)
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
#endif
{
retval = false;
}
}
else
retval = false;
}
#ifdef CPUID
_asm popad;
#endif
return retval;
}
bool CheckSSE2Technology(void)
{
int retval = true;
unsigned int RegEDX = 0;
#ifdef CPUID
_asm pushad;
#endif
// Do we have support for the CPUID function?
__try
{
_asm
{
#ifdef CPUID
xor edx, edx // Clue the compiler that EDX is about to be used.
#endif
mov eax, 1 // set up CPUID to return processor version and features
// 0 = vendor string, 1 = version info, 2 = cache info
CPUID // code bytes = 0fh, 0a2h
mov RegEDX, edx // features returned in edx
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
retval = false;
}
// If CPUID not supported, then certainly no SSE extensions.
if (retval)
{
// Do we have support for SSE in this processor?
if ( RegEDX & 0x04000000 ) // bit 26 is set for SSE2 technology
{
// Make sure that SSE is supported by executing an inline SSE instruction
__try
{
_asm
{
// Attempt execution of a SSE2 instruction to make sure OS supports SSE FPU context switches
xorpd xmm0, xmm0
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
retval = false;
}
}
else
retval = false;
}
#ifdef CPUID
_asm popad;
#endif
return retval;
}
bool Check3DNowTechnology(void)
{
int retval = true;
unsigned int RegEAX = 0;
#ifdef CPUID
_asm pushad;
#endif
// First see if we can execute CPUID at all
__try
{
_asm
{
#ifdef CPUID
// xor edx, edx // Clue the compiler that EDX is about to be used.
#endif
mov eax, 0x80000000 // setup CPUID to return whether AMD >0x80000000 function are supported.
// 0x80000000 = Highest 0x80000000+ function, 0x80000001 = 3DNow support
CPUID // code bytes = 0fh, 0a2h
mov RegEAX, eax // result returned in eax
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
retval = false;
}
// If CPUID not supported, then there is definitely no 3DNow support
if (retval)
{
// Are there any "higher" AMD CPUID functions?
if (RegEAX > 0x80000000L )
{
__try
{
_asm
{
mov eax, 0x80000001 // setup to test for CPU features
CPUID // code bytes = 0fh, 0a2h
shr edx, 31 // If bit 31 is set, we have 3DNow support!
mov retval, edx // Save the return value for end of function
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
retval = false;
}
}
else
{
// processor supports CPUID but does not support AMD CPUID functions
retval = false;
}
}
#ifdef CPUID
_asm popad;
#endif
return retval;
}
#pragma optimize( "", on )
#endif // _WIN32

View File

@ -0,0 +1,47 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: linux dependant ASM code for CPU capability detection
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#define cpuid(in,a,b,c,d) \
asm("pushl %%ebx\n\t" "cpuid\n\t" "movl %%ebx,%%esi\n\t" "pop %%ebx": "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (in));
bool CheckMMXTechnology(void)
{
unsigned long eax,ebx,edx,unused;
cpuid(1,eax,ebx,unused,edx);
return edx & 0x800000;
}
bool CheckSSETechnology(void)
{
unsigned long eax,ebx,edx,unused;
cpuid(1,eax,ebx,unused,edx);
return edx & 0x2000000L;
}
bool CheckSSE2Technology(void)
{
unsigned long eax,ebx,edx,unused;
cpuid(1,eax,ebx,unused,edx);
return edx & 0x04000000;
}
bool Check3DNowTechnology(void)
{
unsigned long eax, unused;
cpuid(0x80000000,eax,unused,unused,unused);
if ( eax > 0x80000000L )
{
cpuid(0x80000001,unused,unused,unused,eax);
return ( eax & 1<<31 );
}
return false;
}

41
tier1/rangecheckedvar.cpp Normal file
View File

@ -0,0 +1,41 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "rangecheckedvar.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
bool g_bDoRangeChecks = true;
static int g_nDisables = 0;
CDisableRangeChecks::CDisableRangeChecks()
{
if ( !ThreadInMainThread() )
return;
g_nDisables++;
g_bDoRangeChecks = false;
}
CDisableRangeChecks::~CDisableRangeChecks()
{
if ( !ThreadInMainThread() )
return;
Assert( g_nDisables > 0 );
--g_nDisables;
if ( g_nDisables == 0 )
{
g_bDoRangeChecks = true;
}
}

334
tier1/stringpool.cpp Normal file
View File

@ -0,0 +1,334 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "convar.h"
#include "tier0/dbg.h"
#include "stringpool.h"
#include "tier1/strtools.h"
#include "generichash.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Comparison function for string sorted associative data structures
//-----------------------------------------------------------------------------
bool StrLess( const char * const &pszLeft, const char * const &pszRight )
{
return ( Q_stricmp( pszLeft, pszRight) < 0 );
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CStringPool::CStringPool()
: m_Strings( 32, 256, StrLess )
{
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CStringPool::~CStringPool()
{
FreeAll();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
unsigned int CStringPool::Count() const
{
return m_Strings.Count();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const char * CStringPool::Find( const char *pszValue )
{
unsigned short i = m_Strings.Find(pszValue);
if ( m_Strings.IsValidIndex(i) )
return m_Strings[i];
return NULL;
}
const char * CStringPool::Allocate( const char *pszValue )
{
char *pszNew;
unsigned short i = m_Strings.Find(pszValue);
bool bNew = (i == m_Strings.InvalidIndex());
if ( !bNew )
return m_Strings[i];
pszNew = strdup( pszValue );
if ( bNew )
m_Strings.Insert( pszNew );
return pszNew;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CStringPool::FreeAll()
{
unsigned short i = m_Strings.FirstInorder();
while ( i != m_Strings.InvalidIndex() )
{
free( (void *)m_Strings[i] );
i = m_Strings.NextInorder(i);
}
m_Strings.RemoveAll();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CCountedStringPool::CCountedStringPool()
{
MEM_ALLOC_CREDIT();
m_HashTable.EnsureCount(HASH_TABLE_SIZE);
for( int i = 0; i < m_HashTable.Count(); i++ )
{
m_HashTable[i] = INVALID_ELEMENT;
}
m_FreeListStart = INVALID_ELEMENT;
m_Elements.AddToTail();
m_Elements[0].pString = NULL;
m_Elements[0].nReferenceCount = 0;
m_Elements[0].nNextElement = INVALID_ELEMENT;
}
CCountedStringPool::~CCountedStringPool()
{
FreeAll();
}
void CCountedStringPool::FreeAll()
{
int i;
// Reset the hash table:
for( i = 0; i < m_HashTable.Count(); i++ )
{
m_HashTable[i] = INVALID_ELEMENT;
}
// Blow away the free list:
m_FreeListStart = INVALID_ELEMENT;
for( i = 0; i < m_Elements.Count(); i++ )
{
if( m_Elements[i].pString )
{
delete [] m_Elements[i].pString;
m_Elements[i].pString = NULL;
m_Elements[i].nReferenceCount = 0;
m_Elements[i].nNextElement = INVALID_ELEMENT;
}
}
// Remove all but the invalid element:
m_Elements.RemoveAll();
m_Elements.AddToTail();
m_Elements[0].pString = NULL;
m_Elements[0].nReferenceCount = 0;
m_Elements[0].nNextElement = INVALID_ELEMENT;
}
unsigned short CCountedStringPool::FindStringHandle( const char* pIntrinsic )
{
if( pIntrinsic == NULL )
return INVALID_ELEMENT;
unsigned short nHashBucketIndex = (HashStringCaseless(pIntrinsic ) %HASH_TABLE_SIZE);
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
// Does the bucket already exist?
if( nCurrentBucket != INVALID_ELEMENT )
{
for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
{
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
{
return nCurrentBucket;
}
}
}
return 0;
}
char* CCountedStringPool::FindString( const char* pIntrinsic )
{
if( pIntrinsic == NULL )
return NULL;
// Yes, this will be NULL on failure.
return m_Elements[FindStringHandle(pIntrinsic)].pString;
}
unsigned short CCountedStringPool::ReferenceStringHandle( const char* pIntrinsic )
{
if( pIntrinsic == NULL )
return INVALID_ELEMENT;
unsigned short nHashBucketIndex = (HashStringCaseless( pIntrinsic ) % HASH_TABLE_SIZE);
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
// Does the bucket already exist?
if( nCurrentBucket != INVALID_ELEMENT )
{
for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
{
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
{
// Anyone who hits 65k references is permanant
if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE )
{
m_Elements[nCurrentBucket].nReferenceCount ++ ;
}
return nCurrentBucket;
}
}
}
if( m_FreeListStart != INVALID_ELEMENT )
{
nCurrentBucket = m_FreeListStart;
m_FreeListStart = m_Elements[nCurrentBucket].nNextElement;
}
else
{
nCurrentBucket = m_Elements.AddToTail();
}
m_Elements[nCurrentBucket].nReferenceCount = 1;
// Insert at the beginning of the bucket:
m_Elements[nCurrentBucket].nNextElement = m_HashTable[ nHashBucketIndex ];
m_HashTable[ nHashBucketIndex ] = nCurrentBucket;
m_Elements[nCurrentBucket].pString = new char[Q_strlen( pIntrinsic ) + 1];
Q_strcpy( m_Elements[nCurrentBucket].pString, pIntrinsic );
return nCurrentBucket;
}
char* CCountedStringPool::ReferenceString( const char* pIntrinsic )
{
if(!pIntrinsic)
return NULL;
return m_Elements[ReferenceStringHandle( pIntrinsic)].pString;
}
void CCountedStringPool::DereferenceString( const char* pIntrinsic )
{
// If we get a NULL pointer, just return
if (!pIntrinsic)
return;
unsigned short nHashBucketIndex = (HashStringCaseless( pIntrinsic ) % m_HashTable.Count());
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
// If there isn't anything in the bucket, just return.
if ( nCurrentBucket == INVALID_ELEMENT )
return;
for( unsigned short previous = INVALID_ELEMENT; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
{
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
{
// Anyone who hits 65k references is permanant
if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE )
{
m_Elements[nCurrentBucket].nReferenceCount --;
}
if( m_Elements[nCurrentBucket].nReferenceCount == 0 )
{
if( previous == INVALID_ELEMENT )
{
m_HashTable[nHashBucketIndex] = m_Elements[nCurrentBucket].nNextElement;
}
else
{
m_Elements[previous].nNextElement = m_Elements[nCurrentBucket].nNextElement;
}
delete [] m_Elements[nCurrentBucket].pString;
m_Elements[nCurrentBucket].pString = NULL;
m_Elements[nCurrentBucket].nReferenceCount = 0;
m_Elements[nCurrentBucket].nNextElement = m_FreeListStart;
m_FreeListStart = nCurrentBucket;
break;
}
}
previous = nCurrentBucket;
}
}
char* CCountedStringPool::HandleToString( unsigned short handle )
{
return m_Elements[handle].pString;
}
void CCountedStringPool::SpewStrings()
{
int i;
for ( i = 0; i < m_Elements.Count(); i++ )
{
char* string = m_Elements[i].pString;
Msg("String %d: ref:%d %s", i, m_Elements[i].nReferenceCount, string == NULL? "EMPTY - ok for slot zero only!" : string);
}
Msg("\n%d total counted strings.", m_Elements.Count());
}
#ifdef _DEBUG
CON_COMMAND( test_stringpool, "Tests the class CStringPool" )
{
CStringPool pool;
Assert(pool.Count() == 0);
pool.Allocate("test");
Assert(pool.Count() == 1);
pool.Allocate("test");
Assert(pool.Count() == 1);
pool.Allocate("test2");
Assert(pool.Count() == 2);
Assert( pool.Find("test2") != NULL );
Assert( pool.Find("TEST") != NULL );
Assert( pool.Find("Test2") != NULL );
Assert( pool.Find("test") != NULL );
pool.FreeAll();
Assert(pool.Count() == 0);
Msg("Pass.");
}
#endif

2015
tier1/strtools.cpp Normal file

File diff suppressed because it is too large Load Diff

568
tier1/tier1-2005.vcproj Normal file
View File

@ -0,0 +1,568 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="tier1"
ProjectGUID="{E1DA8DB8-FB4C-4B14-91A6-98BCED6B9720}"
RootNamespace="tier1"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="4"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
CommandLine=""
ExcludedFromBuild="false"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
UseUnicodeResponseFiles="false"
Optimization="0"
AdditionalIncludeDirectories="..\public;..\public\tier0;..\public\tier1"
PreprocessorDefinitions="WIN32;_WIN32;_DEBUG;DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;TIER1_STATIC_LIB"
StringPooling="true"
MinimalRebuild="true"
ExceptionHandling="0"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
BufferSecurityCheck="false"
FloatingPointModel="2"
TreatWChar_tAsBuiltInType="true"
ForceConformanceInForLoopScope="true"
RuntimeTypeInfo="true"
OpenMP="false"
UsePrecompiledHeader="0"
ExpandAttributedSource="false"
AssemblerOutput="0"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/"
GenerateXMLDocumentationFiles="false"
BrowseInformation="0"
BrowseInformationFile="$(IntDir)/"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
CompileAs="2"
ErrorReporting="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
CommandLine=""
ExcludedFromBuild="false"
/>
<Tool
Name="VCLibrarianTool"
UseUnicodeResponseFiles="false"
AdditionalDependencies="Rpcrt4.lib"
OutputFile="..\lib\public\tier1.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
SuppressStartupBanner="true"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile="$(OutDir)/tier1.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
ExcludedFromBuild="false"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory=".\Release"
ConfigurationType="4"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
CommandLine=""
ExcludedFromBuild="false"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
UseUnicodeResponseFiles="false"
Optimization="2"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
AdditionalIncludeDirectories="..\public;..\public\tier0;..\public\tier1"
PreprocessorDefinitions="WIN32;_WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;TIER1_STATIC_LIB"
StringPooling="true"
ExceptionHandling="0"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="true"
FloatingPointModel="2"
TreatWChar_tAsBuiltInType="true"
ForceConformanceInForLoopScope="true"
RuntimeTypeInfo="true"
OpenMP="false"
UsePrecompiledHeader="0"
ExpandAttributedSource="false"
AssemblerOutput="0"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/"
GenerateXMLDocumentationFiles="false"
BrowseInformation="0"
BrowseInformationFile="$(IntDir)/"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="1"
CompileAs="2"
ErrorReporting="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
CommandLine=""
ExcludedFromBuild="false"
/>
<Tool
Name="VCLibrarianTool"
UseUnicodeResponseFiles="false"
AdditionalDependencies="Rpcrt4.lib"
OutputFile="..\lib\public\tier1.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
SuppressStartupBanner="true"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile="$(OutDir)/tier1.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
ExcludedFromBuild="false"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath=".\bitbuf.cpp"
>
</File>
<File
RelativePath=".\byteswap.cpp"
>
</File>
<File
RelativePath=".\characterset.cpp"
>
</File>
<File
RelativePath=".\checksum_crc.cpp"
>
</File>
<File
RelativePath=".\checksum_md5.cpp"
>
</File>
<File
RelativePath=".\commandbuffer.cpp"
>
</File>
<File
RelativePath=".\convar.cpp"
>
</File>
<File
RelativePath=".\datamanager.cpp"
>
</File>
<File
RelativePath=".\diff.cpp"
>
</File>
<File
RelativePath=".\generichash.cpp"
>
</File>
<File
RelativePath=".\interface.cpp"
>
</File>
<File
RelativePath=".\KeyValues.cpp"
>
</File>
<File
RelativePath=".\mempool.cpp"
>
</File>
<File
RelativePath=".\memstack.cpp"
>
</File>
<File
RelativePath=".\NetAdr.cpp"
>
</File>
<File
RelativePath=".\newbitbuf.cpp"
>
</File>
<File
RelativePath=".\processor_detect.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
ExceptionHandling="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
ExceptionHandling="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\rangecheckedvar.cpp"
>
</File>
<File
RelativePath=".\stringpool.cpp"
>
</File>
<File
RelativePath=".\strtools.cpp"
>
</File>
<File
RelativePath=".\tier1.cpp"
>
</File>
<File
RelativePath=".\tokenreader.cpp"
>
</File>
<File
RelativePath=".\uniqueid.cpp"
>
</File>
<File
RelativePath=".\utlbuffer.cpp"
>
</File>
<File
RelativePath=".\utlbufferutil.cpp"
>
</File>
<File
RelativePath=".\utlstring.cpp"
>
</File>
<File
RelativePath=".\utlsymbol.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath="..\public\tier1\bitbuf.h"
>
</File>
<File
RelativePath="..\public\tier1\byteswap.h"
>
</File>
<File
RelativePath="..\public\tier1\callqueue.h"
>
</File>
<File
RelativePath="..\public\tier1\characterset.h"
>
</File>
<File
RelativePath="..\public\tier1\checksum_crc.h"
>
</File>
<File
RelativePath="..\public\tier1\checksum_md5.h"
>
</File>
<File
RelativePath="..\public\tier1\CommandBuffer.h"
>
</File>
<File
RelativePath="..\public\tier1\convar.h"
>
</File>
<File
RelativePath="..\public\tier1\datamanager.h"
>
</File>
<File
RelativePath="..\public\datamap.h"
>
</File>
<File
RelativePath="..\public\tier1\delegates.h"
>
</File>
<File
RelativePath="..\public\tier1\diff.h"
>
</File>
<File
RelativePath="..\public\tier1\fmtstr.h"
>
</File>
<File
RelativePath="..\public\tier1\functors.h"
>
</File>
<File
RelativePath="..\public\tier1\generichash.h"
>
</File>
<File
RelativePath="..\public\tier1\iconvar.h"
>
</File>
<File
RelativePath="..\public\tier1\interface.h"
>
</File>
<File
RelativePath="..\public\tier1\KeyValues.h"
>
</File>
<File
RelativePath="..\public\tier1\lzmaDecoder.h"
>
</File>
<File
RelativePath="..\public\tier1\lzss.h"
>
</File>
<File
RelativePath="..\public\tier1\mempool.h"
>
</File>
<File
RelativePath="..\public\tier1\memstack.h"
>
</File>
<File
RelativePath="..\public\tier1\netadr.h"
>
</File>
<File
RelativePath="..\public\tier1\processor_detect.h"
>
</File>
<File
RelativePath="..\public\tier1\rangecheckedvar.h"
>
</File>
<File
RelativePath="..\public\tier1\refcount.h"
>
</File>
<File
RelativePath="..\public\tier1\smartptr.h"
>
</File>
<File
RelativePath="..\public\tier1\stringpool.h"
>
</File>
<File
RelativePath="..\public\tier1\strtools.h"
>
</File>
<File
RelativePath="..\public\tier1\tier1.h"
>
</File>
<File
RelativePath="..\public\tier1\tokenreader.h"
>
</File>
<File
RelativePath="..\public\tier1\uniqueid.h"
>
</File>
<File
RelativePath="..\public\tier1\utlbidirectionalset.h"
>
</File>
<File
RelativePath="..\public\tier1\utlblockmemory.h"
>
</File>
<File
RelativePath="..\public\tier1\utlbuffer.h"
>
</File>
<File
RelativePath="..\public\tier1\utlbufferutil.h"
>
</File>
<File
RelativePath="..\public\tier1\utldict.h"
>
</File>
<File
RelativePath="..\public\tier1\utlenvelope.h"
>
</File>
<File
RelativePath="..\public\tier1\utlfixedmemory.h"
>
</File>
<File
RelativePath="..\public\tier1\utlhandletable.h"
>
</File>
<File
RelativePath="..\public\tier1\utlhash.h"
>
</File>
<File
RelativePath="..\public\tier1\utllinkedlist.h"
>
</File>
<File
RelativePath="..\public\tier1\utlmap.h"
>
</File>
<File
RelativePath="..\public\tier1\utlmemory.h"
>
</File>
<File
RelativePath="..\public\tier1\utlmultilist.h"
>
</File>
<File
RelativePath="..\public\tier1\utlpriorityqueue.h"
>
</File>
<File
RelativePath="..\public\tier1\utlqueue.h"
>
</File>
<File
RelativePath="..\public\tier1\utlrbtree.h"
>
</File>
<File
RelativePath="..\public\tier1\UtlSortVector.h"
>
</File>
<File
RelativePath="..\public\tier1\utlstack.h"
>
</File>
<File
RelativePath="..\public\tier1\utlstring.h"
>
</File>
<File
RelativePath="..\public\tier1\UtlStringMap.h"
>
</File>
<File
RelativePath="..\public\tier1\utlsymbol.h"
>
</File>
<File
RelativePath="..\public\tier1\utlvector.h"
>
</File>
<File
RelativePath="..\common\xbox\xboxstubs.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

63
tier1/tier1.cpp Normal file
View File

@ -0,0 +1,63 @@
//===== Copyright © 2005-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: A higher level link library for general use in the game and tools.
//
//===========================================================================//
#include <tier1/tier1.h>
#include "tier0/dbg.h"
#include "vstdlib/iprocessutils.h"
#include "icvar.h"
//-----------------------------------------------------------------------------
// These tier1 libraries must be set by any users of this library.
// They can be set by calling ConnectTier1Libraries or InitDefaultFileSystem.
// It is hoped that setting this, and using this library will be the common mechanism for
// allowing link libraries to access tier1 library interfaces
//-----------------------------------------------------------------------------
ICvar *cvar = 0;
ICvar *g_pCVar = 0;
IProcessUtils *g_pProcessUtils = 0;
static bool s_bConnected = false;
// for utlsortvector.h
#ifndef _WIN32
void *g_pUtlSortVectorQSortContext = NULL;
#endif
//-----------------------------------------------------------------------------
// Call this to connect to all tier 1 libraries.
// It's up to the caller to check the globals it cares about to see if ones are missing
//-----------------------------------------------------------------------------
void ConnectTier1Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount )
{
// Don't connect twice..
if ( s_bConnected )
return;
s_bConnected = true;
for ( int i = 0; i < nFactoryCount; ++i )
{
if ( !g_pCVar )
{
cvar = g_pCVar = ( ICvar * )pFactoryList[i]( CVAR_INTERFACE_VERSION, NULL );
}
if ( !g_pProcessUtils )
{
g_pProcessUtils = ( IProcessUtils * )pFactoryList[i]( PROCESS_UTILS_INTERFACE_VERSION, NULL );
}
}
}
void DisconnectTier1Libraries()
{
if ( !s_bConnected )
return;
g_pCVar = cvar = 0;
g_pProcessUtils = NULL;
s_bConnected = false;
}

480
tier1/tokenreader.cpp Normal file
View File

@ -0,0 +1,480 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "tokenreader.h"
#include "tier0/platform.h"
#include "tier1/strtools.h"
#include "tier0/dbg.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
TokenReader::TokenReader(void)
{
m_szFilename[0] = '\0';
m_nLine = 1;
m_nErrorCount = 0;
m_bStuffed = false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pszFilename -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool TokenReader::Open(const char *pszFilename)
{
open(pszFilename, std::ios::in | std::ios::binary );
Q_strncpy(m_szFilename, pszFilename, sizeof( m_szFilename ) );
m_nLine = 1;
m_nErrorCount = 0;
m_bStuffed = false;
return(is_open() != 0);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TokenReader::Close()
{
close();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *error -
// Output : const char
//-----------------------------------------------------------------------------
const char *TokenReader::Error(char *error, ...)
{
static char szErrorBuf[256];
Q_snprintf(szErrorBuf, sizeof( szErrorBuf ), "File %s, line %d: ", m_szFilename, m_nLine);
Q_strncat(szErrorBuf, error, sizeof( szErrorBuf ), COPY_ALL_CHARACTERS );
m_nErrorCount++;
return(szErrorBuf);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pszStore -
// nSize -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
trtoken_t TokenReader::GetString(char *pszStore, int nSize)
{
if (nSize <= 0)
{
return TOKENERROR;
}
char szBuf[1024];
//
// Until we reach the end of this string or run out of room in
// the destination buffer...
//
while (true)
{
//
// Fetch the next batch of text from the file.
//
get(szBuf, sizeof(szBuf), '\"');
if (eof())
{
return TOKENEOF;
}
if (fail())
{
// Just means nothing was read (empty string probably "")
clear();
}
//
// Transfer the text to the destination buffer.
//
char *pszSrc = szBuf;
while ((*pszSrc != '\0') && (nSize > 1))
{
if (*pszSrc == 0x0d)
{
//
// Newline encountered before closing quote -- unterminated string.
//
*pszStore = '\0';
return TOKENSTRINGTOOLONG;
}
else if (*pszSrc != '\\')
{
*pszStore = *pszSrc;
pszSrc++;
}
else
{
//
// Backslash sequence - replace with the appropriate character.
//
pszSrc++;
if (*pszSrc == 'n')
{
*pszStore = '\n';
}
pszSrc++;
}
pszStore++;
nSize--;
}
if (*pszSrc != '\0')
{
//
// Ran out of room in the destination buffer. Skip to the close-quote,
// terminate the string, and exit.
//
ignore(1024, '\"');
*pszStore = '\0';
return TOKENSTRINGTOOLONG;
}
//
// Check for closing quote.
//
if (peek() == '\"')
{
//
// Eat the close quote and any whitespace.
//
get();
bool bCombineStrings = SkipWhiteSpace();
//
// Combine consecutive quoted strings if the combine strings character was
// encountered between the two strings.
//
if (bCombineStrings && (peek() == '\"'))
{
//
// Eat the open quote and keep parsing this string.
//
get();
}
else
{
//
// Done with this string, terminate the string and exit.
//
*pszStore = '\0';
return STRING;
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns the next token, allocating enough memory to store the token
// plus a terminating NULL.
// Input : pszStore - Pointer to a string that will be allocated.
// Output : Returns the type of token that was read, or TOKENERROR.
//-----------------------------------------------------------------------------
trtoken_t TokenReader::NextTokenDynamic(char **ppszStore)
{
char szTempBuffer[8192];
trtoken_t eType = NextToken(szTempBuffer, sizeof(szTempBuffer));
int len = Q_strlen(szTempBuffer) + 1;
*ppszStore = new char [len];
Assert( *ppszStore );
Q_strncpy(*ppszStore, szTempBuffer, len );
return(eType);
}
//-----------------------------------------------------------------------------
// Purpose: Returns the next token.
// Input : pszStore - Pointer to a string that will receive the token.
// Output : Returns the type of token that was read, or TOKENERROR.
//-----------------------------------------------------------------------------
trtoken_t TokenReader::NextToken(char *pszStore, int nSize)
{
char *pStart = pszStore;
if (!is_open())
{
return TOKENEOF;
}
//
// If they stuffed a token, return that token.
//
if (m_bStuffed)
{
m_bStuffed = false;
Q_strncpy( pszStore, m_szStuffed, nSize );
return m_eStuffed;
}
SkipWhiteSpace();
if (eof())
{
return TOKENEOF;
}
if (fail())
{
return TOKENEOF;
}
char ch = get();
//
// Look for all the valid operators.
//
switch (ch)
{
case '@':
case ',':
case '!':
case '+':
case '&':
case '*':
case '$':
case '.':
case '=':
case ':':
case '[':
case ']':
case '(':
case ')':
case '{':
case '}':
case '\\':
{
pszStore[0] = ch;
pszStore[1] = 0;
return OPERATOR;
}
}
//
// Look for the start of a quoted string.
//
if (ch == '\"')
{
return GetString(pszStore, nSize);
}
//
// Integers consist of numbers with an optional leading minus sign.
//
if (isdigit(ch) || (ch == '-'))
{
do
{
if ( (pszStore - pStart + 1) < nSize )
{
*pszStore = ch;
pszStore++;
}
ch = get();
if (ch == '-')
{
return TOKENERROR;
}
} while (isdigit(ch));
//
// No identifier characters are allowed contiguous with numbers.
//
if (isalpha(ch) || (ch == '_'))
{
return TOKENERROR;
}
//
// Put back the non-numeric character for the next call.
//
putback(ch);
*pszStore = '\0';
return INTEGER;
}
//
// Identifiers consist of a consecutive string of alphanumeric
// characters and underscores.
//
while ( isalpha(ch) || isdigit(ch) || (ch == '_') )
{
if ( (pszStore - pStart + 1) < nSize )
{
*pszStore = ch;
pszStore++;
}
ch = get();
}
//
// Put back the non-identifier character for the next call.
//
putback(ch);
*pszStore = '\0';
return IDENT;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : ttype -
// *pszToken -
//-----------------------------------------------------------------------------
void TokenReader::IgnoreTill(trtoken_t ttype, const char *pszToken)
{
trtoken_t _ttype;
char szBuf[1024];
while(1)
{
_ttype = NextToken(szBuf, sizeof(szBuf));
if(_ttype == TOKENEOF)
return;
if(_ttype == ttype)
{
if(IsToken(pszToken, szBuf))
{
Stuff(ttype, pszToken);
return;
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : ttype -
// pszToken -
//-----------------------------------------------------------------------------
void TokenReader::Stuff(trtoken_t eType, const char *pszToken)
{
m_eStuffed = eType;
Q_strncpy(m_szStuffed, pszToken, sizeof( m_szStuffed ) );
m_bStuffed = true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : ttype -
// pszToken -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool TokenReader::Expecting(trtoken_t ttype, const char *pszToken)
{
char szBuf[1024];
if (NextToken(szBuf, sizeof(szBuf)) != ttype || !IsToken(pszToken, szBuf))
{
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pszStore -
// Output :
//-----------------------------------------------------------------------------
trtoken_t TokenReader::PeekTokenType(char *pszStore, int maxlen )
{
if (!m_bStuffed)
{
m_eStuffed = NextToken(m_szStuffed, sizeof(m_szStuffed));
m_bStuffed = true;
}
if (pszStore)
{
Q_strncpy(pszStore, m_szStuffed, maxlen );
}
return(m_eStuffed);
}
//-----------------------------------------------------------------------------
// Purpose: Gets the next non-whitespace character from the file.
// Input : ch - Receives the character.
// Output : Returns true if the whitespace contained the combine strings
// character '\', which is used to merge consecutive quoted strings.
//-----------------------------------------------------------------------------
bool TokenReader::SkipWhiteSpace(void)
{
bool bCombineStrings = false;
while (true)
{
char ch = get();
if ((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == 0))
{
continue;
}
if (ch == '+')
{
bCombineStrings = true;
continue;
}
if (ch == '\n')
{
m_nLine++;
continue;
}
if (eof())
{
return(bCombineStrings);
}
//
// Check for the start of a comment.
//
if (ch == '/')
{
if (peek() == '/')
{
ignore(1024, '\n');
m_nLine++;
}
}
else
{
//
// It is a worthy character. Put it back.
//
putback(ch);
return(bCombineStrings);
}
}
}

94
tier1/undiff.cpp Normal file
View File

@ -0,0 +1,94 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// UnDiff - Apply difference block
//
//=============================================================================//
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier1/diff.h"
#include "mathlib/mathlib.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
void ApplyDiffs(uint8 const *OldBlock, uint8 const *DiffList,
int OldSize, int DiffListSize, int &ResultListSize,uint8 *Output,uint32 OutSize)
{
uint8 const *copy_src=OldBlock;
uint8 const *end_of_diff_list=DiffList+DiffListSize;
uint8 const *obuf=Output;
while(DiffList<end_of_diff_list)
{
// printf("dptr=%x ",DiffList-d);
uint8 op=*(DiffList++);
if (op==0)
{
uint16 copy_sz=DiffList[0]+256*DiffList[1];
int copy_ofs=DiffList[2]+DiffList[3]*256;
if (copy_ofs>32767)
copy_ofs|=0xffff0000;
// printf("long cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
memcpy(Output,copy_src+copy_ofs,copy_sz);
Output+=copy_sz;
copy_src=copy_src+copy_ofs+copy_sz;
DiffList+=4;
}
else
{
if (op & 0x80)
{
int copy_sz=op & 0x7f;
int copy_ofs;
if (copy_sz==0)
{
copy_sz=DiffList[0];
if (copy_sz==0)
{
// big raw copy
copy_sz=DiffList[1]+256*DiffList[2]+65536*DiffList[3];
memcpy(Output,DiffList+4,copy_sz);
// printf("big rawcopy to %x len=%d\n", Output-obuf,copy_sz);
DiffList+=copy_sz+4;
Output+=copy_sz;
}
else
{
copy_ofs=DiffList[1]+(DiffList[2]*256);
if (copy_ofs>32767)
copy_ofs|=0xffff0000;
// printf("long ofs cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
memcpy(Output,copy_src+copy_ofs,copy_sz);
Output+=copy_sz;
copy_src=copy_src+copy_ofs+copy_sz;
DiffList+=3;
}
}
else
{
copy_ofs=DiffList[0];
if (copy_ofs>127)
copy_ofs|=0xffffff80;
// printf("cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
memcpy(Output,copy_src+copy_ofs,copy_sz);
Output+=copy_sz;
copy_src=copy_src+copy_ofs+copy_sz;
DiffList++;
}
}
else
{
// printf("raw copy %d to %x\n",op & 127,Output-obuf);
memcpy(Output,DiffList,op & 127);
Output+=op & 127;
DiffList+=(op & 127);
}
}
}
ResultListSize=Output-obuf;
}

177
tier1/uniqueid.cpp Normal file
View File

@ -0,0 +1,177 @@
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======//
//
// Purpose:
//
// $NoKeywords: $
//
// Unique ID generation
//=============================================================================//
#include "tier0/platform.h"
#ifdef IS_WINDOWS_PC
#include <windows.h> // UUIDCreate
#else
#include "checksum_crc.h"
#endif
#include "tier1/uniqueid.h"
#include "tier1/utlbuffer.h"
//-----------------------------------------------------------------------------
// Creates a new unique id
//-----------------------------------------------------------------------------
void CreateUniqueId( UniqueId_t *pDest )
{
#ifdef IS_WINDOWS_PC
Assert( sizeof( UUID ) == sizeof( *pDest ) );
UuidCreate( (UUID *)pDest );
#else
// X360/linux TBD: Need a real UUID Implementation
Q_memset( pDest, 0, sizeof( UniqueId_t ) );
#endif
}
//-----------------------------------------------------------------------------
// Creates a new unique id from a string representation of one
//-----------------------------------------------------------------------------
bool UniqueIdFromString( UniqueId_t *pDest, const char *pBuf, int nMaxLen )
{
if ( nMaxLen == 0 )
{
nMaxLen = Q_strlen( pBuf );
}
char *pTemp = (char*)stackalloc( nMaxLen + 1 );
V_strncpy( pTemp, pBuf, nMaxLen + 1 );
--nMaxLen;
while( (nMaxLen >= 0) && isspace( pTemp[nMaxLen] ) )
{
--nMaxLen;
}
pTemp[ nMaxLen + 1 ] = 0;
while( *pTemp && isspace( *pTemp ) )
{
++pTemp;
}
#ifdef IS_WINDOWS_PC
Assert( sizeof( UUID ) == sizeof( *pDest ) );
if ( RPC_S_OK != UuidFromString( (unsigned char *)pTemp, (UUID *)pDest ) )
{
InvalidateUniqueId( pDest );
return false;
}
#else
// X360TBD: Need a real UUID Implementation
// For now, use crc to generate a unique ID from the UUID string.
Q_memset( pDest, 0, sizeof( UniqueId_t ) );
if ( nMaxLen > 0 )
{
CRC32_t crc;
CRC32_Init( &crc );
CRC32_ProcessBuffer( &crc, pBuf, nMaxLen );
CRC32_Final( &crc );
Q_memcpy( pDest, &crc, sizeof( CRC32_t ) );
}
#endif
return true;
}
//-----------------------------------------------------------------------------
// Sets an object ID to be an invalid state
//-----------------------------------------------------------------------------
void InvalidateUniqueId( UniqueId_t *pDest )
{
Assert( pDest );
memset( pDest, 0, sizeof( UniqueId_t ) );
}
bool IsUniqueIdValid( const UniqueId_t &id )
{
UniqueId_t invalidId;
memset( &invalidId, 0, sizeof( UniqueId_t ) );
return !IsUniqueIdEqual( invalidId, id );
}
bool IsUniqueIdEqual( const UniqueId_t &id1, const UniqueId_t &id2 )
{
return memcmp( &id1, &id2, sizeof( UniqueId_t ) ) == 0;
}
void UniqueIdToString( const UniqueId_t &id, char *pBuf, int nMaxLen )
{
pBuf[ 0 ] = 0;
// X360TBD: Need a real UUID Implementation
#ifdef IS_WINDOWS_PC
UUID *self = ( UUID * )&id;
unsigned char *outstring = NULL;
UuidToString( self, &outstring );
if ( outstring && *outstring )
{
Q_strncpy( pBuf, (const char *)outstring, nMaxLen );
RpcStringFree( &outstring );
}
#endif
}
void CopyUniqueId( const UniqueId_t &src, UniqueId_t *pDest )
{
memcpy( pDest, &src, sizeof( UniqueId_t ) );
}
bool Serialize( CUtlBuffer &buf, const UniqueId_t &src )
{
// X360TBD: Need a real UUID Implementation
#ifdef IS_WINDOWS_PC
if ( buf.IsText() )
{
UUID *pId = ( UUID * )&src;
unsigned char *outstring = NULL;
UuidToString( pId, &outstring );
if ( outstring && *outstring )
{
buf.PutString( (const char *)outstring );
RpcStringFree( &outstring );
}
else
{
buf.PutChar( '\0' );
}
}
else
{
buf.Put( &src, sizeof(UniqueId_t) );
}
return buf.IsValid();
#else
return false;
#endif
}
bool Unserialize( CUtlBuffer &buf, UniqueId_t &dest )
{
if ( buf.IsText() )
{
int nTextLen = buf.PeekStringLength();
char *pBuf = (char*)stackalloc( nTextLen );
buf.GetString( pBuf, nTextLen );
UniqueIdFromString( &dest, pBuf, nTextLen );
}
else
{
buf.Get( &dest, sizeof(UniqueId_t) );
}
return buf.IsValid();
}

1753
tier1/utlbuffer.cpp Normal file

File diff suppressed because it is too large Load Diff

561
tier1/utlbufferutil.cpp Normal file
View File

@ -0,0 +1,561 @@
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// $Header: $
// $NoKeywords: $
//
// Serialization buffer
//===========================================================================//
#ifdef _MSC_VER
#pragma warning (disable : 4514)
#endif
#include "tier1/utlbufferutil.h"
#include "tier1/utlbuffer.h"
#include "mathlib/vector.h"
#include "mathlib/vector2d.h"
#include "mathlib/vector4d.h"
#include "mathlib/vmatrix.h"
#include "Color.h"
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
#include "tier1/utlstring.h"
#include "tier1/strtools.h"
#include "tier1/characterset.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// For serialization, set the delimiter rules
//-----------------------------------------------------------------------------
CUtlCharConversion *s_pConv = NULL;
const char *s_pUtlBufferUtilArrayDelim = NULL;
void SetSerializationDelimiter( CUtlCharConversion *pConv )
{
s_pConv = pConv;
}
void SetSerializationArrayDelimiter( const char *pDelimiter )
{
s_pUtlBufferUtilArrayDelim = pDelimiter;
}
//-----------------------------------------------------------------------------
// Serialize a floating point number in text mode in a readably friendly fashion
//-----------------------------------------------------------------------------
static void SerializeFloat( CUtlBuffer &buf, float f )
{
Assert( buf.IsText() );
// FIXME: Print this in a way that we never lose precision
char pTemp[256];
int nLen = Q_snprintf( pTemp, sizeof(pTemp), "%.10f", f );
while ( nLen > 0 && pTemp[nLen-1] == '0' )
{
--nLen;
pTemp[nLen] = 0;
}
if ( nLen > 0 && pTemp[nLen-1] == '.' )
{
--nLen;
pTemp[nLen] = 0;
}
buf.PutString( pTemp );
}
static void SerializeFloats( CUtlBuffer &buf, int nCount, const float *pFloats )
{
for ( int i = 0; i < nCount; ++i )
{
SerializeFloat( buf, pFloats[i] );
if ( i != nCount-1 )
{
buf.PutChar( ' ' );
}
}
}
//-----------------------------------------------------------------------------
// Serialization methods for basic types
//-----------------------------------------------------------------------------
bool Serialize( CUtlBuffer &buf, const bool &src )
{
if ( buf.IsText() )
{
buf.Printf( "%d", src );
}
else
{
buf.PutChar( src );
}
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, bool &dest )
{
if ( buf.IsText() )
{
int nValue = 0;
int nRetVal = buf.Scanf( "%d", &nValue );
dest = ( nValue != 0 );
return (nRetVal == 1) && buf.IsValid();
}
dest = ( buf.GetChar( ) != 0 );
return buf.IsValid();
}
bool Serialize( CUtlBuffer &buf, const int &src )
{
if ( buf.IsText() )
{
buf.Printf( "%d", src );
}
else
{
buf.PutInt( src );
}
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, int &dest )
{
if ( buf.IsText() )
{
int nRetVal = buf.Scanf( "%d", &dest );
return (nRetVal == 1) && buf.IsValid();
}
dest = buf.GetInt( );
return buf.IsValid();
}
bool Serialize( CUtlBuffer &buf, const float &src )
{
if ( buf.IsText() )
{
SerializeFloat( buf, src );
}
else
{
buf.PutFloat( src );
}
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, float &dest )
{
if ( buf.IsText() )
{
// FIXME: Print this in a way that we never lose precision
int nRetVal = buf.Scanf( "%f", &dest );
return (nRetVal == 1) && buf.IsValid();
}
dest = buf.GetFloat( );
return buf.IsValid();
}
//-----------------------------------------------------------------------------
// Attribute types related to vector math
//-----------------------------------------------------------------------------
bool Serialize( CUtlBuffer &buf, const Vector2D &src )
{
if ( buf.IsText() )
{
SerializeFloats( buf, 2, src.Base() );
}
else
{
buf.PutFloat( src.x );
buf.PutFloat( src.y );
}
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, Vector2D &dest )
{
if ( buf.IsText() )
{
// FIXME: Print this in a way that we never lose precision
int nRetVal = buf.Scanf( "%f %f", &dest.x, &dest.y );
return (nRetVal == 2) && buf.IsValid();
}
dest.x = buf.GetFloat( );
dest.y = buf.GetFloat( );
return buf.IsValid();
}
bool Serialize( CUtlBuffer &buf, const Vector &src )
{
if ( buf.IsText() )
{
SerializeFloats( buf, 3, src.Base() );
}
else
{
buf.PutFloat( src.x );
buf.PutFloat( src.y );
buf.PutFloat( src.z );
}
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, Vector &dest )
{
if ( buf.IsText() )
{
// FIXME: Print this in a way that we never lose precision
int nRetVal = buf.Scanf( "%f %f %f", &dest.x, &dest.y, &dest.z );
return (nRetVal == 3) && buf.IsValid();
}
dest.x = buf.GetFloat( );
dest.y = buf.GetFloat( );
dest.z = buf.GetFloat( );
return buf.IsValid();
}
bool Serialize( CUtlBuffer &buf, const Vector4D &src )
{
if ( buf.IsText() )
{
SerializeFloats( buf, 4, src.Base() );
}
else
{
buf.PutFloat( src.x );
buf.PutFloat( src.y );
buf.PutFloat( src.z );
buf.PutFloat( src.w );
}
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, Vector4D &dest )
{
if ( buf.IsText() )
{
// FIXME: Print this in a way that we never lose precision
int nRetVal = buf.Scanf( "%f %f %f %f", &dest.x, &dest.y, &dest.z, &dest.w );
return (nRetVal == 4) && buf.IsValid();
}
dest.x = buf.GetFloat( );
dest.y = buf.GetFloat( );
dest.z = buf.GetFloat( );
dest.w = buf.GetFloat( );
return buf.IsValid();
}
bool Serialize( CUtlBuffer &buf, const QAngle &src )
{
if ( buf.IsText() )
{
SerializeFloats( buf, 3, src.Base() );
}
else
{
buf.PutFloat( src.x );
buf.PutFloat( src.y );
buf.PutFloat( src.z );
}
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, QAngle &dest )
{
if ( buf.IsText() )
{
// FIXME: Print this in a way that we never lose precision
int nRetVal = buf.Scanf( "%f %f %f", &dest.x, &dest.y, &dest.z );
return (nRetVal == 3) && buf.IsValid();
}
dest.x = buf.GetFloat( );
dest.y = buf.GetFloat( );
dest.z = buf.GetFloat( );
return buf.IsValid();
}
bool Serialize( CUtlBuffer &buf, const Quaternion &src )
{
if ( buf.IsText() )
{
SerializeFloats( buf, 4, &src.x );
}
else
{
buf.PutFloat( src.x );
buf.PutFloat( src.y );
buf.PutFloat( src.z );
buf.PutFloat( src.w );
}
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, Quaternion &dest )
{
if ( buf.IsText() )
{
// FIXME: Print this in a way that we never lose precision
int nRetVal = buf.Scanf( "%f %f %f %f", &dest.x, &dest.y, &dest.z, &dest.w );
return (nRetVal == 4) && buf.IsValid();
}
dest.x = buf.GetFloat( );
dest.y = buf.GetFloat( );
dest.z = buf.GetFloat( );
dest.w = buf.GetFloat( );
return buf.IsValid();
}
bool Serialize( CUtlBuffer &buf, const VMatrix &src )
{
if ( buf.IsText() )
{
buf.Printf( "\n" );
SerializeFloats( buf, 4, src[0] );
buf.Printf( "\n" );
SerializeFloats( buf, 4, src[1] );
buf.Printf( "\n" );
SerializeFloats( buf, 4, src[2] );
buf.Printf( "\n" );
SerializeFloats( buf, 4, src[3] );
buf.Printf( "\n" );
}
else
{
buf.Put( &src, sizeof(VMatrix) );
}
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, VMatrix &dest )
{
if ( !buf.IsValid() )
return false;
if ( buf.IsText() )
{
int nRetVal = buf.Scanf( "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
&dest[ 0 ][ 0 ], &dest[ 0 ][ 1 ], &dest[ 0 ][ 2 ], &dest[ 0 ][ 3 ],
&dest[ 1 ][ 0 ], &dest[ 1 ][ 1 ], &dest[ 1 ][ 2 ], &dest[ 1 ][ 3 ],
&dest[ 2 ][ 0 ], &dest[ 2 ][ 1 ], &dest[ 2 ][ 2 ], &dest[ 2 ][ 3 ],
&dest[ 3 ][ 0 ], &dest[ 3 ][ 1 ], &dest[ 3 ][ 2 ], &dest[ 3 ][ 3 ] );
return (nRetVal == 16);
}
buf.Get( &dest, sizeof(VMatrix) );
return true;
}
//-----------------------------------------------------------------------------
// Color attribute
//-----------------------------------------------------------------------------
bool Serialize( CUtlBuffer &buf, const Color &src )
{
if ( buf.IsText() )
{
buf.Printf( "%d %d %d %d", src[0], src[1], src[2], src[3] );
}
else
{
buf.PutUnsignedChar( src[0] );
buf.PutUnsignedChar( src[1] );
buf.PutUnsignedChar( src[2] );
buf.PutUnsignedChar( src[3] );
}
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, Color &dest )
{
if ( buf.IsText() )
{
int r = 0, g = 0, b = 0, a = 255;
int nRetVal = buf.Scanf( "%d %d %d %d", &r, &g, &b, &a );
dest.SetColor( r, g, b, a );
return (nRetVal == 4) && buf.IsValid();
}
dest[0] = buf.GetUnsignedChar( );
dest[1] = buf.GetUnsignedChar( );
dest[2] = buf.GetUnsignedChar( );
dest[3] = buf.GetUnsignedChar( );
return buf.IsValid();
}
/*
//-----------------------------------------------------------------------------
// Object ID attribute
//-----------------------------------------------------------------------------
bool Serialize( CUtlBuffer &buf, const DmObjectId_t &src )
{
return g_pDataModel->Serialize( buf, src );
}
bool Unserialize( CUtlBuffer &buf, DmObjectId_t &dest )
{
return g_pDataModel->Unserialize( buf, &dest );
}
*/
//-----------------------------------------------------------------------------
// Binary buffer attribute
//-----------------------------------------------------------------------------
bool Serialize( CUtlBuffer &buf, const CUtlBinaryBlock &src )
{
int nLength = src.Length();
if ( !buf.IsText() )
{
buf.PutInt( nLength );
if ( nLength != 0 )
{
buf.Put( src.Get(), nLength );
}
return buf.IsValid();
}
// Writes out uuencoded binaries
for ( int i = 0; i < nLength; ++i )
{
if ( (i % 40) == 0 )
{
buf.PutChar( '\n' );
}
char b1 = src[i] & 0xF;
char b2 = src[i] >> 4;
char c1 = ( b1 <= 9 ) ? b1 + '0' : b1 - 10 + 'A';
char c2 = ( b2 <= 9 ) ? b2 + '0' : b2 - 10 + 'A';
buf.PutChar( c2 );
buf.PutChar( c1 );
}
buf.PutChar( '\n' );
return buf.IsValid();
}
static int CountBinaryBytes( CUtlBuffer &buf, int *pEndGet )
{
// This counts the number of bytes in the uuencoded text
int nStartGet = buf.TellGet();
buf.EatWhiteSpace();
*pEndGet = buf.TellGet();
int nByteCount = 0;
while ( buf.IsValid() )
{
char c1 = buf.GetChar();
char c2 = buf.GetChar();
bool bIsNum1 = ( c1 >= '0' ) && ( c1 <= '9' );
bool bIsNum2 = ( c2 >= '0' ) && ( c2 <= '9' );
bool bIsAlpha1 = (( c1 >= 'A' ) && ( c1 <= 'F' )) || (( c1 >= 'a' ) && ( c1 <= 'f' ));
bool bIsAlpha2 = (( c2 >= 'A' ) && ( c2 <= 'F' )) || (( c2 >= 'a' ) && ( c2 <= 'f' ));
if ( !(bIsNum1 || bIsAlpha1) || !(bIsNum2 || bIsAlpha2) )
break;
buf.EatWhiteSpace();
*pEndGet = buf.TellGet();
++nByteCount;
}
buf.SeekGet( CUtlBuffer::SEEK_HEAD, nStartGet );
return nByteCount;
}
inline static unsigned char HexCharToInt( int c1 )
{
if (( c1 >= '0' ) && ( c1 <= '9' ))
return c1 - '0';
if (( c1 >= 'A' ) && ( c1 <= 'F' ))
return 10 + c1 - 'A';
if (( c1 >= 'a' ) && ( c1 <= 'f' ))
return 10 + c1 - 'a';
return 0xFF;
}
bool Unserialize( CUtlBuffer &buf, CUtlBinaryBlock &dest )
{
if ( !buf.IsText() )
{
int nLen = buf.GetInt( );
dest.SetLength( nLen );
if ( dest.Length() != 0 )
{
buf.Get( dest.Get(), dest.Length() );
}
if ( nLen != dest.Length() )
{
buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nLen - dest.Length() );
return false;
}
return buf.IsValid();
}
int nEndGet;
int nByteCount = CountBinaryBytes( buf, &nEndGet );
if ( nByteCount < 0 )
return false;
buf.EatWhiteSpace();
int nDest = 0;
dest.SetLength( nByteCount );
while( buf.TellGet() < nEndGet )
{
char c1 = buf.GetChar();
char c2 = buf.GetChar();
unsigned char b1 = HexCharToInt( c1 );
unsigned char b2 = HexCharToInt( c2 );
if ( b1 == 0xFF || b2 == 0xFF )
return false;
dest[ nDest++ ] = b2 | ( b1 << 4 );
buf.EatWhiteSpace();
}
return true;
}
//-----------------------------------------------------------------------------
// String attribute
//-----------------------------------------------------------------------------
bool Serialize( CUtlBuffer &buf, const CUtlString &src )
{
buf.PutDelimitedString( s_pConv, src.Get() );
return buf.IsValid();
}
bool Unserialize( CUtlBuffer &buf, CUtlString &dest )
{
int nLen = buf.PeekDelimitedStringLength( s_pConv );
dest.SetLength( nLen - 1 ); // -1 because the length returned includes space for \0
buf.GetDelimitedString( s_pConv, dest.Get(), nLen );
return buf.IsValid();
}

334
tier1/utlstring.cpp Normal file
View File

@ -0,0 +1,334 @@
//====== Copyright © 1996-2004, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "tier1/utlstring.h"
#include "tier1/strtools.h"
//-----------------------------------------------------------------------------
// Base class, containing simple memory management
//-----------------------------------------------------------------------------
CUtlBinaryBlock::CUtlBinaryBlock( int growSize, int initSize ) : m_Memory( growSize, initSize )
{
m_nActualLength = 0;
}
CUtlBinaryBlock::CUtlBinaryBlock( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Memory( (unsigned char*)pMemory, nSizeInBytes )
{
m_nActualLength = nInitialLength;
}
CUtlBinaryBlock::CUtlBinaryBlock( const void* pMemory, int nSizeInBytes ) : m_Memory( (const unsigned char*)pMemory, nSizeInBytes )
{
m_nActualLength = nSizeInBytes;
}
CUtlBinaryBlock::CUtlBinaryBlock( const CUtlBinaryBlock& src )
{
Set( src.Get(), src.Length() );
}
void CUtlBinaryBlock::Get( void *pValue, int nLen ) const
{
Assert( nLen > 0 );
if ( m_nActualLength < nLen )
{
nLen = m_nActualLength;
}
if ( nLen > 0 )
{
memcpy( pValue, m_Memory.Base(), nLen );
}
}
void CUtlBinaryBlock::SetLength( int nLength )
{
Assert( !m_Memory.IsReadOnly() );
m_nActualLength = nLength;
if ( nLength > m_Memory.NumAllocated() )
{
int nOverFlow = nLength - m_Memory.NumAllocated();
m_Memory.Grow( nOverFlow );
// If the reallocation failed, clamp length
if ( nLength > m_Memory.NumAllocated() )
{
m_nActualLength = m_Memory.NumAllocated();
}
}
#ifdef _DEBUG
if ( m_Memory.NumAllocated() > m_nActualLength )
{
memset( ( ( char * )m_Memory.Base() ) + m_nActualLength, 0xEB, m_Memory.NumAllocated() - m_nActualLength );
}
#endif
}
void CUtlBinaryBlock::Set( const void *pValue, int nLen )
{
Assert( !m_Memory.IsReadOnly() );
if ( !pValue )
{
nLen = 0;
}
SetLength( nLen );
if ( m_nActualLength )
{
if ( ( ( const char * )m_Memory.Base() ) >= ( ( const char * )pValue ) + nLen ||
( ( const char * )m_Memory.Base() ) + m_nActualLength <= ( ( const char * )pValue ) )
{
memcpy( m_Memory.Base(), pValue, m_nActualLength );
}
else
{
memmove( m_Memory.Base(), pValue, m_nActualLength );
}
}
}
CUtlBinaryBlock &CUtlBinaryBlock::operator=( const CUtlBinaryBlock &src )
{
Assert( !m_Memory.IsReadOnly() );
Set( src.Get(), src.Length() );
return *this;
}
bool CUtlBinaryBlock::operator==( const CUtlBinaryBlock &src ) const
{
if ( src.Length() != Length() )
return false;
return !memcmp( src.Get(), Get(), Length() );
}
//-----------------------------------------------------------------------------
// Simple string class.
//-----------------------------------------------------------------------------
CUtlString::CUtlString()
{
}
CUtlString::CUtlString( const char *pString )
{
Set( pString );
}
CUtlString::CUtlString( const CUtlString& string )
{
Set( string.Get() );
}
// Attaches the string to external memory. Useful for avoiding a copy
CUtlString::CUtlString( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Storage( pMemory, nSizeInBytes, nInitialLength )
{
}
CUtlString::CUtlString( const void* pMemory, int nSizeInBytes ) : m_Storage( pMemory, nSizeInBytes )
{
}
void CUtlString::Set( const char *pValue )
{
Assert( !m_Storage.IsReadOnly() );
int nLen = pValue ? Q_strlen(pValue) + 1 : 0;
m_Storage.Set( pValue, nLen );
}
// Returns strlen
int CUtlString::Length() const
{
return m_Storage.Length() ? m_Storage.Length() - 1 : 0;
}
// Sets the length (used to serialize into the buffer )
void CUtlString::SetLength( int nLen )
{
Assert( !m_Storage.IsReadOnly() );
// Add 1 to account for the NULL
m_Storage.SetLength( nLen > 0 ? nLen + 1 : 0 );
}
const char *CUtlString::Get( ) const
{
if ( m_Storage.Length() == 0 )
{
return "";
}
return reinterpret_cast< const char* >( m_Storage.Get() );
}
// Converts to c-strings
CUtlString::operator const char*() const
{
return Get();
}
char *CUtlString::Get()
{
Assert( !m_Storage.IsReadOnly() );
if ( m_Storage.Length() == 0 )
{
// In general, we optimise away small mallocs for empty strings
// but if you ask for the non-const bytes, they must be writable
// so we can't return "" here, like we do for the const version - jd
m_Storage.SetLength( 1 );
m_Storage[ 0 ] = '\0';
}
return reinterpret_cast< char* >( m_Storage.Get() );
}
CUtlString &CUtlString::operator=( const CUtlString &src )
{
Assert( !m_Storage.IsReadOnly() );
m_Storage = src.m_Storage;
return *this;
}
CUtlString &CUtlString::operator=( const char *src )
{
Assert( !m_Storage.IsReadOnly() );
Set( src );
return *this;
}
bool CUtlString::operator==( const CUtlString &src ) const
{
return m_Storage == src.m_Storage;
}
bool CUtlString::operator==( const char *src ) const
{
return ( strcmp( Get(), src ) == 0 );
}
CUtlString &CUtlString::operator+=( const CUtlString &rhs )
{
Assert( !m_Storage.IsReadOnly() );
const int lhsLength( Length() );
const int rhsLength( rhs.Length() );
const int requestedLength( lhsLength + rhsLength );
SetLength( requestedLength );
const int allocatedLength( Length() );
const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
memcpy( Get() + lhsLength, rhs.Get(), copyLength );
m_Storage[ allocatedLength ] = '\0';
return *this;
}
CUtlString &CUtlString::operator+=( const char *rhs )
{
Assert( !m_Storage.IsReadOnly() );
const int lhsLength( Length() );
const int rhsLength( Q_strlen( rhs ) );
const int requestedLength( lhsLength + rhsLength );
SetLength( requestedLength );
const int allocatedLength( Length() );
const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
memcpy( Get() + lhsLength, rhs, copyLength );
m_Storage[ allocatedLength ] = '\0';
return *this;
}
CUtlString &CUtlString::operator+=( char c )
{
Assert( !m_Storage.IsReadOnly() );
int nLength = Length();
SetLength( nLength + 1 );
m_Storage[ nLength ] = c;
m_Storage[ nLength+1 ] = '\0';
return *this;
}
CUtlString &CUtlString::operator+=( int rhs )
{
Assert( !m_Storage.IsReadOnly() );
Assert( sizeof( rhs ) == 4 );
char tmpBuf[ 12 ]; // Sufficient for a signed 32 bit integer [ -2147483648 to +2147483647 ]
Q_snprintf( tmpBuf, sizeof( tmpBuf ), "%d", rhs );
tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
return operator+=( tmpBuf );
}
CUtlString &CUtlString::operator+=( double rhs )
{
Assert( !m_Storage.IsReadOnly() );
char tmpBuf[ 256 ]; // How big can doubles be??? Dunno.
Q_snprintf( tmpBuf, sizeof( tmpBuf ), "%lg", rhs );
tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
return operator+=( tmpBuf );
}
int CUtlString::Format( const char *pFormat, ... )
{
Assert( !m_Storage.IsReadOnly() );
char tmpBuf[ 4096 ]; //< Nice big 4k buffer, as much memory as my first computer had, a Radio Shack Color Computer
va_list marker;
va_start( marker, pFormat );
#ifdef _WIN32
int len = _vsnprintf( tmpBuf, sizeof( tmpBuf ) - 1, pFormat, marker );
#elif defined _LINUX || defined __APPLE__
int len = vsnprintf( tmpBuf, sizeof( tmpBuf ) - 1, pFormat, marker );
#else
#error "define vsnprintf type."
#endif
va_end( marker );
// Len < 0 represents an overflow
if( len < 0 )
{
len = sizeof( tmpBuf ) - 1;
tmpBuf[sizeof( tmpBuf ) - 1] = 0;
}
Set( tmpBuf );
return len;
}
//-----------------------------------------------------------------------------
// Strips the trailing slash
//-----------------------------------------------------------------------------
void CUtlString::StripTrailingSlash()
{
if ( IsEmpty() )
return;
int nLastChar = Length() - 1;
char c = m_Storage[ nLastChar ];
if ( c == '\\' || c == '/' )
{
m_Storage[ nLastChar ] = 0;
m_Storage.SetLength( m_Storage.Length() - 1 );
}
}

397
tier1/utlsymbol.cpp Normal file
View File

@ -0,0 +1,397 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Defines a symbol table
//
// $Header: $
// $NoKeywords: $
//=============================================================================//
#ifdef _MSC_VER
#pragma warning (disable:4514)
#endif
#include "utlsymbol.h"
#include "KeyValues.h"
#include "tier0/threadtools.h"
#include "tier0/memdbgon.h"
#include "stringpool.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define INVALID_STRING_INDEX CStringPoolIndex( 0xFFFF, 0xFFFF )
#define MIN_STRING_POOL_SIZE 2048
//-----------------------------------------------------------------------------
// globals
//-----------------------------------------------------------------------------
CUtlSymbolTableMT* CUtlSymbol::s_pSymbolTable = 0;
bool CUtlSymbol::s_bAllowStaticSymbolTable = true;
//-----------------------------------------------------------------------------
// symbol methods
//-----------------------------------------------------------------------------
void CUtlSymbol::Initialize()
{
// If this assert fails, then the module that this call is in has chosen to disallow
// use of the static symbol table. Usually, it's to prevent confusion because it's easy
// to accidentally use the global symbol table when you really want to use a specific one.
Assert( s_bAllowStaticSymbolTable );
// necessary to allow us to create global symbols
static bool symbolsInitialized = false;
if (!symbolsInitialized)
{
s_pSymbolTable = new CUtlSymbolTableMT;
symbolsInitialized = true;
}
}
//-----------------------------------------------------------------------------
// Purpose: Singleton to delete table on exit from module
//-----------------------------------------------------------------------------
class CCleanupUtlSymbolTable
{
public:
~CCleanupUtlSymbolTable()
{
delete CUtlSymbol::s_pSymbolTable;
CUtlSymbol::s_pSymbolTable = NULL;
}
};
static CCleanupUtlSymbolTable g_CleanupSymbolTable;
CUtlSymbolTableMT* CUtlSymbol::CurrTable()
{
Initialize();
return s_pSymbolTable;
}
//-----------------------------------------------------------------------------
// string->symbol->string
//-----------------------------------------------------------------------------
CUtlSymbol::CUtlSymbol( const char* pStr )
{
m_Id = CurrTable()->AddString( pStr );
}
const char* CUtlSymbol::String( ) const
{
return CurrTable()->String(m_Id);
}
void CUtlSymbol::DisableStaticSymbolTable()
{
s_bAllowStaticSymbolTable = false;
}
//-----------------------------------------------------------------------------
// checks if the symbol matches a string
//-----------------------------------------------------------------------------
bool CUtlSymbol::operator==( const char* pStr ) const
{
if (m_Id == UTL_INVAL_SYMBOL)
return false;
return strcmp( String(), pStr ) == 0;
}
//-----------------------------------------------------------------------------
// symbol table stuff
//-----------------------------------------------------------------------------
inline const char* CUtlSymbolTable::StringFromIndex( const CStringPoolIndex &index ) const
{
Assert( index.m_iPool < m_StringPools.Count() );
Assert( index.m_iOffset < m_StringPools[index.m_iPool]->m_TotalLen );
return &m_StringPools[index.m_iPool]->m_Data[index.m_iOffset];
}
bool CUtlSymbolTable::CLess::operator()( const CStringPoolIndex &i1, const CStringPoolIndex &i2 ) const
{
// Need to do pointer math because CUtlSymbolTable is used in CUtlVectors, and hence
// can be arbitrarily moved in memory on a realloc. Yes, this is portable. In reality,
// right now at least, because m_LessFunc is the first member of CUtlRBTree, and m_Lookup
// is the first member of CUtlSymbolTabke, this == pTable
CUtlSymbolTable *pTable = (CUtlSymbolTable *)( (byte *)this - offsetof(CUtlSymbolTable::CTree, m_LessFunc) ) - offsetof(CUtlSymbolTable, m_Lookup );
const char* str1 = (i1 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString :
pTable->StringFromIndex( i1 );
const char* str2 = (i2 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString :
pTable->StringFromIndex( i2 );
if ( !pTable->m_bInsensitive )
return strcmp( str1, str2 ) < 0;
else
return strcmpi( str1, str2 ) < 0;
}
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CUtlSymbolTable::CUtlSymbolTable( int growSize, int initSize, bool caseInsensitive ) :
m_Lookup( growSize, initSize ), m_bInsensitive( caseInsensitive ), m_StringPools( 8 )
{
}
CUtlSymbolTable::~CUtlSymbolTable()
{
// Release the stringpool string data
RemoveAll();
}
CUtlSymbol CUtlSymbolTable::Find( const char* pString ) const
{
if (!pString)
return CUtlSymbol();
// Store a special context used to help with insertion
m_pUserSearchString = pString;
// Passing this special invalid symbol makes the comparison function
// use the string passed in the context
UtlSymId_t idx = m_Lookup.Find( INVALID_STRING_INDEX );
#ifdef _DEBUG
m_pUserSearchString = NULL;
#endif
return CUtlSymbol( idx );
}
int CUtlSymbolTable::FindPoolWithSpace( int len ) const
{
for ( int i=0; i < m_StringPools.Count(); i++ )
{
StringPool_t *pPool = m_StringPools[i];
if ( (pPool->m_TotalLen - pPool->m_SpaceUsed) >= len )
{
return i;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// Finds and/or creates a symbol based on the string
//-----------------------------------------------------------------------------
CUtlSymbol CUtlSymbolTable::AddString( const char* pString )
{
if (!pString)
return CUtlSymbol( UTL_INVAL_SYMBOL );
CUtlSymbol id = Find( pString );
if (id.IsValid())
return id;
int len = strlen(pString) + 1;
// Find a pool with space for this string, or allocate a new one.
int iPool = FindPoolWithSpace( len );
if ( iPool == -1 )
{
// Add a new pool.
int newPoolSize = MAX( len, MIN_STRING_POOL_SIZE );
StringPool_t *pPool = (StringPool_t*)malloc( sizeof( StringPool_t ) + newPoolSize - 1 );
pPool->m_TotalLen = newPoolSize;
pPool->m_SpaceUsed = 0;
iPool = m_StringPools.AddToTail( pPool );
}
// Copy the string in.
StringPool_t *pPool = m_StringPools[iPool];
Assert( pPool->m_SpaceUsed < 0xFFFF ); // This should never happen, because if we had a string > 64k, it
// would have been given its entire own pool.
unsigned short iStringOffset = pPool->m_SpaceUsed;
memcpy( &pPool->m_Data[pPool->m_SpaceUsed], pString, len );
pPool->m_SpaceUsed += len;
// didn't find, insert the string into the vector.
CStringPoolIndex index;
index.m_iPool = iPool;
index.m_iOffset = iStringOffset;
UtlSymId_t idx = m_Lookup.Insert( index );
return CUtlSymbol( idx );
}
//-----------------------------------------------------------------------------
// Look up the string associated with a particular symbol
//-----------------------------------------------------------------------------
const char* CUtlSymbolTable::String( CUtlSymbol id ) const
{
if (!id.IsValid())
return "";
Assert( m_Lookup.IsValidIndex((UtlSymId_t)id) );
return StringFromIndex( m_Lookup[id] );
}
//-----------------------------------------------------------------------------
// Remove all symbols in the table.
//-----------------------------------------------------------------------------
void CUtlSymbolTable::RemoveAll()
{
m_Lookup.Purge();
for ( int i=0; i < m_StringPools.Count(); i++ )
free( m_StringPools[i] );
m_StringPools.RemoveAll();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pFileName -
// Output : FileNameHandle_t
//-----------------------------------------------------------------------------
FileNameHandle_t CUtlFilenameSymbolTable::FindOrAddFileName( const char *pFileName )
{
if ( !pFileName )
{
return NULL;
}
// find first
FileNameHandle_t hFileName = FindFileName( pFileName );
if ( hFileName )
{
return hFileName;
}
// Fix slashes+dotslashes and make lower case first..
char fn[ MAX_PATH ];
Q_strncpy( fn, pFileName, sizeof( fn ) );
Q_RemoveDotSlashes( fn );
#ifdef _WIN32
strlwr( fn );
#endif
// Split the filename into constituent parts
char basepath[ MAX_PATH ];
Q_ExtractFilePath( fn, basepath, sizeof( basepath ) );
char filename[ MAX_PATH ];
Q_strncpy( filename, fn + Q_strlen( basepath ), sizeof( filename ) );
// not found, lock and look again
FileNameHandleInternal_t handle;
m_lock.LockForWrite();
handle.path = m_StringPool.FindStringHandle( basepath );
handle.file = m_StringPool.FindStringHandle( filename );
if ( handle.path && handle.file )
{
// found
m_lock.UnlockWrite();
return *( FileNameHandle_t * )( &handle );
}
// safely add it
handle.path = m_StringPool.ReferenceStringHandle( basepath );
handle.file = m_StringPool.ReferenceStringHandle( filename );
m_lock.UnlockWrite();
return *( FileNameHandle_t * )( &handle );
}
FileNameHandle_t CUtlFilenameSymbolTable::FindFileName( const char *pFileName )
{
if ( !pFileName )
{
return NULL;
}
// Fix slashes+dotslashes and make lower case first..
char fn[ MAX_PATH ];
Q_strncpy( fn, pFileName, sizeof( fn ) );
Q_RemoveDotSlashes( fn );
#ifdef _WIN32
strlwr( fn );
#endif
// Split the filename into constituent parts
char basepath[ MAX_PATH ];
Q_ExtractFilePath( fn, basepath, sizeof( basepath ) );
char filename[ MAX_PATH ];
Q_strncpy( filename, fn + Q_strlen( basepath ), sizeof( filename ) );
FileNameHandleInternal_t handle;
m_lock.LockForRead();
handle.path = m_StringPool.FindStringHandle(basepath);
handle.file = m_StringPool.FindStringHandle(filename);
m_lock.UnlockRead();
if ( handle.path == 0 || handle.file == 0 )
return NULL;
return *( FileNameHandle_t * )( &handle );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : handle -
// Output : const char
//-----------------------------------------------------------------------------
bool CUtlFilenameSymbolTable::String( const FileNameHandle_t& handle, char *buf, int buflen )
{
buf[ 0 ] = 0;
FileNameHandleInternal_t *internal = ( FileNameHandleInternal_t * )&handle;
if ( !internal )
{
return false;
}
m_lock.LockForRead();
const char *path = m_StringPool.HandleToString(internal->path);
const char *fn = m_StringPool.HandleToString(internal->file);
m_lock.UnlockRead();
if ( !path || !fn )
{
return false;
}
Q_strncpy( buf, path, buflen );
Q_strncat( buf, fn, buflen, COPY_ALL_CHARACTERS );
return true;
}
void CUtlFilenameSymbolTable::RemoveAll()
{
m_StringPool.FreeAll();
}
void CUtlFilenameSymbolTable::SpewStrings()
{
m_lock.LockForRead();
m_StringPool.SpewStrings();
m_lock.UnlockRead();
}