diff options
Diffstat (limited to 'unittests')
69 files changed, 10374 insertions, 0 deletions
diff --git a/unittests/autotestscripts/check_debug_dlls.pl b/unittests/autotestscripts/check_debug_dlls.pl new file mode 100644 index 0000000..7f1e16c --- /dev/null +++ b/unittests/autotestscripts/check_debug_dlls.pl @@ -0,0 +1,25 @@ +#!perl + +use File::Find; +use Win32::API; + +find(\&ProcessFile, "../../../game/bin/" ); + +sub ProcessFile + { + return if (/360/); + return unless( /\.dll$/i ); + my $LoadLibrary = Win32::API->new( "kernel32", "LoadLibrary","P","L" ); + my $GetProcAddress = Win32::API->new( "kernel32", "GetProcAddress","LP","L" ); + my $FreeLibrary = Win32::API->new( "kernel32", "FreeLibrary", "P", "V" ); + my $handle=$LoadLibrary->Call($_); + if ( $handle ) + { + my $proc = $GetProcAddress->Call($handle, "BuiltDebug\0"); + if ( $proc ) + { + print "Error $_ is built debug\n"; + } + $FreeLibrary->Call( $handle ); + } + } diff --git a/unittests/autotestscripts/check_dynamic_shader_compile.pl b/unittests/autotestscripts/check_dynamic_shader_compile.pl new file mode 100644 index 0000000..39e8e3a --- /dev/null +++ b/unittests/autotestscripts/check_dynamic_shader_compile.pl @@ -0,0 +1,15 @@ +#!perl + +open(DLL,"../../../game/bin/shaderapidx9.dll" ) || die "can't open shaderapi"; + +binmode DLL; +my $dllcode = do { local( $/ ) ; <DLL> } ; # slurp comparison output in +close DLL; + +if ( $dllcode =~ /dynamic_shader_compile_is_on/s ) + { + open(ERRORS,">errors.txt") || die "huh - can't write"; + print ERRORS "stdshader_dx9.dll was built with dynamic shader compile!\n"; + close ERRORS; + } + diff --git a/unittests/autotestscripts/datafiles/gwolf.tga b/unittests/autotestscripts/datafiles/gwolf.tga Binary files differnew file mode 100644 index 0000000..c813d8a --- /dev/null +++ b/unittests/autotestscripts/datafiles/gwolf.tga diff --git a/unittests/autotestscripts/filecompare_tests.cfg b/unittests/autotestscripts/filecompare_tests.cfg new file mode 100644 index 0000000..4f4cda6 --- /dev/null +++ b/unittests/autotestscripts/filecompare_tests.cfg @@ -0,0 +1,16 @@ +// this config file defines all unit tests which are run by running a program and comparing its output to reference output +// which is checked in in the directory src/unittests/autotestscripts/reference_output + +// the format of entries is TESTNAME,OUTPUTFILE,COMMAND-LINE-TO-EXECUTE +// if the OUTPUTFILE part is blank, it assumes the test is meant to compare the output of stdio + +file_size_monitor,,perl subtests/file_size_monitor.pl +testprocess,,..\testprocess\testprocess -message "testprocess autotest1" +vtex,gwolf.vtf,vtex -outdir . -nopause -nop4 -crcforce datafiles\gwolf.tga +rt_test,,..\rt_test\rt_test ..\rt_test\gwolf.tga test 1024 1024 +// mathlib_test,,..\mathlib_test\mathlib_test + + + + + diff --git a/unittests/autotestscripts/reference_output/file_size_monitor.txt b/unittests/autotestscripts/reference_output/file_size_monitor.txt new file mode 100644 index 0000000..1f3ef70 --- /dev/null +++ b/unittests/autotestscripts/reference_output/file_size_monitor.txt @@ -0,0 +1,6 @@ +Running file size monitor +PC shader size := 291934326 +PC Game Bin DLL size := 108442741 +360 shader size := 0 +360 Game Bin DLL size := 0 +tf texture size := 1396651036 diff --git a/unittests/autotestscripts/reference_output/mathlib_test.txt b/unittests/autotestscripts/reference_output/mathlib_test.txt new file mode 100644 index 0000000..e581561 --- /dev/null +++ b/unittests/autotestscripts/reference_output/mathlib_test.txt @@ -0,0 +1,3 @@ +right spherical triangle projected percentage=0.1250 +small spherical triangle projected percentage=0.00156 +sum of areas of cubemap cells = 1.00 diff --git a/unittests/autotestscripts/reference_output/rt_test.txt b/unittests/autotestscripts/reference_output/rt_test.txt new file mode 100644 index 0000000..1cee230 --- /dev/null +++ b/unittests/autotestscripts/reference_output/rt_test.txt @@ -0,0 +1,6 @@ +reading src texture +n triangles 1567238 +Creating kd-tree +kd built time := 79 +Rendering +pixels traced and lit per second := 1559694.998968 diff --git a/unittests/autotestscripts/reference_output/testprocess.txt b/unittests/autotestscripts/reference_output/testprocess.txt new file mode 100644 index 0000000..63b55cd --- /dev/null +++ b/unittests/autotestscripts/reference_output/testprocess.txt @@ -0,0 +1 @@ +testprocess autotest1
\ No newline at end of file diff --git a/unittests/autotestscripts/reference_output/vtex.vtf b/unittests/autotestscripts/reference_output/vtex.vtf Binary files differnew file mode 100644 index 0000000..f36a030 --- /dev/null +++ b/unittests/autotestscripts/reference_output/vtex.vtf diff --git a/unittests/autotestscripts/run_file_comparison_tests.pl b/unittests/autotestscripts/run_file_comparison_tests.pl new file mode 100644 index 0000000..7408a56 --- /dev/null +++ b/unittests/autotestscripts/run_file_comparison_tests.pl @@ -0,0 +1,181 @@ +#!perl + +# read stdio_test_list.cfg and perform all tests + +$create_refs=0; +$subset_string=shift; + +@months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); +@weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun); +($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime(); +$year = 1900 + $yearOffset; +$dstamp = "$weekDays[$dayOfWeek] $months[$month] $dayOfMonth $year".sprintf(" %02d:%02d:%02d", $hour,$minute,$second); +$changelist_counter=`p4 counter main_changelist`; # grab value of p4 counter + +$dstamp.=" $changelist_counter"; +$dstamp=~ s/[\n\r]//g; + +$computername=$ENV{'COMPUTERNAME'}; + + +# first, set our priority to high and affinity to 1 to try to get more repeatable benchmark results +#my $pid = $$; + +#my $cmd="datafiles\\process.exe -p $pid High"; +#print STDERR `$cmd`; +#$cmd="datafiles\\process.exe -a $pid 01"; +#print STDERR `$cmd`; + +if ( open(CFGFILE, "filecompare_tests.cfg") ) + { + while(<CFGFILE>) + { + s/[\n\r]//g; + s@//.*$@@; # kill comments + if (/^([^,]*),([^,]*),(.*$)/) + { + $testname=$1; + $testfile=$2; + $testcommand=$3; + + next if ( length($subset_string) && ( ! ( $testname=~/$subset_string/i) ) ); + + $ext=".txt"; + if ( length($testfile ) ) + { + $ext=""; + $ext = $1 if ( $testfile=~/(\..*)$/ ); # copy extension + unlink $testfile if ( -e $testfile); # kill it if it exists + } + + print STDOUT "running $testname : $testcommand ($testfile)\n"; + # suck the reference output in. use binary mode unless stdio + $refname="reference_output/$testname$ext"; + + # run the test + my $stime=time; + $output=`$testcommand`; + $stime=time-$stime; + + if ( open(REF,$refname)) + { + if ( length($testfile )) + { + binmode REF; + } + $ref_output= do { local( $/ ) ; <REF> } ; # slurp comparison output in + close REF; + + if ( length( $testfile ) ) + { + print STDERR $output; + # file case + if ( open(TESTFILE, $testfile )) + { + binmode TESTFILE; + $new_output= do { local( $/ ) ; <TESTFILE> } ; # slurp comparison output in + close TESTFILE; + if ($new_output ne $ref_output ) + { + $errout.="ERROR: test $testname ($testcommand) : test produced file $testfile (length=". + length($new_output).") but it doesn't match the reference (length=".length($ref_output).")\n"; + } + else + { + &UpdateMetrics( $testname, $output, $stime ); + } + } + else + { + $errout.="ERROR: test $testname ($testcommand) : test was supposed to create $testfile, but didn't.\n"; + } + } + else + { + # strip metrics (like timing) for comparison + my $massaged_ref = $ref_output; + my $massaged_output = $output; + $massaged_ref =~ s/:=\s*[0-9\.]+//g; + $massaged_output =~ s/:=\s*[0-9\.]+//g; + if ($massaged_output ne $massaged_ref ) + { +# print STDERR "o=$massaged_output r=$massaged_ref\n"; + $errout.="ERROR: test $testname ($testcommand) : output does not match reference output.\n"; + } + else + { + &UpdateMetrics( $testname, $output, $stime ); + } + } + } + else + { + $errout.="ERROR: Can't open reference $refname for $testname\n"; + if ($create_refs) + { + if ( length($testfile ) ) + { + if ( -e $testfile ) + { + $oname=$refname; + $oname=~s@/@\\@g; + print STDERR "copy $testfile $oname"; + print STDERR `copy $testfile $oname`; + print STDERR `p4 add $oname`; + } + } + else + { + if ( open(REFOUT,">$refname") ) + { + print REFOUT $output; + } + close REFOUT; + print STDERR `p4 add $refname`; + } + } + } + } + } + } +else + { + $errout.="Can't open stdio_test_list.cfg\n"; + } + +if (length($errout)) +{ + print STDERR "There were errors: $errout"; + open(ERRORS,">errors.txt") || die "huh - can't write"; + print ERRORS $errout; + close ERRORS; +} + + + + +sub UpdateMetrics + { + return unless length($computername); + local( $tname, $output, $runtime) = @_; + $output .= "\ntest runtime := $runtime\n"; + foreach $_ ( split(/\n/,$output)) + { + if (/^(.+):=(.*$)/) + { + my $varname=$1; + my $etime=$2; + $varname=~s@^\s*@@g; + $varname=~s@\s*$@@g; + mkdir "\\\\fileserver\\user\\perf\\$computername"; + mkdir "\\\\fileserver\\user\\perf\\$computername\\$tname"; + if ( open(COUT,">>\\\\fileserver\\user\\perf\\$computername\\$tname\\$varname.csv") ) + { + print COUT "\"$dstamp\",$etime\n"; + close COUT; + } + + } + } + + } diff --git a/unittests/autotestscripts/subtests/file_size_monitor.pl b/unittests/autotestscripts/subtests/file_size_monitor.pl new file mode 100644 index 0000000..fa834d3 --- /dev/null +++ b/unittests/autotestscripts/subtests/file_size_monitor.pl @@ -0,0 +1,40 @@ +#!perl + +use File::Find; + +# customize here +print "Running file size monitor\n"; + +LogDirectorySize("PC shader size", "../../../game/hl2/shaders","\.vcs","\.360\.vcs"); +LogDirectorySize("PC Game Bin DLL size", "../../../game/bin/","\.dll","_360\.dll"); +LogDirectorySize("360 shader size", "../../../game/hl2/shaders","\.360\.vcs"); +LogDirectorySize("360 Game Bin DLL size", "../../../game/bin/","_360\.dll"); +LogDirectorySize("tf texture size","../../../game/tf/materials/","\.vtf"); + + + + + + + +sub LogDirectorySize + { + my ($label, $basedir, $filepattern, $excludepattern ) = @_; + undef @FileList; + find(\&ProcessFile, $basedir); + my $total_size = 0; + foreach $_ (@FileList) + { + next if ( length($excludepattern) && ( /$excludepattern/i ) ); + if (/$filepattern/i) + { + $total_size += (-s $_ ); + } + } + print "$label := $total_size\n"; + } + +sub ProcessFile + { + push @FileList, $File::Find::name; + } diff --git a/unittests/autotestscripts/test_error_reporting.pl b/unittests/autotestscripts/test_error_reporting.pl new file mode 100644 index 0000000..f705f9c --- /dev/null +++ b/unittests/autotestscripts/test_error_reporting.pl @@ -0,0 +1,13 @@ +#! perl +$errfname="//fileserver/user/cgreen/force_an_error.txt"; + +if (-e $errfname ) + { + unlink $errfname; + open(ERROUT,">errors.txt") || die "huh - can't write"; + { + print ERROUT "This is not an error - its just a test of the error script system.\n"; + close ERROUT; + } + + } diff --git a/unittests/autotestscripts/test_shader_crcs.pl b/unittests/autotestscripts/test_shader_crcs.pl new file mode 100644 index 0000000..517aa02 --- /dev/null +++ b/unittests/autotestscripts/test_shader_crcs.pl @@ -0,0 +1,36 @@ +use Cwd; + +my $dir = getcwd; + +chdir "../../materialsystem/stdshaders"; + +@output = `perl ..\\..\\devtools\\bin\\checkshaderchecksums.pl stdshader_dx9_20b.txt`; +foreach $_ (@output) +{ + $output.=$_ unless(/appchooser360/i); +} + +@output = `perl ..\\..\\devtools\\bin\\checkshaderchecksums.pl stdshader_dx9_30.txt`; +foreach $_ (@output) +{ + $output.=$_ unless(/appchooser360/i); +} + +my $errors; + +foreach $_ (@output ) +{ + $errors.=$_ unless (/appchooser360movie/); +} + +chdir $dir; + +print $errors; + +if( length( $errors ) > 0 ) +{ + print "writing errors.txt\n"; + open FP, ">errors.txt"; + print FP "$errors"; + close FP; +} diff --git a/unittests/autotestscripts/verify_compiled_sheet_files_match_src.pl b/unittests/autotestscripts/verify_compiled_sheet_files_match_src.pl new file mode 100644 index 0000000..bce70ba --- /dev/null +++ b/unittests/autotestscripts/verify_compiled_sheet_files_match_src.pl @@ -0,0 +1,69 @@ +#! perl + + +use File::Find; +use Cwd; +use File::Basename; + +# find(\&Visitfile,"../../../content/tf"); + +foreach $_ ( @sheetfiles ) + { + $dest_sheet_name=$_; + $dest_sheet_name =~ s/\.mks/.sht/i; + $dest_sheet_name =~ s@/content/([^/]+)/materialsrc/@/game/\1/materials/@gi; + print "**Checking $_\n"; + if (! -e $dest_sheet_name ) + { + push @errors,"sheet $_ exists but not $dest_sheet_name"; + } + else + { + # buid it and make sure they match + $cmd="cd ".dirname($_)." & mksheet ".basename($_)." test.sht"; + $cmd=~tr/\//\\/; + $cmdout=`$cmd`; + if ( open(NEWFILE, dirname($_)."/test.sht") ) + { + binmode NEWFILE; + open(OLDFILE, $dest_sheet_name ) || die "strange error - cant find $dest_sheet_name"; + binmode OLDFILE; + { + local( $/, *FH ) ; + $old_data=<OLDFILE>; + $new_data=<NEWFILE>; + if ( $new_data ne $old_data ) + { + push @errors,"Sheet source file $_ does not compile to the same output as the checked in $dest_sheet_name"; + } + close OLDFILE; + close NEWFILE; + unlink dirname($_)."/test.sht"; + } + } + else + { + push @errors, "Couldn't compile sheet $_ by running $cmd : \n$cmdout"; + } + } + } + +$errout=join("\n", @errors); +print $errout; +if (length($errout)) + { + open(ERRFILE,">errors.txt") || die "can't write errors.txt"; + print ERRFILE $errout; + close ERRFILE; + } + + +sub Visitfile + { + local($_)= $File::Find::name; + s@\\@\/@g; + if (m@content/(\S+)/.*\.mks$@i) + { + push @sheetfiles, $_; + } + } diff --git a/unittests/autotestscripts_graphics/keyimages/abovewater.tga b/unittests/autotestscripts_graphics/keyimages/abovewater.tga Binary files differnew file mode 100644 index 0000000..9700ce3 --- /dev/null +++ b/unittests/autotestscripts_graphics/keyimages/abovewater.tga diff --git a/unittests/autotestscripts_graphics/keyimages/belowwater.tga b/unittests/autotestscripts_graphics/keyimages/belowwater.tga Binary files differnew file mode 100644 index 0000000..5641376 --- /dev/null +++ b/unittests/autotestscripts_graphics/keyimages/belowwater.tga diff --git a/unittests/autotestscripts_graphics/keyimages/mat_fullbright_1.tga b/unittests/autotestscripts_graphics/keyimages/mat_fullbright_1.tga Binary files differnew file mode 100644 index 0000000..ce60746 --- /dev/null +++ b/unittests/autotestscripts_graphics/keyimages/mat_fullbright_1.tga diff --git a/unittests/autotestscripts_graphics/keyimages/mat_fullbright_2.tga b/unittests/autotestscripts_graphics/keyimages/mat_fullbright_2.tga Binary files differnew file mode 100644 index 0000000..ef516c5 --- /dev/null +++ b/unittests/autotestscripts_graphics/keyimages/mat_fullbright_2.tga diff --git a/unittests/autotestscripts_graphics/keyimages/mat_luxels_1.tga b/unittests/autotestscripts_graphics/keyimages/mat_luxels_1.tga Binary files differnew file mode 100644 index 0000000..80e5bd1 --- /dev/null +++ b/unittests/autotestscripts_graphics/keyimages/mat_luxels_1.tga diff --git a/unittests/autotestscripts_graphics/keyimages/mat_showmiplevels_1.tga b/unittests/autotestscripts_graphics/keyimages/mat_showmiplevels_1.tga Binary files differnew file mode 100644 index 0000000..ac2b726 --- /dev/null +++ b/unittests/autotestscripts_graphics/keyimages/mat_showmiplevels_1.tga diff --git a/unittests/autotestscripts_graphics/keyimages/mat_showmiplevels_2.tga b/unittests/autotestscripts_graphics/keyimages/mat_showmiplevels_2.tga Binary files differnew file mode 100644 index 0000000..04af7cb --- /dev/null +++ b/unittests/autotestscripts_graphics/keyimages/mat_showmiplevels_2.tga diff --git a/unittests/autotestscripts_graphics/keyimages/mat_wireframe_1.tga b/unittests/autotestscripts_graphics/keyimages/mat_wireframe_1.tga Binary files differnew file mode 100644 index 0000000..862b241 --- /dev/null +++ b/unittests/autotestscripts_graphics/keyimages/mat_wireframe_1.tga diff --git a/unittests/autotestscripts_graphics/rendering_regression_test.pl b/unittests/autotestscripts_graphics/rendering_regression_test.pl new file mode 100644 index 0000000..a29bd57 --- /dev/null +++ b/unittests/autotestscripts_graphics/rendering_regression_test.pl @@ -0,0 +1,36 @@ +use Cwd; + +my $dir = getcwd; + +chdir "../../../game"; + +if( 1 ) +{ + system "rd /s /q ep2\\screenshots"; + system "mkdir ep2\\screenshots"; + @output = `hl2.exe -allowdebug -autoconfig -console -toconsole -dev -sw -width 1024 -game ep2 -testscript rendering_regression_test.vtest`; +} + +$keydir = "\\\\fileserver\\user\\rendering_regression_test"; + +open TESTSCRIPT, "<ep2/testscripts/rendering_regression_test.vtest" || die; +foreach $line (<TESTSCRIPT>) +{ + $line =~ s,//.*,,g; # remove comments + if( $line =~ m/\s*screenshot\s+(.*)$/i ) + { + push @screenshots, $1; + } +} +close TESTSCRIPT; + +foreach $screenshot (@screenshots) +{ + $cmd = "tgamse $keydir\\$screenshot.tga ep2\\screenshots\\$screenshot.tga 0"; + $output = `$cmd`; + if( $output =~ m/FAIL/ ) + { + $cmd = "tgadiff $keydir\\$screenshot.tga ep2\\screenshots\\$screenshot.tga ep2\\screenshots\\$screenshot" . "_diff.tga"; + system $cmd; + } +} diff --git a/unittests/avitest/avitest.cpp b/unittests/avitest/avitest.cpp new file mode 100644 index 0000000..0002930 --- /dev/null +++ b/unittests/avitest/avitest.cpp @@ -0,0 +1,233 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Material editor +//============================================================================= +#include <windows.h> +#include "appframework/vguimatsysapp.h" +#include "filesystem.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/imesh.h" +#include "vgui/ISurface.h" +#include "vgui/IVGui.h" +#include "vgui_controls/controls.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "vgui/ILocalize.h" +#include "vgui/IScheme.h" +#include "avi/iavi.h" +#include "avi/ibik.h" +#include "tier3/tier3.h" + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CAVITestApp : public CVguiMatSysApp +{ + typedef CVguiMatSysApp BaseClass; + +public: + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit( ); + virtual int Main(); + virtual void PostShutdown( ); + virtual const char *GetAppName() { return "AVITest"; } + virtual bool AppUsesReadPixels() { return true; } + +private: + // Draws a quad + void DrawStuff( AVIMaterial_t hMaterial ); + IMaterial *m_pMaterial; + float m_flStartTime; +}; + +DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT( CAVITestApp ); + + +//----------------------------------------------------------------------------- +// Create all singleton systems +//----------------------------------------------------------------------------- +bool CAVITestApp::Create() +{ + if ( !BaseClass::Create() ) + return false; + + AppSystemInfo_t appSystems[] = + { + { "valve_avi.dll", AVI_INTERFACE_VERSION }, + { "valve_avi.dll", BIK_INTERFACE_VERSION }, + { "", "" } // Required to terminate the list + }; + + return AddSystems( appSystems ); +} + + +//----------------------------------------------------------------------------- +// PreInit, PostShutdown +//----------------------------------------------------------------------------- +bool CAVITestApp::PreInit( ) +{ + if ( !BaseClass::PreInit() ) + return false; + + if ( !g_pFullFileSystem || !g_pMaterialSystem || !g_pVGui || !g_pVGuiSurface || !g_pAVI || !g_pBIK ) + return false; + + g_pAVI->SetMainWindow( GetAppWindow() ); + return true; +} + +void CAVITestApp::PostShutdown( ) +{ + g_pAVI->SetMainWindow( NULL ); + BaseClass::PostShutdown(); +} + + +//----------------------------------------------------------------------------- +// Draws a quad +//----------------------------------------------------------------------------- +void CAVITestApp::DrawStuff( AVIMaterial_t hMaterial ) +{ + int iViewableWidth = GetWindowWidth(); + int iViewableHeight = GetWindowHeight(); + + g_pAVI->SetTime( hMaterial, Sys_FloatTime() - m_flStartTime ); + + float flMaxU, flMaxV; + g_pAVI->GetTexCoordRange( hMaterial, &flMaxU, &flMaxV ); + IMaterial *pMaterial = g_pAVI->GetMaterial( hMaterial ); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->LoadIdentity(); + pRenderContext->Ortho( 0, 0, iViewableWidth, iViewableHeight, 0, 1 ); + + pRenderContext->Bind( pMaterial ); + IMesh *pMesh = pRenderContext->GetDynamicMesh(); + CMeshBuilder meshBuilder; + + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + // Draw a polygon the size of the panel + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( -0.5, iViewableHeight + 0.5, 0 ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( -0.5, 0.5, 0 ); + meshBuilder.TexCoord2f( 0, 0, flMaxV ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( iViewableWidth - 0.5, 0.5, 0 ); + meshBuilder.TexCoord2f( 0, flMaxU, flMaxV ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.Position3f( iViewableWidth - 0.5, iViewableHeight + 0.5, 0 ); + meshBuilder.TexCoord2f( 0, flMaxU, 0 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// main application +//----------------------------------------------------------------------------- +int CAVITestApp::Main() +{ + if (!SetVideoMode()) + return 0; + + // load scheme + if (!vgui::scheme()->LoadSchemeFromFile("resource/BoxRocket.res", "ElementViewer" )) + { + Assert( 0 ); + } + + // load the boxrocket localization file + g_pVGuiLocalize->AddFile( "resource/boxrocket_%language%.txt" ); + + // load the base localization file + g_pVGuiLocalize->AddFile( "Resource/valve_%language%.txt" ); + g_pFullFileSystem->AddSearchPath("platform", "PLATFORM"); + g_pVGuiLocalize->AddFile( "Resource/vgui_%language%.txt"); + + // start vgui + g_pVGui->Start(); + + // add our main window +// vgui::Panel *mainPanel = CreateElementViewerPanel(); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + AVIParams_t params; + Q_strcpy( params.m_pFileName, "c:\\temp\\out.avi" ); + Q_strcpy( params.m_pPathID, "MOD" ); + pRenderContext->GetWindowSize( params.m_nWidth, params.m_nHeight ); + params.m_nFrameRate = 24; + params.m_nFrameScale = 1; + params.m_nNumChannels = 0; + + AVIHandle_t h = g_pAVI->StartAVI( params ); + AVIMaterial_t hAVIMaterial = g_pAVI->CreateAVIMaterial( "avitest", "c:\\temp\\test.avi", "MOD" ); + + // run app frame loop + vgui::VPANEL root = g_pVGuiSurface->GetEmbeddedPanel(); + g_pVGuiSurface->Invalidate( root ); + + int imagesize = params.m_nWidth * params.m_nHeight; + BGR888_t *hp = new BGR888_t[ imagesize ]; + + m_flStartTime = Sys_FloatTime(); + m_pMaterial = g_pMaterialSystem->FindMaterial( "debug/debugempty", "app" ); + while ( g_pVGui->IsRunning() ) + { + AppPumpMessages(); + + pRenderContext->ClearColor4ub( 76, 88, 68, 255 ); + pRenderContext->ClearBuffers( true, true ); + + DrawStuff( hAVIMaterial ); + + g_pVGui->RunFrame(); + + g_pVGuiSurface->PaintTraverse( root ); + + // Get Bits from material system + Rect_t rect; + rect.x = rect.y = 0; + rect.width = params.m_nWidth; + rect.height = params.m_nHeight; + + pRenderContext->ReadPixelsAndStretch( &rect, &rect, (unsigned char*)hp, + IMAGE_FORMAT_BGR888, rect.width * sizeof( BGR888_t ) ); + g_pAVI->AppendMovieFrame( h, hp ); + + g_pMaterialSystem->SwapBuffers(); + } + + delete[] hp; + g_pAVI->FinishAVI( h ); + g_pAVI->DestroyAVIMaterial( hAVIMaterial ); + +// delete mainPanel; + + return 1; +} + + + diff --git a/unittests/avitest/avitest.vpc b/unittests/avitest/avitest.vpc new file mode 100644 index 0000000..a4708eb --- /dev/null +++ b/unittests/avitest/avitest.vpc @@ -0,0 +1,27 @@ +//----------------------------------------------------------------------------- +// AVITEST.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_win_win32_base.vpc" + +$Project "Avitest" +{ + $Folder "Source Files" + { + $File "avitest.cpp" + $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp" + } + + $Folder "Link Libraries" + { + $DynamicFile "$SRCDIR\lib\public\appframework.lib" + $DynamicFile "$SRCDIR\lib\public\tier2.lib" + $DynamicFile "$SRCDIR\lib\public\tier3.lib" + $DynamicFile "$SRCDIR\lib\public\vgui_controls.lib" + } +} diff --git a/unittests/dmxtest/dmxtest.cpp b/unittests/dmxtest/dmxtest.cpp new file mode 100644 index 0000000..55261d6 --- /dev/null +++ b/unittests/dmxtest/dmxtest.cpp @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for DMX testing +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "filesystem.h" +#include "datamodel/idatamodel.h" +#include "datamodel/dmelementfactoryhelper.h" +#include "tier3/tier3dm.h" + + +//----------------------------------------------------------------------------- +// Used to connect/disconnect the DLL +//----------------------------------------------------------------------------- +class CDmxTestAppSystem : public CTier3DmAppSystem< IAppSystem > +{ + typedef CTier3DmAppSystem< IAppSystem > BaseClass; + +public: + CDmxTestAppSystem() + { + } + + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + + if ( !g_pFullFileSystem || !g_pDataModel || !g_pDmElementFramework ) + return false; + + return true; + } + + virtual InitReturnVal_t Init() + { + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); + return BaseClass::Init(); + } +}; + +USE_UNITTEST_APPSYSTEM( CDmxTestAppSystem ) diff --git a/unittests/dmxtest/dmxtest.vpc b/unittests/dmxtest/dmxtest.vpc new file mode 100644 index 0000000..6f5069f --- /dev/null +++ b/unittests/dmxtest/dmxtest.vpc @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------------- +// DMXTEST.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin\unittests" + +$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE,$SRCDIR\game\shared,$SRCDIR\utils\common" + $PreprocessorDefinitions "$BASE;DMXTEST_EXPORTS" + } +} + +$Project "Dmxtest" +{ + $Folder "Source Files" + { + $File "$SRCDIR\movieobjects\dmx_to_vcd.cpp" + $File "dmxtest.cpp" + $File "dmxtest_dmeloglayers.cpp" + $File "dmxtest_vcdtodme.cpp" + $File "dmxtestarray.cpp" + $File "dmxtestdmelog.cpp" + $File "dmxtestloader.cpp" + $File "dmxtestnotify.cpp" + $File "dmxtestserialization.cpp" + $File "dmxtestundoredo.cpp" + $File "$SRCDIR\public\interpolatortypes.cpp" + $File "$SRCDIR\public\movieobjects\movieobjects.cpp" + } + + $Folder "Header Files" + { + $File "$SRCDIR\public\movieobjects\dmx_to_vcd.h" + $File "$SRCDIR\public\interpolatortypes.h" + } + + $Folder "Link Libraries" + { + $Lib datamodel + $Lib choreoobjects + $Lib dmserializers + $Lib mathlib + $Lib dmxloader + $Lib movieobjects + $Lib tier2 + $Lib tier3 + $Lib unitlib + } +} diff --git a/unittests/dmxtest/dmxtest_dmeloglayers.cpp b/unittests/dmxtest/dmxtest_dmeloglayers.cpp new file mode 100644 index 0000000..77626b1 --- /dev/null +++ b/unittests/dmxtest/dmxtest_dmeloglayers.cpp @@ -0,0 +1,908 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "datamodel/dmelement.h" +#include "movieobjects/movieobjects.h" +#include "datamodel/idatamodel.h" + +#include "movieobjects/dmechannel.h" +#include "movieobjects/dmelog.h" + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define NUM_CHANNELS 1 +#define NUM_LOG_ENTRIES 10 + +enum +{ + SPEW_DIFFS = (1<<0), + SPEW_VALUES= (1<<1), + SPEW_KEYS= (1<<2), +}; + +static void ValidateDataSets( int spew, char const *testname, CUtlVector< CUtlVector< float > >& values, CUtlVector< CUtlVector< float > >& valuesbaked ) +{ + int i, j; + // Compare baked, unbaked values + Assert( values.Count() == valuesbaked.Count() ); + int c = values.Count(); + bool differs = false; + bool spewvalues = ( spew & SPEW_VALUES ) ? true : false; + + float tol = 0.0001f; + + for ( i = 0; i < c; ++i ) + { + CUtlVector< float >& v = values[ i ]; + CUtlVector< float >& vb = valuesbaked[ i ]; + + Assert( v.Count() == vb.Count() ); + + // Now get the values of the samples in the log + for ( j = 0; j < v.Count(); ++j ) + { + Assert( vb.IsValidIndex( j ) ); + if ( !vb.IsValidIndex( j ) ) + continue; + + float v1 = v[ j ]; + float v2 = vb[ j ]; + if ( fabs( v1 - v2 ) > tol ) + { + differs = true; + } + + if ( spewvalues ) + { + Msg( "%d %f %f\n", j, v[ j ], vb[ j ] ); + } + } + } + + Msg( " %s\n", differs ? "FAILED" : "OK" ); + + if ( !(spew & SPEW_DIFFS ) ) + return; + + for ( i = 0; i < c; ++i ) + { + CUtlVector< float >& v = values[ i ]; + CUtlVector< float >& vb = valuesbaked[ i ]; + + Assert( v.Count() == vb.Count() ); + + // Now get the values of the samples in the log + for ( j = 0; j < v.Count(); ++j ) + { + Assert( vb.IsValidIndex( j ) ); + if ( !vb.IsValidIndex( j ) ) + continue; + + if ( v[ j ] == vb[ j ] ) + { + if ( differs ) + { + Msg( "%d found %f to equal %f\n", j, v[ j ], vb[ j ] ); + } + continue; + } + + Msg( "%d expected %f to equal %f\n", j, v[ j ], vb[ j ] ); + } + } + + if ( differs ) + { + Msg( "End Test '%s'\n---------------\n", testname ); + } +} + +static void CreateChannels( int num, CUtlVector< CDmeChannel * >& channels, DmFileId_t fileid ) +{ + CDisableUndoScopeGuard guard; + + for ( int i = 0; i < num; ++i ) + { + CDmeChannel *channel = NULL; + + channel = CreateElement< CDmeChannel >( "channel1", fileid ); + channels.AddToTail( channel ); + channel->CreateLog( AT_FLOAT ); // only care about float logs for now + channel->SetMode( CM_PLAY );// Make sure it's in playback mode + } +} + +struct TestLayer_t +{ + enum + { + TYPE_SIMPLESLOPE = 0, // value == time + TYPE_SINE, // sinusoidal + TYPE_CONSTANT, + }; + + TestLayer_t() : + startTime( 0 ), + endTime( 0 ), + timeStep( 0 ), + usecurvetype( false ), + curvetype( CURVE_DEFAULT ), + type( TYPE_SIMPLESLOPE ), + constantvalue( 0.0f ) + { + } + + float ValueForTime( DmeTime_t time ) const + { + float t = (float)time.GetSeconds(); + switch ( type ) + { + default: + case TYPE_SIMPLESLOPE: + return t; + case TYPE_SINE: + return constantvalue * ( 1.0f + sin( ( t * 0.002f ) * 2 * M_PI ) ) * 0.5f; + case TYPE_CONSTANT: + return constantvalue; + } + + return t; + } + + int type; + DmeTime_t startTime; + DmeTime_t endTime; + DmeTime_t timeStep; + + bool usecurvetype; + int curvetype; + + float constantvalue; +}; + +struct TestParams_t +{ + TestParams_t() : + testundo( false ), + usecurves( false ), + purgevalues( true ), + testabort( false ), + spew( 0 ), + spewnontopmostlayers( false ), + defaultcurve( CURVE_DEFAULT ), + mintime( DmeTime_t( 0 ) ), + maxtime( DmeTime_t( 100 ) ) + { + } + int spew; + bool usecurves; + bool purgevalues; + bool testundo; + bool testabort; + bool spewnontopmostlayers; + int defaultcurve; + DmeTime_t mintime; + DmeTime_t maxtime; + CUtlVector< TestLayer_t > layers; + + void Reset() + { + purgevalues = true; + usecurves = false; + testundo = false; + testabort = false; + spewnontopmostlayers = false; + spew = 0; + mintime = DmeTime_t( 0 ); + maxtime = DmeTime_t( 100 ); + defaultcurve = CURVE_DEFAULT; + layers.RemoveAll(); + } + + void AddLayer( DmeTime_t start, DmeTime_t end, DmeTime_t step, int curvetype, int valuetype, float constantvalue = 0.0f ) + { + TestLayer_t tl; + tl.startTime = start; + tl.endTime = end; + tl.timeStep = step; + tl.curvetype = curvetype; + tl.type = valuetype; + tl.constantvalue = constantvalue; + + layers.AddToTail( tl ); + } +}; + +static void RunLayerTest( char const *testname, CUtlVector< CDmeChannel * >& channels, const TestParams_t& params ) +{ + if ( params.layers.Count() == 0 ) + { + Assert( 0 ); + return; + } + + Msg( "Test '%s'...\n", testname ); + + g_pDataModel->StartUndo( testname, testname ); + + int i; + int c = channels.Count(); + + { + CDisableUndoScopeGuard guard; + + for ( i = 0; i < NUM_CHANNELS; ++i ) + { + CDmeChannel *channel = channels[ i ]; + CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() ); + Assert( pLog ); + pLog->ClearKeys(); // reset it + + CDmeCurveInfo *pCurveInfo = NULL; + if ( params.usecurves ) + { + pCurveInfo = pLog->GetOrCreateCurveInfo(); + pCurveInfo->SetDefaultCurveType( params.defaultcurve ); + pCurveInfo->SetMinValue( 0.0f ); + pCurveInfo->SetMaxValue( 1000.0f ); + } + else + { + if ( pLog->GetCurveInfo() ) + { + g_pDataModel->DestroyElement( pLog->GetCurveInfo()->GetHandle() ); + } + pLog->SetCurveInfo( NULL ); + } + + const TestLayer_t& tl = params.layers[ 0 ]; + // Now add entries + DmeTime_t logStep = tl.timeStep; + DmeTime_t logStart = tl.startTime; + + for ( DmeTime_t t = logStart; t <= tl.endTime + logStep - DmeTime_t( 1 ); t += logStep ) + { + DmeTime_t useTime = t; + if ( useTime > tl.endTime ) + { + useTime = tl.endTime; + } + float value = tl.ValueForTime( useTime ); + if ( tl.usecurvetype ) + { + pLog->SetKey( useTime, value, tl.curvetype ); + } + else + { + pLog->SetKey( useTime, value ); + } + } + } + } + + for ( int layer = 1; layer < params.layers.Count(); ++layer ) + { + const TestLayer_t& tl = params.layers[ layer ]; + + // Test creating a layer and collapsing it back down + g_pChannelRecordingMgr->StartLayerRecording( "layer operations" ); + for ( i = 0; i < c; ++i ) + { + g_pChannelRecordingMgr->AddChannelToRecordingLayer( channels[ i ] ); // calls log->CreateNewLayer() + } + + // Now add values to channel logs + for ( i = 0; i < c; ++i ) + { + CDmeChannel *channel = channels[ i ]; + CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() ); + Assert( pLog ); + + // Now add entries + DmeTime_t logStep = tl.timeStep; + DmeTime_t logStart = tl.startTime; + + for ( DmeTime_t t = logStart; t <= tl.endTime + logStep - DmeTime_t( 1 ); t += logStep ) + { + DmeTime_t useTime = t; + if ( useTime > tl.endTime ) + { + useTime = tl.endTime; + } + float value = tl.ValueForTime( useTime ); + if ( tl.usecurvetype ) + { + pLog->SetKey( useTime, value, tl.curvetype ); + } + else + { + pLog->SetKey( useTime, value ); + } + } + } + + g_pChannelRecordingMgr->FinishLayerRecording( 0.0f, false ); // don't flatten layers here, we'll do it manually + } + + // Now sample values + CUtlVector< CUtlVector< float > > values; + CUtlVector< CUtlVector< float > > valuesbaked; + + for ( i = 0; i < c; ++i ) + { + CDmeChannel *channel = channels[ i ]; + CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() ); + Assert( pLog ); + + int idx = values.AddToTail(); + + CUtlVector< float >& v = values[ idx ]; + + // Now get the values of the samples in the log + for ( DmeTime_t j = params.mintime; j <= params.maxtime; j += DmeTime_t( 1 ) ) + { + float fval = pLog->GetValue( j ); + v.AddToTail( fval ); + } + } + + if ( params.spewnontopmostlayers ) + { + for ( i = 0; i < c; ++i ) + { + CDmeChannel *channel = channels[ i ]; + CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() ); + Assert( pLog ); + + // Now get the values of the samples in the log + for ( DmeTime_t j = params.mintime; j <= params.maxtime; j += DmeTime_t( 1 ) ) + { + float topValue = pLog->GetValue( j ); + float underlyingValue = pLog->GetValueSkippingTopmostLayer( j ); + + Msg( "t(%d) top [%f] rest [%f]\n", + j.GetTenthsOfMS(), topValue, underlyingValue ); + } + } + } + + // Now test creating a layer and "undo/redo" of the layer + if ( params.testundo ) + { + g_pDataModel->FinishUndo(); + g_pDataModel->Undo(); + g_pDataModel->Redo(); + g_pDataModel->StartUndo( testname, testname ); + } + + { + CUndoScopeGuard guard( "Bake Layers" ); + // Now bake down and resample values + for ( i = 0; i < c; ++i ) + { + CDmeChannel *channel = channels[ i ]; + CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() ); + Assert( pLog ); + + pLog->FlattenLayers( 0.0f, params.spew & SPEW_DIFFS ); + + int idx = valuesbaked.AddToTail(); + + CUtlVector< float >& v = valuesbaked[ idx ]; + + // Now get the values of the samples in the log + for ( DmeTime_t j = params.mintime; j <= params.maxtime; j += DmeTime_t( 1 ) ) + { + float fval = pLog->GetValue( j ); + v.AddToTail( fval ); + } + } + } + + ValidateDataSets( params.spew, testname, values, valuesbaked ); + + // Now test creating a layer and "undo/redo" of the layer + if ( params.testundo ) + { + g_pDataModel->FinishUndo(); + g_pDataModel->Undo(); + g_pDataModel->Redo(); + g_pDataModel->StartUndo( testname, testname ); + } + + if ( params.testabort ) + { + g_pDataModel->AbortUndoableOperation(); + } + else + { + g_pDataModel->FinishUndo(); + } +} + +static void RunTimeSelectionTest( char const *testname, CUtlVector< CDmeChannel * >& channels, + const TestParams_t& params, DmeTime_t tHeadPosition, DmeLog_TimeSelection_t& ts, float value ) +{ + if ( params.layers.Count() == 0 ) + { + Assert( 0 ); + return; + } + + Msg( "Test '%s'...\n", testname ); + + int i, j; + int c = channels.Count(); + + if ( params.purgevalues ) + { + CDisableUndoScopeGuard guard; + + for ( i = 0; i < NUM_CHANNELS; ++i ) + { + CDmeChannel *channel = channels[ i ]; + CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() ); + Assert( pLog ); + pLog->ClearKeys(); // reset it + + CDmeCurveInfo *pCurveInfo = params.usecurves ? pLog->GetOrCreateCurveInfo() : pLog->GetCurveInfo(); + if ( params.usecurves ) + { + pCurveInfo->SetDefaultCurveType( params.defaultcurve ); + pCurveInfo->SetMinValue( 0.0f ); + pCurveInfo->SetMaxValue( 1000.0f ); + } + else if ( !params.usecurves && pCurveInfo ) + { + g_pDataModel->DestroyElement( pCurveInfo->GetHandle() ); + pLog->SetCurveInfo( NULL ); + } + + const TestLayer_t& tl = params.layers[ 0 ]; + // Now add entries + DmeTime_t logStep = tl.timeStep; + DmeTime_t logStart = tl.startTime; + + for ( DmeTime_t t = logStart; t <= tl.endTime + logStep - DmeTime_t( 1 ); t += logStep ) + { + DmeTime_t useTime = t; + if ( useTime > tl.endTime ) + useTime = tl.endTime; + + float value = tl.ValueForTime( useTime ); + if ( tl.usecurvetype ) + { + pLog->SetKey( useTime, value, tl.curvetype ); + } + else + { + pLog->SetKey( useTime, value ); + } + } + } + } + + // Test creating a layer and collapsing it back down + g_pChannelRecordingMgr->StartLayerRecording( "layer operations", &ts ); + for ( i = 0; i < c; ++i ) + { + g_pChannelRecordingMgr->AddChannelToRecordingLayer( channels[ i ] ); // calls log->CreateNewLayer() + } + + // Now add values to channel logs + for ( i = 0; i < c; ++i ) + { + CDmeChannel *channel = channels[ i ]; + CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() ); + Assert( pLog ); + + pLog->StampKeyAtHead( tHeadPosition, tHeadPosition, ts, value ); + } + + // Flattens the layers + g_pChannelRecordingMgr->FinishLayerRecording( 0.0f, true ); + + if ( params.spew & SPEW_VALUES ) + { + for ( i = 0; i < c; ++i ) + { + CDmeChannel *channel = channels[ i ]; + CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() ); + Assert( pLog ); + Assert( pLog->GetNumLayers() == 1 ); + + for ( DmeTime_t j = params.mintime; j <= params.maxtime; j += DmeTime_t( 1 ) ) + { + float fval = pLog->GetValue( j ); + Msg( "%d %f\n", j.GetTenthsOfMS(), fval ); + } + } + } + + if ( params.spew & SPEW_KEYS ) + { + for ( i = 0; i < c; ++i ) + { + CDmeChannel *channel = channels[ i ]; + CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() ); + Assert( pLog ); + Assert( pLog->GetNumLayers() == 1 ); + + int kc = pLog->GetKeyCount(); + for ( j = 0; j < kc; ++j ) + { + DmeTime_t time = pLog->GetKeyTime( j ); + + float fval = pLog->GetValue( time ); + Msg( "%d %f %f\n", j, time.GetSeconds(), fval ); + } + } + } + + // Now test creating a layer and "undo/redo" of the layer + if ( params.testundo ) + { + g_pDataModel->Undo(); + g_pDataModel->Redo(); + } +} + +DEFINE_TESTCASE_NOSUITE( DmxTestDmeLogLayers ) +{ + Msg( "Running CDmeTypedLog<float> layering tests...\n" ); + +#ifdef _DEBUG + int nStartingCount = g_pDataModel->GetAllocatedElementCount(); +#endif + + CUtlVector< CDmeChannel * > channels; + + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxTestDmeLogLayers>" ); + + CreateChannels( NUM_CHANNELS, channels, fileid ); + + TestParams_t params; + { + params.testundo = false; + params.usecurves = false; + params.defaultcurve = CURVE_DEFAULT; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_DEFAULT, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 5 ), DmeTime_t( 95 ), DmeTime_t( 10 ), CURVE_DEFAULT, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "One-Layer", channels, params ); + params.Reset(); + } + + // Single layer using lerp everywhere + // ----------------------- + { + params.testundo = false; + params.usecurves = true; + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "One-Layer Lerp", channels, params ); + params.Reset(); + } + + // Two layers using lerp + // ---------------------------- + // ------------------------ + { + params.testundo = false; + params.usecurves = true; + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 5 ), DmeTime_t( 95 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Two-Layer Lerp (contained)", channels, params ); + params.Reset(); + } + + // Two layers using CURVE_EASE_IN_TO_EASE_OUT, there should be some disparity + // ---------------------------- + // ------------------------ + { + params.testundo = false; + params.usecurves = true; + params.defaultcurve = CURVE_EASE_IN_TO_EASE_OUT; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_EASE_IN_TO_EASE_OUT, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 5 ), DmeTime_t( 95 ), DmeTime_t( 10 ), CURVE_EASE_IN_TO_EASE_OUT, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Two-Layer Ease In/Out (contained)", channels, params ); + params.Reset(); + } + + // Two layers using lerp + // ---------------------------- + // --------- + { + params.testundo = false; + params.usecurves = true; + params.mintime = DmeTime_t( -20 ); + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( -20 ), DmeTime_t( 20 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Two-Layer Lerp (overhang start)", channels, params ); + params.Reset(); + } + + // Two layers using lerp + // ---------------------------- + // ------------ + { + params.testundo = false; + params.usecurves = true; + params.maxtime = DmeTime_t( 120 ); + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 80 ), DmeTime_t( 120 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Two-Layer Lerp (overhang end)", channels, params ); + params.Reset(); + } + // Three layers using lerp + // ------------- + // ----- ----- + { + params.testundo = false; + params.usecurves = true; + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.mintime = DmeTime_t( -12 ); + params.maxtime = DmeTime_t( 115 ); + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( -12 ), DmeTime_t( 12 ), DmeTime_t( 4 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 85 ), DmeTime_t( 115 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Three-Layer Lerp (overhang start + end)", channels, params ); + params.Reset(); + } + + // Three layers using lerp + // ------------- + // ----- + // -- + { + params.testundo = false; + params.usecurves = true; + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 25 ), DmeTime_t( 75 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 40 ), DmeTime_t( 60 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Three-Layer Lerp (layer inside layer)", channels, params ); + params.Reset(); + } + + // Three layers using lerp + // ------------- + // ----- + // -- + { + params.testundo = false; + params.usecurves = true; + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 25 ), DmeTime_t( 75 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 70 ), DmeTime_t( 80 ), DmeTime_t( 2 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Three-Layer Lerp (first layer contained, second layer overlapping first at end)", channels, params ); + params.Reset(); + } + + // Three layers using lerp + // ------------- + // ----- + // -- + { + params.testundo = false; + params.usecurves = true; + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 25 ), DmeTime_t( 75 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 15 ), DmeTime_t( 35 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Three-Layer Lerp (first layer contained, second layer overlapping first at start)", channels, params ); + params.Reset(); + } + + // Four layers using lerp + // --------------- + // ----- + // ---- + // ------- + { + params.testundo = false; + params.usecurves = true; + // params.spewnontopmostlayers = true; + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_CONSTANT, 20.0f ); + params.AddLayer( DmeTime_t( 15 ), DmeTime_t( 40 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 60 ), DmeTime_t( 85 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + params.AddLayer( DmeTime_t( 35 ), DmeTime_t( 79 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Four-Layer Lerp (top overlapping end of 1st and start of 2nd layer)", channels, params ); + params.Reset(); + } + + // Single layer using lerp everywhere + // ----------------------- + { + params.testundo = false; + params.usecurves = true; + params.spew = 0; //SPEW_VALUES | SPEW_KEYS; + params.mintime = DmeTime_t( 0 ); + params.maxtime = DmeTime_t( 10000 ); + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 10000 ), DmeTime_t( 20 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SINE, 100.0f ); + + DmeTime_t tHeadPosition = DmeTime_t( 5000 ); + + DmeLog_TimeSelection_t ts; + ts.m_nTimes[ TS_LEFT_FALLOFF ] = tHeadPosition + DmeTime_t( -987 ); + ts.m_nTimes[ TS_LEFT_HOLD ] = ts.m_nTimes[ TS_RIGHT_HOLD ] = tHeadPosition; + ts.m_nTimes[ TS_RIGHT_FALLOFF ] = tHeadPosition + DmeTime_t( 1052 ); + ts.m_nFalloffInterpolatorTypes[ 0 ] = ts.m_nFalloffInterpolatorTypes[ 1 ] = INTERPOLATE_EASE_INOUT; + + // Resample at 50 msec intervals + ts.m_bResampleMode = true; + ts.m_nResampleInterval = DmeTime_t( 50 ); + + ///params.spew |= SPEW_KEYS | SPEW_VALUES; + + RunTimeSelectionTest( "One-Layer Time Selection at 50, falloff 25, EASE_INOUT interp", channels, params, tHeadPosition, ts, 250 ); + + params.purgevalues = false; + // params.spew |= SPEW_VALUES; + + // Shift the head and do it all again + tHeadPosition = DmeTime_t( 2000 ); + ts.m_nTimes[ TS_LEFT_FALLOFF ] = DmeTime_t( 1487 ); + ts.m_nTimes[ TS_LEFT_HOLD ] = ts.m_nTimes[ TS_RIGHT_HOLD ] = tHeadPosition; + ts.m_nTimes[ TS_RIGHT_FALLOFF ] = tHeadPosition + DmeTime_t( 631 ); + + RunTimeSelectionTest( "2nd layer", channels, params, tHeadPosition, ts, 500 ); + params.Reset(); + } + // Single layer using lerp everywhere + // ----------------------- + { + params.testundo = true; + params.usecurves = true; + params.spew = 0; //SPEW_VALUES | SPEW_KEYS; + params.mintime = DmeTime_t( 0 ); + params.maxtime = DmeTime_t( 1000 ); + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 1000 ), DmeTime_t( 20 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_CONSTANT, 100.0f ); + + DmeTime_t tHeadPosition = DmeTime_t( 500 ); + DmeLog_TimeSelection_t ts; + ts.m_nTimes[ TS_LEFT_FALLOFF ] = tHeadPosition + DmeTime_t( -100 ); + ts.m_nTimes[ TS_LEFT_HOLD ] = ts.m_nTimes[ TS_RIGHT_HOLD ] = tHeadPosition; + ts.m_nTimes[ TS_RIGHT_FALLOFF ] = tHeadPosition + DmeTime_t( 100 ); + ts.m_nFalloffInterpolatorTypes[ 0 ] = ts.m_nFalloffInterpolatorTypes[ 1 ] = INTERPOLATE_LINEAR_INTERP; + + // Resample at 50 msec intervals + ts.m_bResampleMode = true; + ts.m_nResampleInterval = DmeTime_t( 10 ); + +// params.spew |= SPEW_VALUES; + + RunTimeSelectionTest( "Resetting layer", channels, params, tHeadPosition, ts, 200 ); + + params.purgevalues = false; + //params.spew |= SPEW_VALUES; + + // Shift the head and do it all again + //ts.m_nRelativeFalloffTimes[ 0 ] = 1487 - 2000; + //ts.m_nRelativeHoldTimes[ 0 ] = ts.m_nRelativeHoldTimes[ 1 ] = 0; + //ts.m_nRelativeFalloffTimes[ 1 ] = 631; + //ts.SetHeadPosition( 2000 ); + + RunTimeSelectionTest( "2nd layer", channels, params, tHeadPosition, ts, 110 ); + params.Reset(); + } +// g_pDataModel->TraceUndo( true ); + + // Test abort undo stuff + for ( int i = 0; i < 2; ++i ) + // Four layers using lerp + // --------------- + // ----- + // ---- + // ------- + { + params.testundo = false; + params.testabort = i != 1 ? true : false; + params.usecurves = false; + // params.spewnontopmostlayers = true; + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 10 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_CONSTANT, 20.0f ); + params.AddLayer( DmeTime_t( 5 ), DmeTime_t( 6 ), DmeTime_t( 1 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Four-Layer Lerp (top overlapping end of 1st and start of 2nd layer)", channels, params ); + params.Reset(); + } + + // g_pDataModel->TraceUndo( false ); + + + //DestroyChannels( channels ); + + g_pDataModel->ClearUndo(); + + g_pDataModel->RemoveFileId( fileid ); + +#ifdef _DEBUG + int nEndingCount = g_pDataModel->GetAllocatedElementCount(); + AssertEquals( nEndingCount, nStartingCount ); + if ( nEndingCount != nStartingCount ) + { + for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement() ; + hElement != DMELEMENT_HANDLE_INVALID; + hElement = g_pDataModel->NextAllocatedElement( hElement ) ) + { + CDmElement *pElement = g_pDataModel->GetElement( hElement ); + Assert( pElement ); + if ( !pElement ) + return; + + Msg( "[%s : %s] in memory\n", pElement->GetName(), pElement->GetTypeString() ); + } + } +#endif +} + +DEFINE_TESTCASE_NOSUITE( DmxTestDmeLogLayersUndo ) +{ + Msg( "Running CDmeTypedLog<float> layering UNDO tests...\n" ); + +#ifdef _DEBUG + int nStartingCount = g_pDataModel->GetAllocatedElementCount(); +#endif + + CUtlVector< CDmeChannel * > channels; + + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxTestDmeLogLayersUndo>" ); + + CreateChannels( NUM_CHANNELS, channels, fileid ); + + TestParams_t params; + +// g_pDataModel->TraceUndo( true ); + + // Test abort undo stuff + for ( int i = 0; i < 2; ++i ) + { + params.testundo = false; + params.testabort = true; + params.usecurves = false; + // params.spewnontopmostlayers = true; + params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP; + params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 1000 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_CONSTANT, 20.0f ); + params.AddLayer( DmeTime_t( 100 ), DmeTime_t( 900 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE ); + RunLayerTest( "Abort undo", channels, params ); + params.Reset(); + } + +// g_pDataModel->TraceUndo( false ); + + g_pDataModel->ClearUndo(); + g_pDataModel->RemoveFileId( fileid ); + +#ifdef _DEBUG + int nEndingCount = g_pDataModel->GetAllocatedElementCount(); + AssertEquals( nEndingCount, nStartingCount ); + if ( nEndingCount != nStartingCount ) + { + for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement() ; + hElement != DMELEMENT_HANDLE_INVALID; + hElement = g_pDataModel->NextAllocatedElement( hElement ) ) + { + CDmElement *pElement = g_pDataModel->GetElement( hElement ); + Assert( pElement ); + if ( !pElement ) + return; + + Msg( "[%s : %s] in memory\n", pElement->GetName(), pElement->GetTypeString() ); + } + } +#endif +} diff --git a/unittests/dmxtest/dmxtest_vcdtodme.cpp b/unittests/dmxtest/dmxtest_vcdtodme.cpp new file mode 100644 index 0000000..900b310 --- /dev/null +++ b/unittests/dmxtest/dmxtest_vcdtodme.cpp @@ -0,0 +1,110 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "datamodel/dmelement.h" +#include "movieobjects/movieobjects.h" +#include "datamodel/idatamodel.h" +#include "tier1/utlbuffer.h" +#include "filesystem.h" +#include "movieobjects/dmelog.h" +#include "choreoscene.h" +#include "choreoevent.h" +#include "iscenetokenprocessor.h" +#include "tier1/tokenreader.h" +#include "characterset.h" +#include "movieobjects/dmx_to_vcd.h" +#include "tier3/scenetokenprocessor.h" +#include "tier2/tier2.h" + +char const *vcdtestfile = "dmxtest.vcd"; + +void RunSceneToDmxTests( CChoreoScene *scene ) +{ + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( scene->GetFilename() ); + CDmeFilmClip *dmx = CreateElement< CDmeFilmClip >( scene->GetFilename(), fileid ); + Assert( dmx ); + + bool success = ConvertSceneToDmx( scene, dmx ); + Assert( success ); + + CChoreoScene *scene2 = new CChoreoScene( NULL ); + scene2->SetFileName( scene->GetFilename() ); + + success = ConvertDmxToScene( dmx, scene2 ); + Assert( success ); + + char sz[ 512 ]; + Q_StripExtension( scene->GetFilename(), sz, sizeof( sz ) ); + Q_strncat( sz, "_2.vcd", sizeof( sz ), COPY_ALL_CHARACTERS ); + scene2->SaveToFile( sz ); + + delete scene2; + + g_pDataModel->RemoveFileId( fileid ); +} + +DEFINE_TESTCASE_NOSUITE( DmxTestVcdToDme ) +{ + Msg( "Running .vcd (faceposer) to dmx tests\n" ); + +#ifdef _DEBUG + int nStartingCount = g_pDataModel->GetAllocatedElementCount(); +#endif + + CDisableUndoScopeGuard guard; + + g_pDmElementFramework->BeginEdit(); + + const char *pFileName = vcdtestfile; + char pFullPathName[ MAX_PATH ]; + char pDir[ MAX_PATH ]; + if ( g_pFullFileSystem->GetCurrentDirectory( pDir, sizeof( pDir ) ) ) + { + V_ComposeFileName( pDir, vcdtestfile, pFullPathName, sizeof( pFullPathName ) ); + V_RemoveDotSlashes( pFullPathName ); + pFileName = pFullPathName; + } + + CUtlBuffer buf; + if ( g_pFullFileSystem->ReadFile( pFileName, NULL, buf ) ) + { + SetTokenProcessorBuffer( (char *)buf.Base() ); + CChoreoScene *scene = ChoreoLoadScene( pFileName, NULL, GetTokenProcessor(), NULL ); + if ( scene ) + { + RunSceneToDmxTests( scene ); + delete scene; + } + } + else + { + Msg( "Unable to load test file '%s'\n", pFileName ); + } + + g_pDataModel->ClearUndo(); + +#ifdef _DEBUG + int nEndingCount = g_pDataModel->GetAllocatedElementCount(); + AssertEquals( nEndingCount, nStartingCount ); + if ( nEndingCount != nStartingCount ) + { + for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement() ; + hElement != DMELEMENT_HANDLE_INVALID; + hElement = g_pDataModel->NextAllocatedElement( hElement ) ) + { + CDmElement *pElement = g_pDataModel->GetElement( hElement ); + Assert( pElement ); + if ( !pElement ) + return; + + Msg( "[%s : %s] in memory\n", pElement->GetName(), pElement->GetTypeString() ); + } + } +#endif +}
\ No newline at end of file diff --git a/unittests/dmxtest/dmxtestarray.cpp b/unittests/dmxtest/dmxtestarray.cpp new file mode 100644 index 0000000..e9c7468 --- /dev/null +++ b/unittests/dmxtest/dmxtestarray.cpp @@ -0,0 +1,76 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for DMX testing (testing the Array operations) +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "datamodel/dmelement.h" +#include "datamodel/idatamodel.h" +#include "tier1/utlbuffer.h" +#include "filesystem.h" +#include "datamodel/dmehandle.h" +#include "tier2/tier2.h" +#include "movieobjects/dmeshape.h" + + +DEFINE_TESTCASE_NOSUITE( DmxArrayTest ) +{ + Msg( "Running dmx array tests...\n" ); + + CDisableUndoScopeGuard sg; + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<RunArrayTests>" ); + + CDmElement *pElement = CreateElement< CDmElement >( "root", fileid ); + + CDmElement *pElement2 = CreateElement<CDmElement>( "element1", fileid ); + Assert( pElement2 ); + CDmElement *pElement3 = CreateElement<CDmElement>( "element2", fileid ); + Assert( pElement3 ); + CDmeShape *pElement4 = CreateElement<CDmeShape>( "shape", fileid ); + Assert( pElement4 ); + + CDmrStringArray stringVec( pElement, "string_array_test", true ); + stringVec.AddToTail( "string1" ); + stringVec.AddToTail( "string2" ); + stringVec.AddToTail( "string3" ); + + CDmrArray< float > floatVec( pElement, "float_array_test", true ); + floatVec.AddToTail( -1.0f ); + floatVec.AddToTail( 0.0f ); + floatVec.AddToTail( 1.0f ); + + CDmrElementArray< > elementVec( pElement, "element_array_test", true ); + elementVec.AddToTail( pElement2 ); + elementVec.AddToTail( pElement3 ); + elementVec.AddToTail( pElement4 ); + + CDmrStringArray stringVec2( pElement, "string_array_test2", true ); + stringVec2 = stringVec; + Shipping_Assert( stringVec2.Count() == 3 ); + + CDmrArray< float > floatVec2( pElement, "float_array_test2", true ); + floatVec2 = floatVec; + Shipping_Assert( floatVec2.Count() == 3 ); + + CDmrElementArray< > elementVec2( pElement, "element_array_test2", true ); + elementVec2 = elementVec; + Shipping_Assert( elementVec2.Count() == 3 ); + + CDmrElementArray< CDmeShape > elementVec3( pElement, "element_array_test3", true ); + elementVec3 = elementVec2; + Shipping_Assert( elementVec3.Count() == 1 ); + + CUtlVector<DmElementHandle_t> val; + val.AddToTail( pElement2->GetHandle() ); + val.AddToTail( pElement4->GetHandle() ); + + elementVec2 = val; + Shipping_Assert( elementVec2.Count() == 2 ); + + elementVec3 = val; + Shipping_Assert( elementVec3.Count() == 1 ); + + g_pDataModel->RemoveFileId( fileid ); +} diff --git a/unittests/dmxtest/dmxtestdmelog.cpp b/unittests/dmxtest/dmxtestdmelog.cpp new file mode 100644 index 0000000..3f98678 --- /dev/null +++ b/unittests/dmxtest/dmxtestdmelog.cpp @@ -0,0 +1,393 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "datamodel/dmelement.h" +#include "movieobjects/movieobjects.h" +#include "datamodel/idatamodel.h" +#include "tier1/utlbuffer.h" +#include "filesystem.h" +#include "movieobjects/dmelog.h" +#include "choreoscene.h" +#include "choreoevent.h" + +struct data_t +{ + int tms; // tenths of a millisecond + float value; + int curvetype; +}; + +struct tvpair_t +{ + int tms; + float expectedvalue; +}; + +data_t data[] = +{ + { 0, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) }, + { 10000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) }, + { 20000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_EASE_IN, INTERPOLATE_EASE_OUT ) }, + { 30000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_EASE_OUT, INTERPOLATE_EASE_INOUT ) }, + { 40000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_EASE_INOUT, INTERPOLATE_BSPLINE ) }, + { 50000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_BSPLINE, INTERPOLATE_LINEAR_INTERP ) }, + { 60000, 1.0f, MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_KOCHANEK_BARTELS ) }, + { 70000, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS, INTERPOLATE_KOCHANEK_BARTELS_EARLY ) }, + { 80000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS_EARLY, INTERPOLATE_KOCHANEK_BARTELS_LATE ) }, + { 90000, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS_LATE, INTERPOLATE_SIMPLE_CUBIC ) }, + { 100000, 0.25f, MAKE_CURVE_TYPE( INTERPOLATE_SIMPLE_CUBIC, INTERPOLATE_CATMULL_ROM ) }, + { 110000, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM, INTERPOLATE_CATMULL_ROM_NORMALIZE ) }, + { 120000, 0.125f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZE, INTERPOLATE_EXPONENTIAL_DECAY ) }, + { 130000, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_EXPONENTIAL_DECAY, INTERPOLATE_HOLD ) }, + { 140000, 0.0625f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_EXPONENTIAL_DECAY ) }, + { 150000, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) }, +}; + +#define NUM_DEF_TESTS 3 + +static data_t values1[] = +{ + { -1, 0.0f, 0 }, +}; +static data_t values2[] = +{ + { 5000, 0.5f, CURVE_DEFAULT }, + { -1, 0.0f, 0 }, +}; +static data_t values3[] = +{ + { 2500, 0.25f, CURVE_DEFAULT }, + { 7500, 0.75f, CURVE_DEFAULT }, + { -1, 0.0f, 0 }, +}; + +static data_t *defaultvaluetest[ NUM_DEF_TESTS ] = +{ + values1, + values2, + values3 +}; + +#define NUM_TEST_VALUES 3 + +static tvpair_t expectedvalues1[NUM_TEST_VALUES] = +{ + { 0, 0.5f }, + { 5000, 0.5f }, + { 10000, 0.5f }, +}; + +static tvpair_t expectedvalues2[NUM_TEST_VALUES] = +{ + { 0, 0.5f }, + { 5000, 0.5f }, + { 10000, 0.5f }, +}; + +static tvpair_t expectedvalues3[NUM_TEST_VALUES] = +{ + { 0, 0.25f }, + { 5000, 0.5f }, + { 10000, 0.75f }, +}; + +static tvpair_t *expectedvalues[ NUM_DEF_TESTS ] = +{ + expectedvalues1, + expectedvalues2, + expectedvalues3 +}; + +void ResetLog( CDmeFloatLog *log, bool useCurveTypes, int startIndex = 0, int endIndex = -1 ) +{ + log->ClearKeys(); + + CDmeCurveInfo *pCurveInfo = useCurveTypes ? log->GetOrCreateCurveInfo() : log->GetCurveInfo(); + if ( useCurveTypes ) + { + pCurveInfo->SetDefaultCurveType( MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) ); + } + else if ( !useCurveTypes && pCurveInfo ) + { + g_pDataModel->DestroyElement( pCurveInfo->GetHandle() ); + log->SetCurveInfo( NULL ); + } + + int i; + int c; + + c = ARRAYSIZE( data ); + for ( i = startIndex; i < c; ++i ) + { + log->SetKey( DmeTime_t( data[ i ].tms ), data[ i ].value, useCurveTypes ? data[ i ].curvetype : CURVE_DEFAULT ); + + if ( endIndex != -1 && i >= endIndex ) + break; + } +} + +void CompareFloats( float f1, float f2, float tol, char const *fmt, ... ) +{ + float diff = fabs( f1 - f2 ); + if ( diff < tol ) + return; + + char buf[ 256 ]; + va_list argptr; + va_start( argptr, fmt ); + _vsnprintf( buf, sizeof( buf ) - 1, fmt, argptr ); + va_end( argptr ); + + Msg( buf ); +} + +DEFINE_TESTCASE_NOSUITE( DmxRunDefaultValueLogTest ) +{ + Msg( "Running CDmeTypedLog<float> default value (stereo channel w/ value 0.5) tests...\n" ); + CDisableUndoScopeGuard sg; + + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxTestDmeLog>" ); + + for ( int i = 0; i < NUM_DEF_TESTS; ++i ) + { + data_t *pdata = defaultvaluetest[ i ]; + tvpair_t *pexpected = expectedvalues[ i ]; + + // Run each test + + CDmeFloatLog *log = CreateElement<CDmeFloatLog>( "curve", fileid ); + if ( !log ) + { + Msg( "Unable to create CDmeFloatLog object!!!" ); + continue; + } + + log->SetDefaultValue( 0.5f ); + + if ( pdata ) + { + // Run the test + for ( int j = 0; ; ++j ) + { + if ( pdata[ j ].tms == -1 ) + break; + + log->SetKey( DmeTime_t( pdata[ j ].tms ), pdata[ j ].value ); + } + } + + // Now compare against expected values + for ( int j = 0; j < NUM_TEST_VALUES; ++j ) + { + DmeTime_t t = DmeTime_t( pexpected[ j ].tms ); + float v = pexpected[ j ].expectedvalue; + float logv = log->GetValue( t ); + Shipping_Assert( v == logv ); + } + + DestroyElement( log ); + } + + g_pDataModel->RemoveFileId( fileid ); +} + +void RunDmeFloatLogTests( CDmeFloatLog *log ) +{ + Msg( " Testing general log data...\n" ); + + ResetLog( log, false ); + + CompareFloats( 0.5f, log->GetValue( DmeTime_t( 2.0f ) ), 0.000001f, "log->GetValue( 2.0 ) expected to be 0.5f\n" ); + CompareFloats( 0.5f, log->GetValue( DmeTime_t( 2.5f ) ), 0.000001f, "log->GetValue( 2.5 ) expected to be 0.5f\n" ); + CompareFloats( 0.5f, log->GetValue( DmeTime_t( 2.5f ) ), 0.000001f, "log->GetValue( 2.5 ) expected to be 0.5f\n" ); + CompareFloats( 0.5f, log->GetValue( DmeTime_t( 6.5f ) ), 0.000001f, "log->GetValue( 6.5 ) expected to be 0.5f\n" ); + + CDmeCurveInfo *pCurveInfo = log->GetOrCreateCurveInfo(); + + int idx = log->FindKeyWithinTolerance( DmeTime_t( 6.0f ), DmeTime_t( 0 ) ); + Shipping_Assert( log->GetKeyTime( idx ) == DmeTime_t( 6.0f ) ); + log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_LINEAR_INTERP ) ); + log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_LINEAR_INTERP ) ); + + float val = log->GetValue( DmeTime_t( 6.5f ) ); + float qval = log->GetValue( DmeTime_t( 6.25f ) ); + + CompareFloats( 0.5f, val, 0.000001f, "INTERPOLATE_LINEAR_INTERPlog->GetValue( 6500 ) expcted to be 0.5f\n" ); + CompareFloats( 0.75f, qval, 0.000001f, "INTERPOLATE_LINEAR_INTERPlog->GetValue( 6250 ) expcted to be 0.75f\n" ); + + log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) ); + log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) ); + + float val2 = log->GetValue( DmeTime_t( 6.5f ) ); + float qval2 = log->GetValue( DmeTime_t( 6.25f ) ); + Shipping_Assert( val2 == val ); + Shipping_Assert( qval2 != val ); + + log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_EASE_INOUT, INTERPOLATE_EASE_INOUT ) ); + log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_EASE_INOUT, INTERPOLATE_EASE_INOUT ) ); + + float val3 = log->GetValue( DmeTime_t( 6.5f ) ); + float qval3 = log->GetValue( DmeTime_t( 6.25f ) ); + Shipping_Assert( val3 == val ); + Shipping_Assert( qval3 != val ); + + log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_EXPONENTIAL_DECAY, INTERPOLATE_EXPONENTIAL_DECAY ) ); + log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_EXPONENTIAL_DECAY, INTERPOLATE_EXPONENTIAL_DECAY ) ); + + float val4 = log->GetValue( DmeTime_t( 6.5f ) ); + float qval4 = log->GetValue( DmeTime_t( 6.25f ) ); + Shipping_Assert( val4 != val ); + Shipping_Assert( qval4 != val ); + + log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS, INTERPOLATE_KOCHANEK_BARTELS ) ); + log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS, INTERPOLATE_KOCHANEK_BARTELS ) ); + + float val5 = log->GetValue( DmeTime_t( 6.5f ) ); + float qval5 = log->GetValue( DmeTime_t( 6.25f ) ); + Shipping_Assert( val5 == val ); + Shipping_Assert( qval5 != val ); + + pCurveInfo->SetDefaultCurveType( MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS, INTERPOLATE_KOCHANEK_BARTELS ) ); + log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_DEFAULT, INTERPOLATE_DEFAULT ) ); + log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_DEFAULT, INTERPOLATE_DEFAULT ) ); + + float val6 = log->GetValue( DmeTime_t( 6.5f ) ); + float qval6 = log->GetValue( DmeTime_t( 6.25f ) ); + Shipping_Assert( val5 == val6 ); + Shipping_Assert( qval6 == qval5 ); + +} + +void CompareLogToChoreo( CFlexAnimationTrack *track, CDmeFloatLog *log ) +{ + // Now run tests + for ( DmeTime_t t( 0 ); t < DmeTime_t( 20.0f ); t += DmeTime_t( 0.1f ) ) + { + // Compare values + float dmevalue = log->GetValue( t ); + float choreovalue = track->GetIntensity( t.GetSeconds() ); + + CompareFloats( dmevalue, choreovalue, 0.001f, "Time(%f sec) , dme [%f] choreo[%f], diff[%f]\n", + t.GetSeconds(), + dmevalue, + choreovalue, + fabs( dmevalue - choreovalue ) ); + } +} + +void ResetChoreo( CFlexAnimationTrack *track, bool useCurveTypes, int startIndex = 0, int endIndex = -1 ) +{ + track->Clear(); + + int i; + int c; + + c = ARRAYSIZE( data ); + for ( i = startIndex; i < c; ++i ) + { + data_t *e = &data[ i ]; + + float t = (float)e->tms / 10000.0f; + + CExpressionSample *sample = track->AddSample( t, e->value ); + Shipping_Assert( sample ); + if ( useCurveTypes ) + { + sample->SetCurveType( e->curvetype ); + } + + if ( endIndex != -1 && i >= endIndex ) + break; + } +} + +void RunDmeChoreoComparisons( CDmeFloatLog *log ) +{ + Msg( " Testing choreo-style log data...\n" ); + + ResetLog( log, true ); + log->SetRightEdgeTime( DmeTime_t( 15.0f ) ); + + CChoreoScene *scene = new CChoreoScene( NULL ); + CChoreoEvent *event = new CChoreoEvent( scene, CChoreoEvent::FLEXANIMATION, "test" ); + event->SetStartTime( 0.0f ); + event->SetEndTime( 15.0f ); + CFlexAnimationTrack *track = new CFlexAnimationTrack( event ); + track->SetFlexControllerName( "flextest" ); + track->SetComboType( false ); + + ResetChoreo( track, true ); + + Msg( " Comparing default data...\n" ); + + CompareLogToChoreo( track, log ); + + ResetLog( log, true, 3, 14 ); + ResetChoreo( track, true, 3, 14 ); + + Msg( " Comparing subset of data...\n" ); + + CompareLogToChoreo( track, log ); + + Msg( " Comparing left/right edge settings...\n" ); + // Now test right and left edge stuff + // Enable left edge stuff + track->SetEdgeActive( true, true ); + track->SetEdgeInfo( true, MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_LINEAR_INTERP ), 0.75f ); + track->SetEdgeActive( false, true ); + track->SetEdgeInfo( false, MAKE_CURVE_TYPE( INTERPOLATE_EASE_OUT, INTERPOLATE_EASE_OUT ), 0.25f ); + + // Same settings for log + log->SetUseEdgeInfo( true ); + log->SetDefaultEdgeZeroValue( 0.0f ); + log->SetEdgeInfo( 0, true, 0.75f, MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_LINEAR_INTERP ) ); + log->SetEdgeInfo( 1, true, 0.25f, MAKE_CURVE_TYPE( INTERPOLATE_EASE_OUT, INTERPOLATE_EASE_OUT ) ); + + CompareLogToChoreo( track, log ); + + int i; + for ( i = 1; i < NUM_INTERPOLATE_TYPES; ++i ) + { + Msg( " Comparing left/right edge settings[ %s ]...\n", Interpolator_NameForInterpolator( i, true ) ); + + float val = (float)i / (float)( NUM_INTERPOLATE_TYPES - 1 ) ; + // Now test right and left edge stuff with different data + track->SetEdgeInfo( true, MAKE_CURVE_TYPE( i, i ), val ); + track->SetEdgeInfo( false, MAKE_CURVE_TYPE( i, i ), val ); + log->SetEdgeInfo( 0, true, val, MAKE_CURVE_TYPE( i, i ) ); + log->SetEdgeInfo( 1, true, val, MAKE_CURVE_TYPE( i, i ) ); + + CompareLogToChoreo( track, log ); + } + + delete event; + delete scene; +} + +DEFINE_TESTCASE_NOSUITE( DmxTestDmeLog ) +{ + Msg( "Running CDmeTypedLog<float> tests...\n" ); + CDisableUndoScopeGuard sg; + + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxTestDmeLog>" ); + + CDmeFloatLog *pElement = CreateElement<CDmeFloatLog>( "curve", fileid ); + if ( !pElement ) + { + Msg( "Unable to create CDmeFloatLog object!!!" ); + return; + } + + // Run tests + RunDmeFloatLogTests( pElement ); + + RunDmeChoreoComparisons( pElement ); + + g_pDataModel->RemoveFileId( fileid ); +}
\ No newline at end of file diff --git a/unittests/dmxtest/dmxtestloader.cpp b/unittests/dmxtest/dmxtestloader.cpp new file mode 100644 index 0000000..ab3adbf --- /dev/null +++ b/unittests/dmxtest/dmxtestloader.cpp @@ -0,0 +1,211 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for DMX testing +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "dmxloader/dmxloader.h" +#include "dmxloader/dmxelement.h" + +struct TestStruct_t +{ + DmObjectId_t m_nId; + bool m_bBool; + int m_nInt; + float m_flFloat; + Color m_Color; + Vector2D m_Vector2D; + Vector m_Vector3D; + Vector4D m_Vector4D; + QAngle m_Angles; + Quaternion m_Quaternion; + VMatrix m_Matrix; + char m_pStringBuf[256]; +}; + +BEGIN_DMXELEMENT_UNPACK( TestStruct_t ) + DMXELEMENT_UNPACK_FIELD( "id_test", NULL, DmObjectId_t, m_nId ) + DMXELEMENT_UNPACK_FIELD( "bool_test", "1", bool, m_bBool ) + DMXELEMENT_UNPACK_FIELD( "int_test", "5", int, m_nInt ) + DMXELEMENT_UNPACK_FIELD( "float_test", "4.0", float, m_flFloat ) + DMXELEMENT_UNPACK_FIELD( "color_test", "200 200 200 200", Color, m_Color ) + DMXELEMENT_UNPACK_FIELD( "vector2d_test", "5.0 1.0", Vector2D, m_Vector2D ) + DMXELEMENT_UNPACK_FIELD( "vector3d_test", "5.0 1.0 -3.0", Vector, m_Vector3D ) + DMXELEMENT_UNPACK_FIELD( "vector4d_test", "5.0 1.0 -4.0 2.0", Vector4D, m_Vector4D ) + DMXELEMENT_UNPACK_FIELD( "qangle_test", "5.0 1.0 -3.0", QAngle, m_Angles ) + DMXELEMENT_UNPACK_FIELD( "quat_test", "5.0 1.0 -4.0 2.0", Quaternion, m_Quaternion ) + DMXELEMENT_UNPACK_FIELD( "vmatrix_test", NULL, VMatrix, m_Matrix ) + DMXELEMENT_UNPACK_FIELD_STRING( "string_test", "default", m_pStringBuf ) +END_DMXELEMENT_UNPACK( TestStruct_t, s_TestStructUnpack ) + +void TestReadFile( CDmxElement *pRoot ) +{ + VMatrix mattest, mat2test; + MatrixBuildRotateZ( mattest, 45 ); + MatrixBuildRotateZ( mat2test, 30 ); + + int i; + unsigned char buftest[256]; + unsigned char buf2test[256]; + for ( i = 0; i < 256; ++i ) + { + buftest[i] = i; + buf2test[i] = 255 - i; + } + + + // Make sure everything was read in ok. + AssertEquals( pRoot->GetValue<bool>( "bool_test" ), true ); + AssertEquals( pRoot->GetValue<int>( "int_test" ), 2 ); + AssertFloatEquals( pRoot->GetValue<float>( "float_test" ), 3.0f, 1e-3 ); + const Color& color = pRoot->GetValue<Color>( "color_test" ); + Shipping_Assert( color.r() == 0 && color.g() == 64 && color.b() == 128 && color.a() == 255 ); + const Vector2D& vec2D = pRoot->GetValue<Vector2D>( "vector2d_test" ); + Shipping_Assert( vec2D.x == 1.0f && vec2D.y == -1.0f ); + const Vector& vec3D = pRoot->GetValue<Vector>( "vector3d_test" ); + Shipping_Assert( vec3D.x == 1.0f && vec3D.y == -1.0f && vec3D.z == 0.0f ); + const Vector4D& vec4D = pRoot->GetValue<Vector4D>( "vector4d_test" ); + Shipping_Assert( vec4D.x == 1.0f && vec4D.y == -1.0f && vec4D.z == 0.0f && vec4D.w == 2.0f ); + const QAngle& ang = pRoot->GetValue<QAngle>( "qangle_test" ); + Shipping_Assert( ang.x == 0.0f && ang.y == 90.0f && ang.z == -90.0f ); + const Quaternion& quat = pRoot->GetValue<Quaternion>( "quat_test" ); + Shipping_Assert( quat.x == 1.0f && quat.y == -1.0f && quat.z == 0.0f && quat.w == 2.0f ); + + const VMatrix& mat = pRoot->GetValue<VMatrix>( "vmatrix_test" ); + Shipping_Assert( MatricesAreEqual( mat, mattest, 1e-3 ) ); + + Shipping_Assert( !Q_stricmp( pRoot->GetValueString( "string_test" ), "test" ) ); + const CUtlBinaryBlock& blob = pRoot->GetValue<CUtlBinaryBlock>( "binary_test" ); + Shipping_Assert( blob.Length() == 256 ); + Shipping_Assert( !memcmp( blob.Get(), buftest, 256 ) ); + + CDmxElement *pElement7 = pRoot->GetValue<CDmxElement*>( "element_test" ); + Shipping_Assert( pElement7 != NULL ); + CDmxElement *pElement6 = pRoot->GetValue<CDmxElement*>( "shared_element_test" ); + Shipping_Assert( pElement6 != NULL ); + const CUtlVector< CDmxElement* >& elementList = pRoot->GetArray<CDmxElement*>( "children" ); + Shipping_Assert( elementList.Count() == 2 ); + CDmxElement *pElement2 = elementList[0]; + CDmxElement *pElement3 = elementList[1]; + Shipping_Assert( pElement2 != NULL && pElement3 != NULL ); + Shipping_Assert( pElement7->GetValue<CDmxElement*>( "shared_element_test" ) == pElement6 ); + const CUtlVector< CDmxElement* >& elementList3 = pElement6->GetArray<CDmxElement*>( "element_array_test" ); + CDmxElement *pElement4 = elementList3[0]; + CDmxElement *pElement5 = elementList3[1]; + + const CUtlVector< bool > &boolVec = pElement2->GetArray<bool>( "bool_array_test" ); + Shipping_Assert( boolVec.Count() == 2 && boolVec[0] == false && boolVec[1] == true ); + + const CUtlVector< int > &intVec = pElement2->GetArray<int>( "int_array_test" ); + Shipping_Assert( intVec.Count() == 3 && intVec[0] == 0 && intVec[1] == 1 && intVec[2] == 2 ); + + const CUtlVector< float > &floatVec = pElement2->GetArray<float>( "float_array_test" ); + Shipping_Assert( floatVec.Count() == 3 && floatVec[0] == -1.0f && floatVec[1] == 0.0f && floatVec[2] == 1.0f ); + + const CUtlVector< Color > &colorVec = pElement3->GetArray<Color>( "color_array_test" ); + Shipping_Assert( colorVec.Count() == 3 && colorVec[0].r() == 0 && colorVec[1].r() == 64 && colorVec[2].r() == 128 ); + + const CUtlVector< Vector2D > &vec2DVec = pElement3->GetArray<Vector2D>( "vector2d_array_test" ); + Shipping_Assert( vec2DVec.Count() == 2 && vec2DVec[0].x == -1.0f && vec2DVec[1].x == 1.0f ); + + const CUtlVector< Vector > &vec3DVec = pElement3->GetArray<Vector>( "vector3d_array_test" ); + Shipping_Assert( vec3DVec.Count() == 2 && vec3DVec[0].x == 1.0f && vec3DVec[1].x == 2.0f ); + + const CUtlVector< Vector4D > &vec4DVec = pElement4->GetArray<Vector4D>( "vector4d_array_test" ); + Shipping_Assert( vec4DVec.Count() == 2 && vec4DVec[0].x == 1.0f && vec4DVec[1].x == 2.0f ); + + const CUtlVector< QAngle > &angVec = pElement4->GetArray<QAngle>( "qangle_array_test" ); + Shipping_Assert( angVec.Count() == 2 && angVec[0].x == 1.0f && angVec[1].x == 2.0f ); + + const CUtlVector< Quaternion > &quatVec = pElement4->GetArray<Quaternion>( "quat_array_test" ); + Shipping_Assert( quatVec.Count() == 2 && quatVec[0].x == 1.0f && quatVec[1].x == 2.0f ); + + const CUtlVector< VMatrix > &matVec = pElement5->GetArray<VMatrix>( "vmatrix_array_test" ); + Shipping_Assert( matVec.Count() == 2 ); + Shipping_Assert( MatricesAreEqual( matVec[0], mattest, 1e-3 ) ); + Shipping_Assert( MatricesAreEqual( matVec[1], mat2test, 1e-3 ) ); + + const CUtlVector< CUtlString > &stringVec = pElement5->GetArray<CUtlString>( "string_array_test" ); + Shipping_Assert( stringVec.Count() == 3 && !Q_stricmp( stringVec[2], "string3" ) ); + + const CUtlVector< CUtlBinaryBlock > &binaryVec = pElement5->GetArray<CUtlBinaryBlock>( "binary_array_test" ); + Shipping_Assert( binaryVec.Count() == 2 && !memcmp( binaryVec[1].Get(), buf2test, 256 ) ); + + const CUtlVector< DmObjectId_t > &idVec = pElement6->GetArray<DmObjectId_t>( "elementid_array_test" ); + Shipping_Assert( idVec.Count() == 3 ); + + TestStruct_t testStruct; + pRoot->UnpackIntoStructure( &testStruct, sizeof( testStruct ), s_TestStructUnpack ); + + Shipping_Assert( testStruct.m_bBool == true ); + Shipping_Assert( testStruct.m_nInt == 2 ); + AssertFloatEquals( testStruct.m_flFloat, 3.0f, 1e-3 ); + Shipping_Assert( testStruct.m_Color.r() == 0 && testStruct.m_Color.g() == 64 && testStruct.m_Color.b() == 128 && testStruct.m_Color.a() == 255 ); + Shipping_Assert( testStruct.m_Vector2D.x == 1.0f && testStruct.m_Vector2D.y == -1.0f ); + Shipping_Assert( testStruct.m_Vector3D.x == 1.0f && testStruct.m_Vector3D.y == -1.0f && testStruct.m_Vector3D.z == 0.0f ); + Shipping_Assert( testStruct.m_Vector4D.x == 1.0f && testStruct.m_Vector4D.y == -1.0f && testStruct.m_Vector4D.z == 0.0f && testStruct.m_Vector4D.w == 2.0f ); + Shipping_Assert( testStruct.m_Angles.x == 0.0f && testStruct.m_Angles.y == 90.0f && testStruct.m_Angles.z == -90.0f ); + Shipping_Assert( testStruct.m_Quaternion.x == 1.0f && testStruct.m_Quaternion.y == -1.0f && testStruct.m_Quaternion.z == 0.0f && testStruct.m_Quaternion.w == 2.0f ); + Shipping_Assert( MatricesAreEqual( testStruct.m_Matrix, mattest, 1e-3 ) ); + Shipping_Assert( !Q_stricmp( testStruct.m_pStringBuf, "test" ) ); + + pElement6->UnpackIntoStructure( &testStruct, sizeof( testStruct ), s_TestStructUnpack ); + + Shipping_Assert( testStruct.m_bBool == true ); + Shipping_Assert( testStruct.m_nInt == 5 ); + AssertFloatEquals( testStruct.m_flFloat, 4.0f, 1e-3 ); + Shipping_Assert( testStruct.m_Color.r() == 200 && testStruct.m_Color.g() == 200 && testStruct.m_Color.b() == 200 && testStruct.m_Color.a() == 200 ); + Shipping_Assert( testStruct.m_Vector2D.x == 5.0f && testStruct.m_Vector2D.y == 1.0f ); + Shipping_Assert( testStruct.m_Vector3D.x == 5.0f && testStruct.m_Vector3D.y == 1.0f && testStruct.m_Vector3D.z == -3.0f ); + Shipping_Assert( testStruct.m_Vector4D.x == 5.0f && testStruct.m_Vector4D.y == 1.0f && testStruct.m_Vector4D.z == -4.0f && testStruct.m_Vector4D.w == 2.0f ); + Shipping_Assert( testStruct.m_Angles.x == 5.0f && testStruct.m_Angles.y == 1.0f && testStruct.m_Angles.z == -3.0f ); + Shipping_Assert( testStruct.m_Quaternion.x == 5.0f && testStruct.m_Quaternion.y == 1.0f && testStruct.m_Quaternion.z == -4.0f && testStruct.m_Quaternion.w == 2.0f ); + Shipping_Assert( !Q_stricmp( testStruct.m_pStringBuf, "default" ) ); +} + +DEFINE_TESTCASE_NOSUITE( DmxLoaderTest ) +{ + Msg( "Running dmx loader tests...\n" ); + + CDmxElement *pRoot; + bool bOk = UnserializeDMX( "dmxtestloader.dmx", NULL, false, &pRoot ); + Shipping_Assert( bOk ); + Shipping_Assert( pRoot ); + if ( pRoot ) + { + TestReadFile( pRoot ); + CleanupDMX( pRoot ); + } + + bOk = UnserializeDMX( "dmxtestloadertext.dmx", NULL, true, &pRoot ); + Shipping_Assert( bOk ); + Shipping_Assert( pRoot ); + if ( pRoot ) + { + TestReadFile( pRoot ); + CleanupDMX( pRoot ); + } + + // Test serialization + bOk = UnserializeDMX( "dmxtestloader.dmx", NULL, false, &pRoot ); + Shipping_Assert( bOk ); + Shipping_Assert( pRoot ); + if ( pRoot ) + { + bOk = SerializeDMX( "dmxtestscratch.dmx", NULL, false, pRoot ); + Shipping_Assert( bOk ); + CleanupDMX( pRoot ); + } + CleanupDMX( pRoot ); + + bOk = UnserializeDMX( "dmxtestscratch.dmx", NULL, false, &pRoot ); + Shipping_Assert( bOk ); + Shipping_Assert( pRoot ); + if ( pRoot ) + { + TestReadFile( pRoot ); + CleanupDMX( pRoot ); + } +} diff --git a/unittests/dmxtest/dmxtestnotify.cpp b/unittests/dmxtest/dmxtestnotify.cpp new file mode 100644 index 0000000..e5a24be --- /dev/null +++ b/unittests/dmxtest/dmxtestnotify.cpp @@ -0,0 +1,111 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for DMX testing (testing the Notify subsystem) +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "datamodel/dmelement.h" +#include "datamodel/idatamodel.h" +#include "tier1/utlbuffer.h" +#include "filesystem.h" +#include "datamodel/dmehandle.h" +#include "tier2/tier2.h" + +class CNotifyTest : public IDmNotify +{ +public: + CNotifyTest() : m_nValueCount(0), m_nTopologyCount(0), m_nArrayCount(0) {} + + virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) + { + if ( nNotifyFlags & NOTIFY_CHANGE_ATTRIBUTE_VALUE ) + { + m_nValueCount++; + } + if ( nNotifyFlags & NOTIFY_CHANGE_ATTRIBUTE_ARRAY_SIZE ) + { + m_nArrayCount++; + } + if ( nNotifyFlags & NOTIFY_CHANGE_TOPOLOGICAL ) + { + m_nTopologyCount++; + } + } + + int m_nTopologyCount; + int m_nArrayCount; + int m_nValueCount; +}; + + +DEFINE_TESTCASE_NOSUITE( DmxNotifyTest ) +{ + Msg( "Running dmx notify tests...\n" ); + + CNotifyTest test1, test2; + + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<RunNotifyTests>" ); + + g_pDataModel->InstallNotificationCallback( &test1 ); + + CDmElement *element = NULL; + + { + CUndoScopeGuard guard( NOTIFY_SOURCE_APPLICATION, 0, "create" ); + element = CreateElement< CDmElement >( "test", fileid ); + } + + Shipping_Assert( test1.m_nTopologyCount == 1 ); + Shipping_Assert( test1.m_nArrayCount == 0 ); + + g_pDataModel->Undo(); + + Shipping_Assert( test1.m_nTopologyCount == 2 ); + Shipping_Assert( test1.m_nArrayCount == 0 ); + + { + CNotifyScopeGuard notify( "test1", NOTIFY_SOURCE_APPLICATION, 0, &test2 ); + CDisableUndoScopeGuard guard; + element = CreateElement< CDmElement >( "test", fileid ); + } + + Shipping_Assert( test1.m_nTopologyCount == 3 ); + Shipping_Assert( test1.m_nArrayCount == 0 ); + Shipping_Assert( test2.m_nTopologyCount == 1 ); + Shipping_Assert( test2.m_nArrayCount == 0 ); + + { + CDisableUndoScopeGuard guard; + + // NOTE: Nested scope guards referring to the same callback shouldn't double call it + CNotifyScopeGuard notify( "test2", NOTIFY_SOURCE_APPLICATION, 0, &test2 ); + { + CNotifyScopeGuard notify( "test3", NOTIFY_SOURCE_APPLICATION, 0, &test2 ); + DestroyElement( element ); + } + } + + Shipping_Assert( test1.m_nTopologyCount == 4 ); + Shipping_Assert( test1.m_nArrayCount == 0 ); + Shipping_Assert( test2.m_nTopologyCount == 2 ); + Shipping_Assert( test2.m_nArrayCount == 0 ); + + { + CUndoScopeGuard guard( NOTIFY_SOURCE_APPLICATION, 0, "create" ); + { + element = CreateElement< CDmElement >( "test", fileid ); + element->SetValue( "test", 1.0f ); + } + guard.Abort(); + } + + Shipping_Assert( test1.m_nTopologyCount == 4 ); + Shipping_Assert( test1.m_nArrayCount == 0 ); + Shipping_Assert( test2.m_nTopologyCount == 2 ); + Shipping_Assert( test2.m_nArrayCount == 0 ); + + g_pDataModel->RemoveNotificationCallback( &test1 ); + g_pDataModel->RemoveFileId( fileid ); +} diff --git a/unittests/dmxtest/dmxtestserialization.cpp b/unittests/dmxtest/dmxtestserialization.cpp new file mode 100644 index 0000000..57bd323 --- /dev/null +++ b/unittests/dmxtest/dmxtestserialization.cpp @@ -0,0 +1,760 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for DMX testing +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "datamodel/dmelement.h" +#include "datamodel/idatamodel.h" +#include "tier1/utlbuffer.h" +#include "filesystem.h" +#include "datamodel/dmehandle.h" +#include "tier2/tier2.h" + +bool AssertEqualElementHierarchies( bool quiet, DmElementHandle_t src1, DmElementHandle_t src2 ); +bool AssertUnEqualElementHierarchies( DmElementHandle_t src1, DmElementHandle_t src2 ) +{ + bool equal = AssertEqualElementHierarchies( true, src1, src2 ); + if ( equal ) + { + AssertMsg( 0, "Hierarchies equal, expecting mismatch\n" ); + } + return !equal; +} + + +void CreateTestScene( CUtlVector< DmElementHandle_t >& handles, DmFileId_t fileid ) +{ + DmObjectId_t id; + CreateUniqueId( &id ); + + VMatrix mat, mat2; + MatrixBuildRotateZ( mat, 45 ); + MatrixBuildRotateZ( mat2, 30 ); + + int i; + unsigned char buf[256]; + unsigned char buf2[256]; + for ( i = 0; i < 256; ++i ) + { + buf[i] = i; + buf2[i] = 255 - i; + } + + CDmElement *pElement = CreateElement<CDmElement>( "root", fileid ); + Assert( pElement ); + CDmElement *pElement2 = CreateElement<CDmElement>( "shared_child", fileid ); + Assert( pElement2 ); + CDmElement *pElement3 = CreateElement<CDmElement>( "unique_child", fileid ); + Assert( pElement3 ); + CDmElement *pElement4 = CreateElement<CDmElement>( "shared_array_element", fileid ); + Assert( pElement4 ); + CDmElement *pElement5 = CreateElement<CDmElement>( "unique_array_element", fileid ); + Assert( pElement5 ); + CDmElement *pElement6 = CreateElement<CDmElement>( "shared_element", fileid ); + Assert( pElement6 ); + CDmElement *pElement7 = CreateElement<CDmElement>( "unique_element", fileid ); + Assert( pElement7 ); + + g_pDataModel->SetFileRoot( fileid, pElement->GetHandle() ); + + handles.AddToTail( pElement->GetHandle() ); + handles.AddToTail( pElement2->GetHandle() ); + handles.AddToTail( pElement3->GetHandle() ); + handles.AddToTail( pElement4->GetHandle() ); + handles.AddToTail( pElement5->GetHandle() ); + handles.AddToTail( pElement6->GetHandle() ); + handles.AddToTail( pElement7->GetHandle() ); + + pElement->SetValue( "id_test", id ); + pElement->SetValue( "bool_test", true ); + pElement->SetValue( "int_test", 2 ); + pElement->SetValue( "float_test", 3.0f ); + pElement->SetValue( "color_test", Color( 0, 64, 128, 255 ) ); + pElement->SetValue( "vector2d_test", Vector2D( 1.0f, -1.0f ) ); + pElement->SetValue( "vector3d_test", Vector( 1.0f, -1.0f, 0.0f ) ); + pElement->SetValue( "vector4d_test", Vector4D( 1.0f, -1.0f, 0.0f, 2.0f ) ); + pElement->SetValue( "qangle_test", QAngle( 0.0f, 90.0f, -90.0f ) ); + pElement->SetValue( "quat_test", Quaternion( 1.0f, -1.0f, 0.0f, 2.0f ) ); + pElement->SetValue( "vmatrix_test", mat ); + pElement->SetValue( "string_test", "test" ); + pElement->SetValue( "binary_test", buf, 256 ); + + // Test DONTSAVE +// pElement->SetValue( "dontsave", true ); +// CDmAttribute *pAttribute = pElement->GetAttribute( "dontsave" ); +// pAttribute->AddFlag( FATTRIB_DONTSAVE ); + + CDmrArray< bool > boolVec( pElement2, "bool_array_test", true ); + boolVec.AddToTail( false ); + boolVec.AddToTail( true ); + + CDmrArray< int > intVec( pElement2, "int_array_test", true ); + intVec.AddToTail( 0 ); + intVec.AddToTail( 1 ); + intVec.AddToTail( 2 ); + + CDmrArray< float > floatVec( pElement2, "float_array_test", true ); + floatVec.AddToTail( -1.0f ); + floatVec.AddToTail( 0.0f ); + floatVec.AddToTail( 1.0f ); + + CDmrArray< Color > colorVec( pElement3, "color_array_test", true ); + colorVec.AddToTail( Color( 0, 0, 0, 255 ) ); + colorVec.AddToTail( Color( 64, 64, 64, 255 ) ); + colorVec.AddToTail( Color( 128, 128, 128, 255 ) ); + + CDmrArray< Vector2D > vector2DVec( pElement3, "vector2d_array_test", true ); + vector2DVec.AddToTail( Vector2D( -1.0f, -1.0f ) ); + vector2DVec.AddToTail( Vector2D( 1.0f, 1.0f ) ); + + CDmrArray< Vector > vector3DVec( pElement3, "vector3d_array_test", true ); + vector3DVec.AddToTail( Vector( 1.0f, -1.0f, 0.0f ) ); + vector3DVec.AddToTail( Vector( 2.0f, -2.0f, 0.0f ) ); + + CDmrArray< Vector4D > vector4DVec( pElement4, "vector4d_array_test", true ); + vector4DVec.AddToTail( Vector4D( 1.0f, -1.0f, 0.0f, 2.0f ) ); + vector4DVec.AddToTail( Vector4D( 2.0f, -2.0f, 0.0f, 4.0f ) ); + + CDmrArray< QAngle > angleVec( pElement4, "qangle_array_test", true ); + angleVec.AddToTail( QAngle( 1.0f, -1.0f, 0.0f ) ); + angleVec.AddToTail( QAngle( 2.0f, -2.0f, 0.0f ) ); + + CDmrArray< Quaternion > quatVec( pElement4, "quat_array_test", true ); + quatVec.AddToTail( Quaternion( 1.0f, -1.0f, 0.0f, 2.0f ) ); + quatVec.AddToTail( Quaternion( 2.0f, -2.0f, 0.0f, 4.0f ) ); + + CDmrArray< VMatrix > matVec( pElement5, "vmatrix_array_test", true ); + matVec.AddToTail( mat ); + matVec.AddToTail( mat2 ); + + CDmrStringArray stringVec( pElement5, "string_array_test", true ); + stringVec.AddToTail( "string1" ); + stringVec.AddToTail( "string2" ); + stringVec.AddToTail( "string3" ); + + CDmrArray< CUtlBinaryBlock > binaryVec( pElement5, "binary_array_test", true ); + CUtlBinaryBlock block( (const void *)buf, 256 ); + i = binaryVec.AddToTail( block ); + CUtlBinaryBlock block2( (const void *)buf2, 256 ); + i = binaryVec.AddToTail( block2); + + CDmrArray< DmObjectId_t > idVec( pElement6, "elementid_array_test", true ); + i = idVec.AddToTail( pElement6->GetId() ); + i = idVec.AddToTail( pElement5->GetId() ); + i = idVec.AddToTail( pElement4->GetId() ); + + CDmrElementArray< > elementVec( pElement6, "element_array_test", true ); + elementVec.AddToTail( pElement4 ); + elementVec.AddToTail( pElement5 ); + + CDmrElementArray< > elementVec2( pElement7, "element_array_test", true ); + elementVec2.AddToTail( pElement2 ); + elementVec2.AddToTail( pElement4 ); + + pElement->SetValue( "element_test", pElement7 ); + pElement->SetValue( "shared_element_test", pElement6 ); + CDmrElementArray<> children( pElement, "children", true ); + children.InsertBefore( 0, pElement2 ); + children.InsertBefore( 1, pElement3 ); + + pElement7->SetValue( "shared_element_test", pElement6 ); + CDmrElementArray<> children2( pElement7, "children", true ); + children2.InsertBefore( 0, pElement2 ); +} + +DmElementHandle_t CreateTestScene( DmFileId_t fileid ) +{ + CUtlVector< DmElementHandle_t > handles; + CreateTestScene( handles, fileid ); + return handles[ 0 ]; +} + +DmElementHandle_t CreateKeyValuesTestScene( DmFileId_t fileid ) +{ + CDmElement *pElement = CreateElement<CDmElement>( "root", fileid ); + Assert( pElement ); + CDmElement *pElement2 = CreateElement<CDmElement>( "shared_child", fileid ); + Assert( pElement2 ); + CDmElement *pElement3 = CreateElement<CDmElement>( "unique_child", fileid ); + Assert( pElement3 ); + CDmElement *pElement4 = CreateElement<CDmElement>( "shared_array_element", fileid ); + Assert( pElement4 ); + CDmElement *pElement5 = CreateElement<CDmElement>( "unique_array_element", fileid ); + Assert( pElement5 ); + CDmElement *pElement6 = CreateElement<CDmElement>( "shared_element", fileid ); + Assert( pElement6 ); + CDmElement *pElement7 = CreateElement<CDmElement>( "unique_element", fileid ); + Assert( pElement7 ); + + g_pDataModel->SetFileRoot( fileid, pElement->GetHandle() ); + + pElement->SetValue( "int_test", 2 ); + pElement->SetValue( "float_test", 3.0f ); + pElement->SetValue( "string_test", "test" ); + + CDmrElementArray<> eVec( pElement6, "element_array_test", true ); + eVec.AddToTail( pElement4 ); + eVec.AddToTail( pElement5 ); + + CDmrElementArray<> eVec2( pElement7, "element_array_test", true ); + eVec2.AddToTail( pElement2 ); + eVec2.AddToTail( pElement4 ); + + pElement->SetValue( "element_test", pElement7 ); + pElement->SetValue( "shared_element_test", pElement6 ); + CDmrElementArray<> children( pElement, "children", true ); + children.InsertBefore( 0, pElement2 ); + children.InsertBefore( 1, pElement3 ); + + pElement7->SetValue( "shared_element_test", pElement6 ); + CDmrElementArray<> children2( pElement7, "children", true ); + children2.InsertBefore( 0, pElement2 ); + + return pElement->GetHandle(); +} + +template< class T > +bool AssertEqualsTest( bool quiet, const T& src1, const T& src2 ) +{ + if ( !( src1 == src2 )) + { + if ( !quiet ) + { + AssertMsg( 0, "Results not equal, expecting equal\n" ); + } + return false; + } + return true; +} + +template< class T > +bool AssertEqualsUtlVector( bool quiet, const CUtlVector<T> &src1, const CUtlVector<T> &src2 ) +{ + bool retval = true; + if ( src1.Count() != src2.Count() ) + { + if ( !quiet ) + { + AssertEqualsTest( quiet, src1.Count(), src2.Count() ); + } + retval = false; + } + + for ( int i = 0; i < src1.Count(); ++i ) + { + if ( !src2.IsValidIndex( i ) ) + continue; + + if ( !( src1[i] == src2[i] ) ) + { + if ( !quiet ) + { + AssertEqualsTest( quiet, src1[i], src2[i] ); + } + retval = false; + } + } + return retval; +} + +template< class T > +bool AssertEqualsUtlVector( bool quiet, CDmAttribute *pAttribute1, CDmAttribute *pAttribute2 ) +{ + CDmrArray<T> src1( pAttribute1 ); + CDmrArray<T> src2( pAttribute2 ); + return AssertEqualsUtlVector( quiet, src1.Get(), src2.Get() ); +} + +bool AssertEqualAttributes( bool quiet, CDmAttribute *pAttribute1, CDmAttribute *pAttribute2 ) +{ + // Always follow ptrs to elements... + if ( pAttribute1->GetType() != AT_ELEMENT_ARRAY && + pAttribute1->GetType() != AT_ELEMENT ) + { + // Dirty flag checking here is to avoid infinite recursive loops + if ( !pAttribute1->IsFlagSet( FATTRIB_DIRTY ) && !pAttribute2->IsFlagSet( FATTRIB_DIRTY ) ) + return true; + } + + if ( !pAttribute1 ) + { + if ( !quiet ) + { + AssertMsg( 0, "AssertEqualAttributes: pAttribute1 is NULL\n" ); + } + return false; + } + + + if ( !pAttribute2 ) + { + if ( !quiet ) + { + AssertMsg( 0, "AssertEqualAttributes: pAttribute2 is NULL\n" ); + } + return false; + } + + bool retval = true; + + pAttribute1->RemoveFlag( FATTRIB_DIRTY ); + pAttribute2->RemoveFlag( FATTRIB_DIRTY ); + + if ( pAttribute1->GetType() != pAttribute2->GetType() ) + { + if ( !quiet ) + { + AssertMsg( 0, "pAttribute1->GetType() == pAttribute2->GetType()" ); + } + retval = false; + } + + switch( pAttribute1->GetType() ) + { + case AT_INT: + return AssertEqualsTest( quiet, pAttribute1->GetValue<int>( ), pAttribute2->GetValue<int>( ) ); + + case AT_FLOAT: + return AssertEqualsTest( quiet, pAttribute1->GetValue<float>( ), pAttribute2->GetValue<float>( ) ); + + case AT_BOOL: + return AssertEqualsTest( quiet, pAttribute1->GetValue<bool>( ), pAttribute2->GetValue<bool>( ) ); + + case AT_STRING: + return AssertEqualsTest( quiet, pAttribute1->GetValue<CUtlString>( ), pAttribute2->GetValue<CUtlString>( ) ); + + case AT_VOID: + return AssertEqualsTest( quiet, pAttribute1->GetValue<CUtlBinaryBlock>( ), pAttribute2->GetValue<CUtlBinaryBlock>( ) ); + + case AT_OBJECTID: + return true; // skip this for now - two elements can't have the same id, and CreateTestScene currently creates random test_id's each time... +/* + { + if ( !g_pDataModel->IsEqual( pAttribute1->GetValue<DmObjectId_t>( ), pAttribute2->GetValue<DmObjectId_t>( ) ) ) + { + if ( !quiet ) + { + Assert( g_pDataModel->IsEqual( pAttribute1->GetValue<DmObjectId_t>( ), pAttribute2->GetValue<DmObjectId_t>( ) ) ); + } + return false; + } + return true; + } + break; +*/ + + case AT_COLOR: + return AssertEqualsTest( quiet, pAttribute1->GetValue<Color>( ), pAttribute2->GetValue<Color>( ) ); + + case AT_VECTOR2: + return AssertEqualsTest( quiet, pAttribute1->GetValue<Vector2D>( ), pAttribute2->GetValue<Vector2D>( ) ); + + case AT_VECTOR3: + return AssertEqualsTest( quiet, pAttribute1->GetValue<Vector>( ), pAttribute2->GetValue<Vector>( ) ); + + case AT_VECTOR4: + return AssertEqualsTest( quiet, pAttribute1->GetValue<Vector4D>( ), pAttribute2->GetValue<Vector4D>( ) ); + + case AT_QANGLE: + return AssertEqualsTest( quiet, pAttribute1->GetValue<QAngle>( ), pAttribute2->GetValue<QAngle>( ) ); + + case AT_QUATERNION: + return AssertEqualsTest( quiet, pAttribute1->GetValue<Quaternion>( ), pAttribute2->GetValue<Quaternion>( ) ); + + case AT_VMATRIX: + return AssertEqualsTest( quiet, pAttribute1->GetValue<VMatrix>( ), pAttribute2->GetValue<VMatrix>( ) ); + + case AT_ELEMENT: + return AssertEqualElementHierarchies( quiet, pAttribute1->GetValue<DmElementHandle_t>( ), pAttribute2->GetValue<DmElementHandle_t>( ) ); + + case AT_ELEMENT_ARRAY: + { + const CDmrElementArray< CDmElement > src1( pAttribute1 ); + const CDmrElementArray< CDmElement > src2( pAttribute2 ); + + bool differs = !AssertEqualsTest( quiet, src1.Count(), src2.Count() ); + bool differs2 = false; + for ( int i = 0; i < src1.Count(); ++i ) + { + differs2 |= !AssertEqualElementHierarchies( quiet, src1[ i ]->GetHandle(), src2[ i ]->GetHandle() ); + } + + return ( !differs && !differs2 ); + } + break; + + case AT_INT_ARRAY: + return AssertEqualsUtlVector<int>( quiet, pAttribute1, pAttribute2 ); + + case AT_FLOAT_ARRAY: + return AssertEqualsUtlVector<float>( quiet, pAttribute1, pAttribute2 ); + + case AT_BOOL_ARRAY: + return AssertEqualsUtlVector<bool>( quiet, pAttribute1, pAttribute2 ); + + case AT_STRING_ARRAY: + return AssertEqualsUtlVector<CUtlString>( quiet, pAttribute1, pAttribute2 ); + + case AT_VOID_ARRAY: + return AssertEqualsUtlVector<CUtlBinaryBlock>( quiet, pAttribute1, pAttribute2 ); + + case AT_OBJECTID_ARRAY: + { + const CDmrArray<DmObjectId_t> src1( pAttribute1 ); + const CDmrArray<DmObjectId_t> src2( pAttribute2 ); + + bool differs = AssertEqualsTest( quiet, src1.Count(), src2.Count() ); + return differs; // skip this for now - CreateTestScene currently creates random ids each time... +/* + bool differs2 = false; + for ( int i = 0; i < src1.Count(); ++i ) + { + if ( !g_pDataModel->IsEqual( src1[i], src2[i] ) ) + { + differs2 = true; + if ( !quiet ) + { + Assert( g_pDataModel->IsEqual( src1[i], src2[i] ) ); + } + } + } + + return ( !differs && !differs2 ); +*/ + } + break; + + case AT_COLOR_ARRAY: + return AssertEqualsUtlVector<Color>( quiet, pAttribute1, pAttribute2 ); + + case AT_VECTOR2_ARRAY: + return AssertEqualsUtlVector<Vector2D>( quiet, pAttribute1, pAttribute2 ); + + case AT_VECTOR3_ARRAY: + return AssertEqualsUtlVector<Vector>( quiet, pAttribute1, pAttribute2 ); + + case AT_VECTOR4_ARRAY: + return AssertEqualsUtlVector<Vector4D>( quiet, pAttribute1, pAttribute2 ); + + case AT_QANGLE_ARRAY: + return AssertEqualsUtlVector<QAngle>( quiet, pAttribute1, pAttribute2 ); + + case AT_QUATERNION_ARRAY: + return AssertEqualsUtlVector<Quaternion>( quiet, pAttribute1, pAttribute2 ); + + case AT_VMATRIX_ARRAY: + return AssertEqualsUtlVector<VMatrix>( quiet, pAttribute1, pAttribute2 ); + } + + return retval; +} + +bool AssertEqualElementHierarchies( bool quiet, DmElementHandle_t src1, DmElementHandle_t src2 ) +{ + CDmElement *pSrc1 = g_pDataModel->GetElement( src1 ); + CDmElement *pSrc2 = g_pDataModel->GetElement( src2 ); + + if ( !pSrc1 || !pSrc2 ) + return false; + + // Assume equality + bool retval = true; + + if ( pSrc1->GetType() != pSrc2->GetType() ) + { + if ( !quiet ) + { + AssertMsg( 0, "pSrc1->GetType() == pSrc2->GetType()" ); + } + retval = false; + } + + if ( Q_strcmp( pSrc1->GetName(), pSrc2->GetName() ) ) + { + if ( !quiet ) + { + AssertMsg2( 0, "Q_strcmp( %s, %s )", pSrc1->GetName(), pSrc2->GetName() ); + } + retval = false; + } + + if ( pSrc1->AttributeCount() != pSrc2->AttributeCount() ) + { + if ( !quiet ) + { + AssertMsg( 0, "pSrc1->NumAttributes() == pSrc2->NumAttributes()" ); + } + retval = false; + } + + for ( CDmAttribute *pAttribute1 = pSrc1->FirstAttribute(); pAttribute1; pAttribute1 = pAttribute1->NextAttribute() ) + { + const char *pName = pAttribute1->GetName(); + if ( !pSrc2->HasAttribute( pName ) ) + { + if ( !quiet ) + { + AssertMsg1( 0, "pSrc2->HasAttribute( %s ) failed\n", pName ); + } + retval = false; + } + else + { + CDmAttribute *pAttribute2 = pSrc2->GetAttribute( pName ); + + bool differs = !AssertEqualAttributes( quiet, pAttribute1, pAttribute2 ); + if ( differs ) + { + retval = false; + } + } + } + + return retval; +} + +void TestDeleteOldCR( const char *pSerializationType ) +{ + DmFileId_t testFileID = g_pDataModel->FindOrCreateFileId( "<TestDeleteOldCR>" ); + DmElementHandle_t hRoot = CreateTestScene( testFileID ); + + int nTestElements = g_pDataModel->NumElementsInFile( testFileID ); + + const char *pFileName = "DeleteOld.dmx"; + CDmElement *pRoot = static_cast< CDmElement* >( g_pDataModel->GetElement( hRoot ) ); + bool bOk = g_pDataModel->SaveToFile( pFileName, NULL, pSerializationType, "dmx", pRoot ); + Shipping_Assert( bOk ); + + CDmElement *pReadInRoot = NULL; + DmFileId_t readFileID = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pReadInRoot, CR_DELETE_OLD ); + Shipping_Assert( readFileID != DMFILEID_INVALID ); + + if ( pReadInRoot ) + { + Shipping_Assert( pReadInRoot->GetHandle() == hRoot ); + Shipping_Assert( g_pDataModel->GetElement( hRoot ) == pReadInRoot ); + Shipping_Assert( g_pDataModel->NumElementsInFile( testFileID ) == 0 ); + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == nTestElements ); + + CDmeHandle< CDmElement > rootHandle( hRoot ); // keeps a reference to root around, even after the file is unloaded + g_pDataModel->UnloadFile( readFileID ); + + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == 0 ); + Shipping_Assert( g_pDataModel->GetElement( hRoot ) == NULL ); + + DmFileId_t readFileID2 = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pReadInRoot, CR_DELETE_OLD ); + Shipping_Assert( readFileID2 == readFileID ); + + Shipping_Assert( pReadInRoot->GetHandle() == hRoot ); + Shipping_Assert( g_pDataModel->GetElement( hRoot ) == pReadInRoot ); + Shipping_Assert( g_pDataModel->NumElementsInFile( testFileID ) == 0 ); + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == nTestElements ); + + g_pDataModel->RemoveFileId( readFileID ); + } + else + { + Msg( "Failed to load %s back from disk!!!", pFileName ); + } + + g_pDataModel->RemoveFileId( testFileID ); +} + +void TestDeleteNewCR( const char *pSerializationType ) +{ + DmFileId_t testFileID = g_pDataModel->FindOrCreateFileId( "<TestDeleteNewCR>" ); + DmElementHandle_t hRoot = CreateTestScene( testFileID ); + + int nTestElements = g_pDataModel->NumElementsInFile( testFileID ); + + const char *pFileName = "DeleteNew.dmx"; + CDmElement *pRoot = static_cast< CDmElement* >( g_pDataModel->GetElement( hRoot ) ); + bool bOk = g_pDataModel->SaveToFile( pFileName, NULL, pSerializationType, "dmx", pRoot ); + Shipping_Assert( bOk ); + + CDmElement *pReadInRoot = NULL; + DmFileId_t readFileID = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pReadInRoot, CR_DELETE_NEW ); + Shipping_Assert( readFileID != DMFILEID_INVALID ); + + Shipping_Assert( g_pDataModel->GetElement( hRoot ) == pRoot ); + Shipping_Assert( pRoot->GetHandle() == hRoot ); + Shipping_Assert( pReadInRoot == pRoot ); // RestoreFromFile now returns the old element when the new root is deleted + Shipping_Assert( g_pDataModel->NumElementsInFile( testFileID ) == nTestElements ); + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == 0 ); + + g_pDataModel->UnloadFile( readFileID ); + + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == 0 ); + + DmFileId_t readFileID2 = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pReadInRoot, CR_DELETE_NEW ); + Shipping_Assert( readFileID2 == readFileID ); + + Shipping_Assert( g_pDataModel->GetElement( hRoot ) == pRoot ); + Shipping_Assert( pRoot->GetHandle() == hRoot ); + Shipping_Assert( pReadInRoot == pRoot ); // RestoreFromFile now returns the old element when the new root is deleted + Shipping_Assert( g_pDataModel->NumElementsInFile( testFileID ) == nTestElements ); + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == 0 ); + + g_pDataModel->RemoveFileId( readFileID ); + + g_pDataModel->RemoveFileId( testFileID ); +} + +void TestCopyNewCR( const char *pSerializationType ) +{ + DmFileId_t testFileID = g_pDataModel->FindOrCreateFileId( "<TestCopyNewCR>" ); + DmElementHandle_t hRoot = CreateTestScene( testFileID ); + + int nTestElements = g_pDataModel->NumElementsInFile( testFileID ); + + const char *pFileName = "CopyNew.dmx"; + CDmElement *pRoot = g_pDataModel->GetElement( hRoot ); + bool bOk = g_pDataModel->SaveToFile( pFileName, NULL, pSerializationType, "dmx", pRoot ); + Shipping_Assert( bOk ); + + CDmElement *pReadInRoot = NULL; + DmFileId_t readFileID = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pReadInRoot, CR_COPY_NEW ); + Shipping_Assert( readFileID != DMFILEID_INVALID ); + + if ( pReadInRoot ) + { + DmElementHandle_t hReadInRoot = pReadInRoot->GetHandle(); + + Shipping_Assert( g_pDataModel->GetElement( hRoot ) == pRoot ); + Shipping_Assert( pRoot->GetHandle() == hRoot ); + Shipping_Assert( pReadInRoot->GetHandle() != hRoot ); + Shipping_Assert( !IsUniqueIdEqual( pRoot->GetId(), pReadInRoot->GetId() ) ); + Shipping_Assert( g_pDataModel->NumElementsInFile( testFileID ) == nTestElements ); + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == nTestElements ); + + g_pDataModel->UnloadFile( readFileID ); + + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == 0 ); + Shipping_Assert( g_pDataModel->GetElement( hReadInRoot ) == NULL ); + + DmFileId_t readFileID2 = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pReadInRoot, CR_COPY_NEW ); + Shipping_Assert( readFileID2 == readFileID ); + + Shipping_Assert( g_pDataModel->GetElement( hRoot ) == pRoot ); + Shipping_Assert( pRoot->GetHandle() == hRoot ); + Shipping_Assert( pReadInRoot->GetHandle() != hRoot ); + Shipping_Assert( !IsUniqueIdEqual( pRoot->GetId(), pReadInRoot->GetId() ) ); + Shipping_Assert( g_pDataModel->NumElementsInFile( testFileID ) == nTestElements ); + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == nTestElements ); + + g_pDataModel->RemoveFileId( readFileID ); + } + else + { + Msg( "Failed to load %s back from disk!!!", pFileName ); + } + + g_pDataModel->RemoveFileId( testFileID ); +} + +void TestForceCopyCR( const char *pSerializationType ) +{ + DmFileId_t testFileID = g_pDataModel->FindOrCreateFileId( "<TestForceCopyCR>" ); + DmElementHandle_t hRoot = CreateTestScene( testFileID ); + + int nTestElements = g_pDataModel->NumElementsInFile( testFileID ); + + const char *pFileName = "ForceCopy.dmx"; + CDmElement *pRoot = static_cast< CDmElement* >( g_pDataModel->GetElement( hRoot ) ); + bool bOk = g_pDataModel->SaveToFile( pFileName, NULL, pSerializationType, "dmx", pRoot ); + Shipping_Assert( bOk ); + + CDmElement *pReadInRoot = NULL; + DmFileId_t readFileID = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pReadInRoot, CR_FORCE_COPY ); + Shipping_Assert( readFileID != DMFILEID_INVALID ); + + if ( pReadInRoot ) + { + DmElementHandle_t hReadInRoot = pReadInRoot->GetHandle(); + + Shipping_Assert( g_pDataModel->GetElement( hRoot ) == pRoot ); + Shipping_Assert( pRoot->GetHandle() == hRoot ); + Shipping_Assert( pReadInRoot->GetHandle() != hRoot ); + Shipping_Assert( !IsUniqueIdEqual( pRoot->GetId(), pReadInRoot->GetId() ) ); + Shipping_Assert( g_pDataModel->NumElementsInFile( testFileID ) == nTestElements ); + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == nTestElements ); + + g_pDataModel->UnloadFile( readFileID ); + + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == 0 ); + Shipping_Assert( g_pDataModel->GetElement( hReadInRoot ) == NULL ); + + DmFileId_t readFileID2 = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pReadInRoot, CR_FORCE_COPY ); + Shipping_Assert( readFileID2 == readFileID ); + + Shipping_Assert( g_pDataModel->GetElement( hRoot ) == pRoot ); + Shipping_Assert( pRoot->GetHandle() == hRoot ); + Shipping_Assert( pReadInRoot->GetHandle() != hRoot ); + Shipping_Assert( !IsUniqueIdEqual( pRoot->GetId(), pReadInRoot->GetId() ) ); + Shipping_Assert( g_pDataModel->NumElementsInFile( testFileID ) == nTestElements ); + Shipping_Assert( g_pDataModel->NumElementsInFile( readFileID ) == nTestElements ); + + g_pDataModel->RemoveFileId( readFileID ); + } + else + { + Msg( "Failed to load %s back from disk!!!", pFileName ); + } + + g_pDataModel->RemoveFileId( testFileID ); +} + +void TestConflictResolution( const char *pSerializationType ) +{ + TestDeleteOldCR( pSerializationType ); + TestDeleteNewCR( pSerializationType ); + TestCopyNewCR( pSerializationType ); + TestForceCopyCR( pSerializationType ); +} + +void TestSerializationMethod( const char *pSerializationType ) +{ + DmFileId_t testFileID = g_pDataModel->FindOrCreateFileId( "<CreateTestScene>" ); + DmElementHandle_t hRoot = CreateTestScene( testFileID ); + + const char *pFileName = "dmxtest.dmx"; + CDmElement *pRoot = static_cast<CDmElement*>(g_pDataModel->GetElement(hRoot)); + bool bOk = g_pDataModel->SaveToFile( pFileName, NULL, pSerializationType, "dmx", pRoot ); + Shipping_Assert( bOk ); + + CDmElement *pReadInRoot = NULL; + DmFileId_t dmxFileID = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pReadInRoot, CR_FORCE_COPY ); + Shipping_Assert( dmxFileID != DMFILEID_INVALID ); + + if ( pReadInRoot ) + { + AssertEqualElementHierarchies( false, hRoot, pReadInRoot->GetHandle() ); + g_pDataModel->RemoveFileId( dmxFileID ); + } + else + { + Msg( "Failed to load dmxtest.dmx back from disk!!!" ); + } + + g_pDataModel->RemoveFileId( testFileID ); + + TestConflictResolution( pSerializationType ); +} + +DEFINE_TESTCASE_NOSUITE( DmxSerializationTest ) +{ + Msg( "Running dmx serialization tests...\n" ); + CDisableUndoScopeGuard sg; + + TestSerializationMethod( "keyvalues2" ); + TestSerializationMethod( "keyvalues2_flat" ); + TestSerializationMethod( "xml" ); + TestSerializationMethod( "xml_flat" ); + TestSerializationMethod( "binary" ); + + int nEndingCount = g_pDataModel->GetAllocatedElementCount(); + AssertEqualsTest( false, 0, nEndingCount ); +} diff --git a/unittests/dmxtest/dmxtestundoredo.cpp b/unittests/dmxtest/dmxtestundoredo.cpp new file mode 100644 index 0000000..991132c --- /dev/null +++ b/unittests/dmxtest/dmxtestundoredo.cpp @@ -0,0 +1,1096 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for DMX testing +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "datamodel/dmelement.h" +#include "datamodel/idatamodel.h" +#include "movieobjects/movieobjects.h" +#include "tier1/utlbuffer.h" +#include "filesystem.h" + + +// From dmxtestserialization.cpp + +bool AssertEqualElementHierarchies( bool quiet, DmElementHandle_t src1, DmElementHandle_t src2 ); +bool AssertUnEqualElementHierarchies( DmElementHandle_t src1, DmElementHandle_t src2 ); + +void CreateTestScene( CUtlVector< DmElementHandle_t >& handles, DmFileId_t fileid ); + +bool AssertEqualElementHierarchies( bool quiet, CDmElement *src1, CDmElement *src2 ) +{ + DmElementHandle_t h1 = src1->GetHandle(); + DmElementHandle_t h2 = src2->GetHandle(); + + return AssertEqualElementHierarchies( quiet, h1, h2 ); +} + +bool AssertUnEqualElementHierarchies( CDmElement *src1, CDmElement *src2 ) +{ + return AssertUnEqualElementHierarchies( src1->GetHandle(), src2->GetHandle() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : - +//----------------------------------------------------------------------------- +void DescribeUndo() +{ + CUtlVector< UndoInfo_t > list; + g_pDataModel->GetUndoInfo( list ); + + for ( int i = list.Count() - 1; i >= 0; --i ) + { + UndoInfo_t& entry = list[ i ]; + if ( entry.terminator ) + { + Msg( "[ '%s' ] -- %i operations\n", entry.undo, entry.numoperations ); + } + + Msg( " +[ '%s' ]\n", entry.desc ); + } +} + +template< class T > +void RunSingleSetAttributeUndoTest( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, const T& newVal ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + pElement->SetValue( attribute, newVal ); + } + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +void RunSingleSetAttributeUndoTestBinary( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, const void *data, size_t size ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + pElement->SetValue( attribute, data, size ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template< class T > +void RunSingleSetAttributeUndoTestArray( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, int slot, const T& newVal ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrArray< T > array( pElement, attribute ); + array.Set( slot, newVal ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template<> void RunSingleSetAttributeUndoTestArray<DmElementHandle_t>( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, int slot, const DmElementHandle_t& newVal ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrElementArray<> array( pElement, attribute ); + array.SetHandle( slot, newVal ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template< class T > +void RunSingleAttributeUndoTestArrayAddToHead( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, const T& newVal ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrArray< T > array( pElement, attribute ); + array.InsertBefore( 0, newVal ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template< class T > +void RunSingleAttributeUndoTestArrayAddToTail( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, const T& newVal ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrArray< T > array( pElement, attribute ); + array.AddToTail( newVal ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template< class T > +void RunSingleAttributeUndoTestArrayInsertBefore( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, int slot, const T& newVal ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrArray< T > array( pElement, attribute ); + array.InsertBefore( slot, newVal ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + + +template< class T > +void RunSingleAttributeUndoTestArrayFastRemove( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, int slot, T typeDeducer ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrArray< T > array( pElement, attribute ); + array.FastRemove( slot ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + + +void RunSingleAttributeUndoTestElementArrayRemove( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, int slot ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrElementArray<> array( pElement, attribute ); + array.Remove( slot ); + } + + DescribeUndo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template< class T > +void RunSingleAttributeUndoTestArrayRemove( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, int slot, T typeDeducer ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrArray<T> array( pElement, attribute ); + array.Remove( slot ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template< class T > +void RunSingleAttributeUndoTestArrayRemoveMultiple( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, int slot, int count, T typeDeducer ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrArray< T > array( pElement, attribute ); + array.RemoveMultiple( slot, count ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template< class T > +void RunSingleAttributeUndoTestArrayRemoveAll( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, bool purge ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrArray< T > array( pElement, attribute ); + if( purge ) + { + array.Purge(); + } + else + { + array.RemoveAll(); + } + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template< class T > +void RunSingleAttributeUndoTestArrayCopyFrom( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, const CUtlVector<T>& list ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CDmrArray<T> array( pElement, attribute ); + array.CopyArray( list.Base(), list.Count() ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + + +void RunSingleSetAttributeUndoTestArrayBinary( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, int slot, const void *data, size_t size ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + CUtlBinaryBlock block( (const void *)data, size ); + CDmrArray< CUtlBinaryBlock > array( pElement, attribute ); + array.Set( slot, block ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template< class T > +void RunSingleSetAttributeUndoTestArrayWhole( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, CUtlVector< T >& newVal ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + IDmAttributeArray< T > *pArray = static_cast< IDmAttributeArray< T > * >( pElement->GetAttribute( "attribute" ) ); + pArray->SetValue( newVal ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +template< class T > +void RunSingleAddAttributeUndoTest( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute, const T& newVal ) +{ + { + CUndoScopeGuard guard( attribute, attribute ); + pElement->SetValue( attribute, newVal ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + +void RunSingleRemoveAttributeUndoTest( CDmElement *pTest, CDmElement *pOriginal, CDmElement *pElement, const char *attribute ) +{ + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + { + CUndoScopeGuard guard( attribute, attribute ); + pElement->RemoveAttribute( attribute ); + } + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + + AssertUnEqualElementHierarchies( pTest, pOriginal ); + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); +} + + +void RunUndoTestsArray( CUtlVector< DmElementHandle_t >& handles, CDmElement *pTest, CDmElement *pOriginal ) +{ + DmObjectId_t id; + CreateUniqueId( &id ); + + VMatrix mat, mat2; + MatrixBuildRotateZ( mat, 55 ); + MatrixBuildRotateZ( mat2, -55 ); + int i; + unsigned char buf[256]; + unsigned char buf2[256]; + for ( i = 0; i < 256; ++i ) + { + buf[i] = i+55500; + buf2[i] = 55000 + 255 - i; + } + + Assert( handles.Count() == 7 ); + + //CDmElement *pElement = pTest; + CDmElement *pElement2 = GetElement< CDmElement >( handles[ 1 ] ); + CDmElement *pElement3 = GetElement< CDmElement >( handles[ 2 ] ); + CDmElement *pElement4 = GetElement< CDmElement >( handles[ 3 ] ); + CDmElement *pElement5 = GetElement< CDmElement >( handles[ 4 ] ); + CDmElement *pElement6 = GetElement< CDmElement >( handles[ 5 ] ); + CDmElement *pElement7 = GetElement< CDmElement >( handles[ 6 ] ); + + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement2, "int_array_test", 0, 55 ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement2, "float_array_test", 0, 55.0f ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement2, "bool_array_test", 0, true ); + + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement3, "color_array_test", 0, Color( 55, 55, 55, 55 ) ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement3, "vector2d_array_test", 0, Vector2D( 55.0f, -55.0f ) ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement3, "vector3d_array_test", 0, Vector( 55.0f, -55.0f, 55.0f ) ); + + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement4, "vector4d_array_test", 0, Vector4D( 55.0f, -55.0f, 55.0f, 55.0f ) ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement4, "qangle_array_test", 0, QAngle( 55.0f, 55.0f, -55.0f ) ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement4, "quat_array_test", 0, Quaternion( 1.0f, -1.0f, 0.0f, 55.0f ) ); + + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement5, "vmatrix_array_test", 0, mat ); + CUtlString newString( "55test" ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement5, "string_array_test", 0, newString ); + RunSingleSetAttributeUndoTestArrayBinary( pTest, pOriginal, pElement5, "binary_array_test", 0, buf, 256 ); + +// RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement6, "elementid_array_test", 0, id ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement6, "element_array_test", 0, pElement2->GetHandle() ); + + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement7, "element_array_test", 0, pElement5->GetHandle() ); + + { + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement2, "int_array_test", 0, 55 ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement2, "float_array_test", 0, 55.0f ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement2, "bool_array_test", 0, true ); + + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement3, "color_array_test", 0, Color( 55, 55, 55, 55 ) ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement3, "vector2d_array_test", 0, Vector2D( 55.0f, -55.0f ) ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement3, "vector3d_array_test", 0, Vector( 55.0f, -55.0f, 55.0f ) ); + + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement4, "vector4d_array_test", 0, Vector4D( 55.0f, -55.0f, 55.0f, 55.0f ) ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement4, "qangle_array_test", 0, QAngle( 55.0f, 55.0f, -55.0f ) ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement4, "quat_array_test", 0, Quaternion( 1.0f, -1.0f, 0.0f, 55.0f ) ); + + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement5, "vmatrix_array_test", 0, mat ); + CUtlString newString( "55test" ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement5, "string_array_test", 0, newString ); + RunSingleSetAttributeUndoTestArrayBinary( pTest, pOriginal, pElement5, "binary_array_test", 0, buf, 256 ); + +// RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement6, "elementid_array_test", 0, id ); + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement6, "element_array_test", 0, pElement2->GetHandle() ); + + RunSingleSetAttributeUndoTestArray( pTest, pOriginal, pElement7, "element_array_test", 0, pElement5->GetHandle() ); + } + + RunSingleAttributeUndoTestArrayAddToHead( pTest, pOriginal, pElement2, "int_array_test", 55 ); + RunSingleAttributeUndoTestArrayAddToTail( pTest, pOriginal, pElement2, "int_array_test", 55 ); + RunSingleAttributeUndoTestArrayInsertBefore( pTest, pOriginal, pElement2, "int_array_test", 0, 55 ); + RunSingleAttributeUndoTestArrayFastRemove( pTest, pOriginal, pElement2, "int_array_test", 0, (int)0 ); + RunSingleAttributeUndoTestArrayRemove( pTest, pOriginal, pElement2, "int_array_test", 0, (int)0 ); + RunSingleAttributeUndoTestArrayRemoveMultiple( pTest, pOriginal, pElement2, "int_array_test", 0, 2, (int)0 ); + RunSingleAttributeUndoTestElementArrayRemove( pTest, pOriginal, pElement7, "children", 0 ); + + // RemoveAll + RunSingleAttributeUndoTestArrayRemoveAll<int>( pTest, pOriginal, pElement2, "int_array_test", false ); + // Purge + RunSingleAttributeUndoTestArrayRemoveAll<int>( pTest, pOriginal, pElement2, "int_array_test", true ); + + CUtlVector< int > foo; + foo.AddToTail( 55 ); + foo.AddToTail( 56 ); + foo.AddToTail( 57 ); + foo.AddToTail( 58 ); + foo.AddToTail( 59 ); + + RunSingleAttributeUndoTestArrayCopyFrom( pTest, pOriginal, pElement2, "int_array_test", foo ); +} + +void RunUndoTests( CUtlVector< DmElementHandle_t >& handles, CDmElement *pTest, CDmElement *pOriginal ) +{ + DmObjectId_t id; + CreateUniqueId( &id ); + + VMatrix mat, mat2; + MatrixBuildRotateZ( mat, 55 ); + MatrixBuildRotateZ( mat2, -55 ); + int i; + unsigned char buf[256]; + unsigned char buf2[256]; + for ( i = 0; i < 256; ++i ) + { + buf[i] = i+100; + buf2[i] = 127 + 255 - i; + } + + Assert( handles.Count() == 7 ); + CDmElement *pElement = pTest; + CDmElement *pElement2 = GetElement<CDmElement>( handles[ 1 ] ); + + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "element_test", (CDmElement *)NULL ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "int_test", 55 ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "float_test", 55.0f ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "bool_test", false ); +// RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "id_test", id ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "string_test", "55test" ); + RunSingleSetAttributeUndoTestBinary( pTest, pOriginal, pElement, "binary_test", buf, 256 ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "color_test", Color( 55, 55, 55, 55 ) ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "vector2d_test", Vector2D( 55.0f, -55.0f ) ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "vector3d_test", Vector( 55.0f, -55.0f, 55.0f ) ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "vector4d_test", Vector4D( 55.0f, -55.0f, 55.0f, 55.0f ) ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "qangle_test", QAngle( 55.0f, 55.0f, -55.0f ) ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "quat_test", Quaternion( 1.0f, -1.0f, 0.0f, 55.0f ) ); + RunSingleSetAttributeUndoTest( pTest, pOriginal, pElement, "vmatrix_test", mat ); + + // Now run a single test with a bunch of operations occurring at the same time + { + { + CUndoScopeGuard guard( "biggish", "smallish" ); + pElement->SetValue( "bool_test", false ); + pElement->SetValue( "int_test", 55 ); + pElement->SetValue( "float_test", 55.0f ); + pElement->SetValue( "color_test", Color( 55, 55, 55, 55 ) ); + pElement->SetValue( "vector2d_test", Vector2D( 55.0f, -55.0f ) ); + pElement->SetValue( "vector3d_test", Vector( 55.0f, -55.0f, 55.0f ) ); + pElement->SetValue( "vector4d_test", Vector4D( 55.0f, -55.0f, 55.0f, 55.0f ) ); + pElement->SetValue( "qangle_test", QAngle( 55.0f, 55.0f, -55.0f ) ); + pElement->SetValue( "quat_test", Quaternion( 1.0f, -1.0f, 0.0f, 55.0f ) ); + pElement->SetValue( "vmatrix_test", mat ); + pElement->SetValue( "string_test", "55test" ); + pElement->SetValue( "binary_test", buf, 256 ); + } + + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + } + + // Now run a test with multiple items in the stack + { + // Push 1 + { + CUndoScopeGuard guard( "biggish1", "smallish1" ); + pElement->SetValue( "bool_test", false ); + pElement->SetValue( "int_test", 55 ); + pElement->SetValue( "float_test", 55.0f ); + pElement->SetValue( "color_test", Color( 55, 55, 55, 55 ) ); + } + // Push 2 + { + CUndoScopeGuard guard( "biggish2", "smallish2" ); + pElement->SetValue( "vector2d_test", Vector2D( 55.0f, -55.0f ) ); + pElement->SetValue( "vector3d_test", Vector( 55.0f, -55.0f, 55.0f ) ); + pElement->SetValue( "vector4d_test", Vector4D( 55.0f, -55.0f, 55.0f, 55.0f ) ); + pElement->SetValue( "qangle_test", QAngle( 55.0f, 55.0f, -55.0f ) ); + pElement->SetValue( "quat_test", Quaternion( 1.0f, -1.0f, 0.0f, 55.0f ) ); + } + // Push 3 + { + CUndoScopeGuard guard( "biggish3", "smallish3" ); + pElement->SetValue( "vmatrix_test", mat ); + pElement->SetValue( "string_test", "55test" ); + pElement->SetValue( "binary_test", buf, 256 ); + } + // Tests + { + g_pDataModel->Undo(); + g_pDataModel->Undo(); + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + g_pDataModel->Redo(); + g_pDataModel->Redo(); + g_pDataModel->Redo(); + + g_pDataModel->Undo(); + g_pDataModel->Undo(); + g_pDataModel->Undo(); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + } + } + + // Now run "add" tests on a subset -- add adds an attribute where one didn't already exist + RunSingleAddAttributeUndoTest( pTest, pOriginal, pElement2, "int_test_added", 55 ); + + // Now run "remove" tests on a subset of attributes -- removes an existing attribute by name + RunSingleRemoveAttributeUndoTest( pTest, pOriginal, pTest, "int_test" ); +} + +#include "datamodel/dmehandle.h" + +void RunUndoTestCreateElement() +{ + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<RunUndoTestCreateElement>" ); + + CDmElement *element = NULL; + { + CUndoScopeGuard guard( "create" ); + element = CreateElement< CDmElement >( "test", fileid ); + } + + CDmeHandle< CDmElement > hChannel; + + hChannel = element; + + Assert( hChannel.Get() ); + + g_pDataModel->Undo(); + + Assert( !hChannel.Get() ); + + g_pDataModel->Redo(); + + Assert( hChannel.Get() ); + + g_pDataModel->Undo(); // It's on the redo stack, but marked as kill and all ptrs are NULL to it + + Assert( !hChannel.Get() ); + + g_pDataModel->ClearUndo(); + g_pDataModel->ClearRedo(); + + g_pDataModel->RemoveFileId( fileid ); +} + +DEFINE_TESTCASE_NOSUITE( DmxUndoRedoTest ) +{ + Msg( "Running undo tests...\n" ); + +#ifdef _DEBUG + int nStartingCount = g_pDataModel->GetAllocatedElementCount(); +#endif + + CUndoScopeGuard sg( "Create Test Scenes" ); + + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxUndoRedoTest>" ); + CUtlVector< DmElementHandle_t > handles; + CreateTestScene( handles, fileid ); + DmElementHandle_t hOriginal = handles[ 0 ]; + handles.RemoveAll(); + CreateTestScene( handles, fileid ); + DmElementHandle_t hTest = handles[ 0 ]; + + sg.Release(); + + CDmElement *pOriginal = static_cast<CDmElement*>( g_pDataModel->GetElement( hOriginal ) ); + CDmElement *pTest = static_cast<CDmElement*>(g_pDataModel->GetElement( hTest ) ); + + AssertEqualElementHierarchies( false, pTest, pOriginal ); + + RunUndoTests( handles, pTest, pOriginal ); + RunUndoTestsArray( handles, pTest, pOriginal ); + RunUndoTestCreateElement(); + + g_pDataModel->ClearUndo(); + + g_pDataModel->RemoveFileId( fileid ); + +#ifdef _DEBUG + int nEndingCount = g_pDataModel->GetAllocatedElementCount(); + AssertEquals( nEndingCount, nStartingCount ); + if ( nEndingCount != nStartingCount ) + { + for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement() ; + hElement != DMELEMENT_HANDLE_INVALID; + hElement = g_pDataModel->NextAllocatedElement( hElement ) ) + { + CDmElement *pElement = g_pDataModel->GetElement( hElement ); + Assert( pElement ); + if ( !pElement ) + return; + + Msg( "[%s : %s] in memory\n", pElement->GetName(), pElement->GetTypeString() ); + } + } +#endif +} + +#include "datamodel/dmelementfactoryhelper.h" + +//----------------------------------------------------------------------------- +// CDmeExternal - element class used for testing external attributes +//----------------------------------------------------------------------------- + +class CDmeExternal : public CDmElement +{ + DEFINE_ELEMENT( CDmeExternal, CDmElement ); + +public: + CDmaVar< float > m_External; +}; + +IMPLEMENT_ELEMENT_FACTORY( DmeExternal, CDmeExternal ); + +void CDmeExternal::OnConstruction() +{ + m_External .InitAndSet( this, "external", 99.9f ); +} + +void CDmeExternal::OnDestruction() +{ +} + +USING_ELEMENT_FACTORY( DmeExternal ); + + +DEFINE_TESTCASE_NOSUITE( DmxExternalAttributeTest ) +{ + Msg( "Running external attribute test...\n" ); + + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxExternalAttributeTest>" ); + + CDmeExternal *pOriginal = 0; + +#ifdef _DEBUG + int nStartingCount = g_pDataModel->GetAllocatedElementCount(); +#endif + + { + CUndoScopeGuard guard( "External" ); + pOriginal = CreateElement<CDmeExternal>( "foo", fileid ); + + for ( int m = 0; m < 1; ++m ) + { + CDmeExternal *discard = CreateElement<CDmeExternal>( "foo", fileid ); + g_pDataModel->DestroyElement( discard->GetHandle() ); + } + } + + // Now mess with vars + + g_pDataModel->Undo(); + g_pDataModel->Redo(); + + { + CUndoScopeGuard guard( "External2" ); + pOriginal->m_External.Set( 100.0f ); + } + + g_pDataModel->ClearUndo(); + + g_pDataModel->RemoveFileId( fileid ); + +#ifdef _DEBUG + int nEndingCount = g_pDataModel->GetAllocatedElementCount(); + AssertEquals( nEndingCount, nStartingCount ); + if ( nEndingCount != nStartingCount ) + { + for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement() ; + hElement != DMELEMENT_HANDLE_INVALID; + hElement = g_pDataModel->NextAllocatedElement( hElement ) ) + { + CDmElement *pElement = g_pDataModel->GetElement( hElement ); + Assert( pElement ); + if ( !pElement ) + return; + + Msg( "[%s : %s] in memory\n", pElement->GetName(), pElement->GetTypeString() ); + } + } +#endif +} + +void Assert_InvalidAndNULL( CDmeHandle< CDmElement > &hElement ) +{ + Shipping_Assert( !hElement.Get() ); + if ( !hElement.Get() ) + { + g_pDataModel->MarkHandleValid( hElement.GetHandle() ); + Shipping_Assert( !hElement.Get() ); + if ( hElement.Get() ) + { + g_pDataModel->MarkHandleInvalid( hElement.GetHandle() ); + } + } +} + +void Assert_InvalidButNonNULL( CDmeHandle< CDmElement > &hElement ) +{ + Shipping_Assert( !hElement.Get() ); + if ( !hElement.Get() ) + { + g_pDataModel->MarkHandleValid( hElement.GetHandle() ); + Shipping_Assert( hElement.Get() ); + if ( hElement.Get() ) + { + g_pDataModel->MarkHandleInvalid( hElement.GetHandle() ); + } + } +} + +void Assert_ValidAndNonNULL( CDmeHandle< CDmElement > &hElement ) +{ + Shipping_Assert( hElement.Get() ); +} + +DEFINE_TESTCASE_NOSUITE( DmxReferenceCountingTest ) +{ + Msg( "Running external attribute test...\n" ); + + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxReferenceCountingTest>" ); + + CDmeHandle< CDmElement > hRoot; + CDmeHandle< CDmElement > hChild1, hChild2, hChild3, hChild4, hChild5; + CDmeHandle< CDmElement > hGrandChild1, hGrandChild2, hGrandChild3, hGrandChild4, hGrandChild5, hGrandChild6, hGrandChild7; + CDmeCountedHandle hStrong6, hStrong7; + + g_pDmElementFramework->BeginEdit(); + + int nStartingCount = g_pDataModel->GetAllocatedElementCount(); + Shipping_Assert( nStartingCount == 0 ); + + { + CUndoScopeGuard guard( "Create RefCountTest Elements" ); + + hRoot = CreateElement<CDmElement>( "root", fileid ); + CDmrElementArray<> arrayRoot( hRoot, "children", true ); + g_pDataModel->SetFileRoot( fileid, hRoot->GetHandle() ); + + hChild1 = CreateElement<CDmElement>( "child1", fileid ); + CDmrElementArray<> arrayChild1( hChild1, "children", true ); + arrayRoot.AddToTail( hChild1.Get() ); + + hChild2 = CreateElement<CDmElement>( "child2", fileid ); + hChild2->AddAttributeElement<CDmElement>( "child" ); + arrayRoot.AddToTail( hChild2.Get() ); + + hChild3 = CreateElement<CDmElement>( "child3", fileid ); + hChild3->AddAttributeElement<CDmElement>( "child" ); + arrayRoot.AddToTail( hChild3.Get() ); + + hChild4 = CreateElement<CDmElement>( "child4", fileid ); + hChild4->AddAttributeElement<CDmElement>( "child" ); + arrayRoot.AddToTail( hChild4.Get() ); + + hChild5 = CreateElement<CDmElement>( "child5", fileid ); + CDmrElementArray<> arrayChild5( hChild5, "children", true ); + arrayRoot.AddToTail( hChild5.Get() ); + + hGrandChild1 = CreateElement<CDmElement>( "grandchild1", fileid ); + arrayChild1.AddToTail( hGrandChild1.Get() ); + + hGrandChild2 = CreateElement<CDmElement>( "grandchild2", fileid ); + arrayChild1.AddToTail( hGrandChild2.Get() ); + hChild2->SetValue( "child", hGrandChild2.GetHandle() ); + + hGrandChild3 = CreateElement<CDmElement>( "grandchild3", fileid ); + arrayChild1.AddToTail( hGrandChild3.Get() ); + hChild3->SetValue( "child", hGrandChild3.GetHandle() ); + + hGrandChild4 = CreateElement<CDmElement>( "grandchild4", fileid ); + arrayChild1.AddToTail( hGrandChild4.Get() ); + hChild4->SetValue( "child", hGrandChild4.GetHandle() ); + + hGrandChild5 = CreateElement<CDmElement>( "grandchild5", fileid ); + arrayChild1.AddToTail( hGrandChild5.Get() ); + arrayChild5.AddToTail( hGrandChild5.Get() ); + + hGrandChild6 = CreateElement<CDmElement>( "grandchild6", fileid ); + arrayChild1.AddToTail( hGrandChild6.Get() ); + hStrong6 = hGrandChild6; + + hGrandChild7 = CreateElement<CDmElement>( "grandchild7", fileid ); + arrayChild1.AddToTail( hGrandChild7.Get() ); + hStrong7 = hGrandChild7; + } + + g_pDmElementFramework->BeginEdit(); + + int nCreateCount = g_pDataModel->GetAllocatedElementCount(); + Assert( nCreateCount == nStartingCount + 13 ); + + Assert_ValidAndNonNULL ( hRoot ); + Assert_ValidAndNonNULL ( hChild1 ); + Assert_ValidAndNonNULL ( hChild2 ); + Assert_ValidAndNonNULL ( hChild3 ); + Assert_ValidAndNonNULL ( hChild4 ); + Assert_ValidAndNonNULL ( hChild5 ); + Assert_ValidAndNonNULL ( hGrandChild1 ); + Assert_ValidAndNonNULL ( hGrandChild2 ); + Assert_ValidAndNonNULL ( hGrandChild3 ); + Assert_ValidAndNonNULL ( hGrandChild4 ); + Assert_ValidAndNonNULL ( hGrandChild5 ); + Assert_ValidAndNonNULL ( hGrandChild6 ); + Assert_ValidAndNonNULL ( hGrandChild7 ); + + g_pDataModel->ClearUndo(); + + g_pDmElementFramework->BeginEdit(); + + int nPostCreateCount = g_pDataModel->GetAllocatedElementCount(); + Shipping_Assert( nPostCreateCount == nCreateCount ); + + Assert_ValidAndNonNULL ( hRoot ); + Assert_ValidAndNonNULL ( hChild1 ); + Assert_ValidAndNonNULL ( hChild2 ); + Assert_ValidAndNonNULL ( hChild3 ); + Assert_ValidAndNonNULL ( hChild4 ); + Assert_ValidAndNonNULL ( hChild5 ); + Assert_ValidAndNonNULL ( hGrandChild1 ); + Assert_ValidAndNonNULL ( hGrandChild2 ); + Assert_ValidAndNonNULL ( hGrandChild3 ); + Assert_ValidAndNonNULL ( hGrandChild4 ); + Assert_ValidAndNonNULL ( hGrandChild5 ); + Assert_ValidAndNonNULL ( hGrandChild6 ); + Assert_ValidAndNonNULL ( hGrandChild7 ); + + { + CUndoScopeGuard guard( "Edit RefCountTest Elements" ); + + CDmrGenericArray children( hChild1, "children" ); + children.RemoveAll(); // grandchild1 unref'ed to 0, grandchild2..6 unref'ed to 1 + + hChild2->SetValue( "child", DMELEMENT_HANDLE_INVALID ); // grandchild2 unref'ed to 0 + + g_pDataModel->DestroyElement( hChild3 ); // grandchild3 is unref'ed to 0 + + CDmrElementArray<> children5( hChild5, "children" ); + children5.Set( 0, NULL ); // grandchild5 is unref'ed to 0 + + hStrong6 = DMELEMENT_HANDLE_INVALID; // grandchild6 is unref'ed to 0 + } + + g_pDmElementFramework->BeginEdit(); + + int nEditCount = g_pDataModel->GetAllocatedElementCount(); + Shipping_Assert( nEditCount == nCreateCount - 1 ); + + Assert_ValidAndNonNULL ( hRoot ); + Assert_ValidAndNonNULL ( hChild1 ); + Assert_ValidAndNonNULL ( hChild2 ); + Assert_InvalidButNonNULL( hChild3 ); + Assert_ValidAndNonNULL ( hChild4 ); + Assert_ValidAndNonNULL ( hChild5 ); + Assert_ValidAndNonNULL ( hGrandChild1 ); + Assert_ValidAndNonNULL ( hGrandChild2 ); + Assert_ValidAndNonNULL ( hGrandChild3 ); + Assert_ValidAndNonNULL ( hGrandChild4 ); + Assert_ValidAndNonNULL ( hGrandChild5 ); + Assert_ValidAndNonNULL ( hGrandChild6 ); + Assert_ValidAndNonNULL ( hGrandChild7 ); + + g_pDataModel->Undo(); + + g_pDmElementFramework->BeginEdit(); + + int nUndoCount = g_pDataModel->GetAllocatedElementCount(); + Shipping_Assert( nUndoCount == nCreateCount ); + + Assert_ValidAndNonNULL ( hRoot ); + Assert_ValidAndNonNULL ( hChild1 ); + Assert_ValidAndNonNULL ( hChild2 ); + Assert_ValidAndNonNULL ( hChild3 ); + Assert_ValidAndNonNULL ( hChild4 ); + Assert_ValidAndNonNULL ( hChild5 ); + Assert_ValidAndNonNULL ( hGrandChild1 ); + Assert_ValidAndNonNULL ( hGrandChild2 ); + Assert_ValidAndNonNULL ( hGrandChild3 ); + Assert_ValidAndNonNULL ( hGrandChild4 ); + Assert_ValidAndNonNULL ( hGrandChild5 ); + Assert_ValidAndNonNULL ( hGrandChild6 ); + Assert_ValidAndNonNULL ( hGrandChild7 ); + + g_pDataModel->Redo(); + + g_pDmElementFramework->BeginEdit(); + + int nRedoCount = g_pDataModel->GetAllocatedElementCount(); + Shipping_Assert( nRedoCount == nEditCount ); + + Assert_ValidAndNonNULL ( hRoot ); + Assert_ValidAndNonNULL ( hChild1 ); + Assert_ValidAndNonNULL ( hChild2 ); + Assert_InvalidButNonNULL( hChild3 ); + Assert_ValidAndNonNULL ( hChild4 ); + Assert_ValidAndNonNULL ( hChild5 ); + Assert_ValidAndNonNULL ( hGrandChild1 ); + Assert_ValidAndNonNULL ( hGrandChild2 ); + Assert_ValidAndNonNULL ( hGrandChild3 ); + Assert_ValidAndNonNULL ( hGrandChild4 ); + Assert_ValidAndNonNULL ( hGrandChild5 ); + Assert_ValidAndNonNULL ( hGrandChild6 ); + Assert_ValidAndNonNULL ( hGrandChild7 ); + + g_pDataModel->ClearUndo(); + + g_pDmElementFramework->BeginEdit(); + + int nClearUndoCount = g_pDataModel->GetAllocatedElementCount(); + Shipping_Assert( nClearUndoCount == nCreateCount - 6 ); + + Assert_ValidAndNonNULL ( hRoot ); + Assert_ValidAndNonNULL ( hChild1 ); + Assert_ValidAndNonNULL ( hChild2 ); + Assert_InvalidAndNULL ( hChild3 ); + Assert_ValidAndNonNULL ( hChild4 ); + Assert_ValidAndNonNULL ( hChild5 ); + Assert_InvalidAndNULL ( hGrandChild1 ); + Assert_InvalidAndNULL ( hGrandChild2 ); + Assert_InvalidAndNULL ( hGrandChild3 ); + Assert_ValidAndNonNULL ( hGrandChild4 ); + Assert_InvalidAndNULL ( hGrandChild5 ); + Assert_InvalidAndNULL ( hGrandChild6 ); + Assert_ValidAndNonNULL ( hGrandChild7 ); + + g_pDataModel->RemoveFileId( fileid ); +} diff --git a/unittests/dmxtest/dmxtestvalue.cpp b/unittests/dmxtest/dmxtestvalue.cpp new file mode 100644 index 0000000..df20e10 --- /dev/null +++ b/unittests/dmxtest/dmxtestvalue.cpp @@ -0,0 +1,104 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for DMX testing (testing the single-value operations) +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "datamodel/dmelement.h" +#include "datamodel/idatamodel.h" +#include "tier1/utlbuffer.h" +#include "filesystem.h" +#include "datamodel/dmehandle.h" +#include "tier2/tier2.h" +#include "movieobjects/dmeshape.h" + + +DEFINE_TESTCASE_NOSUITE( DmxValueTest ) +{ + Msg( "Running dmx single value tests...\n" ); + + CDisableUndoScopeGuard sg; + DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<RunValueTests>" ); + + CDmElement *pElement = CreateElement< CDmElement >( "root", fileid ); + + CDmElement *pElement2 = CreateElement<CDmElement>( "element1", fileid ); + Assert( pElement2 ); + CDmElement *pElement3 = CreateElement<CDmElement>( "element2", fileid ); + Assert( pElement3 ); + CDmeShape *pElement4 = CreateElement<CDmeShape>( "shape", fileid ); + Assert( pElement4 ); + + CDmAttribute *pIntAttribute = pElement->SetValue( "int_test", 5 ); + CDmAttribute *pFloatAttribute = pElement->SetValue( "float_test", 4.5f ); + CDmAttribute *pBoolAttribute = pElement->SetValue( "bool_test", true ); + + CDmAttribute *pAttribute = pElement->AddAttribute( "int_convert_test", AT_INT ); + + // Type conversion set test + pAttribute->SetValue( 5 ); + Shipping_Assert( pAttribute->GetValue<int>() == 5 ); + pAttribute->SetValue( 4.5f ); + Shipping_Assert( pAttribute->GetValue<int>() == 4 ); + pAttribute->SetValue( true ); + Shipping_Assert( pAttribute->GetValue<int>() == 1 ); + pAttribute->SetValue( pIntAttribute ); + Shipping_Assert( pAttribute->GetValue<int>() == 5 ); + pAttribute->SetValue( pFloatAttribute ); + Shipping_Assert( pAttribute->GetValue<int>() == 4 ); + pAttribute->SetValue( pBoolAttribute ); + Shipping_Assert( pAttribute->GetValue<int>() == 1 ); + + pAttribute = pElement->AddAttribute( "bool_convert_test", AT_BOOL ); + + // Type conversion set test + pAttribute->SetValue( 5 ); + Shipping_Assert( pAttribute->GetValue<bool>() == true ); + pAttribute->SetValue( 4.5f ); + Shipping_Assert( pAttribute->GetValue<bool>() == true ); + pAttribute->SetValue( false ); + Shipping_Assert( pAttribute->GetValue<bool>() == false ); + pAttribute->SetValue( pIntAttribute ); + Shipping_Assert( pAttribute->GetValue<bool>() == true ); + pAttribute->SetValue( pFloatAttribute ); + Shipping_Assert( pAttribute->GetValue<bool>() == true ); + pAttribute->SetValue( pBoolAttribute ); + Shipping_Assert( pAttribute->GetValue<bool>() == true ); + + pAttribute = pElement->AddAttribute( "float_convert_test", AT_FLOAT ); + + // Type conversion set test + pAttribute->SetValue( 5 ); + Shipping_Assert( pAttribute->GetValue<float>() == 5.0f ); + pAttribute->SetValue( 4.5f ); + Shipping_Assert( pAttribute->GetValue<float>() == 4.5f ); + pAttribute->SetValue( true ); + Shipping_Assert( pAttribute->GetValue<float>() == 1.0f ); + pAttribute->SetValue( pIntAttribute ); + Shipping_Assert( pAttribute->GetValue<float>() == 5.0f ); + pAttribute->SetValue( pFloatAttribute ); + Shipping_Assert( pAttribute->GetValue<float>() == 4.5f ); + pAttribute->SetValue( pBoolAttribute ); + Shipping_Assert( pAttribute->GetValue<float>() == 1.0f ); + + // Type conversion set test + QAngle angles( 90, 0, 0 ); + Quaternion quat; + AngleQuaternion( angles, quat ); + + pAttribute = pElement->AddAttribute( "qangle_convert_test", AT_QANGLE ); + pAttribute->SetValue( angles ); + Shipping_Assert( pAttribute->GetValue<QAngle>() == angles ); + pAttribute->SetValue( quat ); + Shipping_Assert( pAttribute->GetValue<QAngle>() == angles ); + + pAttribute = pElement->AddAttribute( "quat_convert_test", AT_QUATERNION ); + pAttribute->SetValue( angles ); + Shipping_Assert( pAttribute->GetValue<Quaternion>() == quat ); + pAttribute->SetValue( quat ); + Shipping_Assert( pAttribute->GetValue<Quaternion>() == quat ); + + g_pDataModel->RemoveFileId( fileid ); +} diff --git a/unittests/ihvtest1/ihvtest1.cpp b/unittests/ihvtest1/ihvtest1.cpp new file mode 100644 index 0000000..b1253dc --- /dev/null +++ b/unittests/ihvtest1/ihvtest1.cpp @@ -0,0 +1,1508 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +//============================================================================= + +#define PROTECTED_THINGS_DISABLE +#if !defined( _X360 ) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif +#include <time.h> +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/IMaterialSystemHardwareConfig.h" +#include "materialsystem/imaterialproxyfactory.h" +#include "materialsystem/MaterialSystem_Config.h" +#include "appframework/appframework.h" +#include "datacache\idatacache.h" +#include "datacache\imdlcache.h" +#include "vphysics_interface.h" +#include "filesystem.h" +#include "IStudioRender.h" +#include "studio.h" +#include "clientstats.h" +#include "bone_setup.h" +#include "tier0/icommandline.h" +#include "vstdlib/cvar.h" +#include "tier0/vprof.h" +#include "tier1/tier1.h" +#include "optimize.h" +#if defined( _X360 ) +#include "xbox\xbox_console.h" +#include "xbox\xbox_win32stubs.h" +#endif + +//----------------------------------------------------------------------------- +// Main system interfaces +//----------------------------------------------------------------------------- +IMaterialSystem *g_pMaterialSystem = NULL; +IStudioRender *g_pStudioRender = NULL; +IFileSystem *g_pFileSystem = NULL; +IMDLCache *g_pMDLCache = NULL; + + +//----------------------------------------------------------------------------- +// App control defines +//----------------------------------------------------------------------------- +//#define MATERIAL_OVERRIDE +//#define USE_VTUNE +//#define USE_VPROF + +#if USE_VTUNE +#include "vtuneapi.h" +#endif + +static bool g_WindowMode = false; +static bool g_bUseEmptyShader = false; +static bool g_BenchFinished = false; +static bool g_BenchMode = false; +static bool g_SoftwareTL = false; + +static int g_RenderWidth = 640; +static int g_RenderHeight = 480; +static int g_RefreshRate = 60; +static int g_LOD = 0; +static int g_BodyGroup = 0; + +static int g_NumRows = 10; +static int g_NumCols = 10; + +static int g_dxLevel = 0; +static int g_LightingCombination = -1; + +static FILE *g_IHVTestFP = NULL; +static IMaterial *g_pForceMaterial = NULL; + +static bool g_bInError = false; + +#define MAX_LIGHTS 2 +#define NUM_LIGHT_TYPES 4 +#define LIGHTING_COMBINATION_COUNT 5 + +static const char *g_LightCombinationNames[] = +{ + "DISABLE ", +// "SPOT ", + "POINT ", + "DIRECTIONAL ", + "SPOT_SPOT ", +// "SPOT_POINT ", +// "SPOT_DIRECTIONAL ", +// "POINT_POINT ", + "POINT_DIRECTIONAL ", + "DIRECTIONAL_DIRECTIONAL" +}; + +//----------------------------------------------------------------------------- +// Test Model class +//----------------------------------------------------------------------------- +struct IHVTestModel +{ + MDLHandle_t hMdl; + studiohdr_t *pStudioHdr; + studiohwdata_t *pHardwareData; +}; + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CIHVTestApp : public CDefaultAppSystemGroup< CSteamAppSystemGroup > +{ +public: + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit(); + virtual int Main(); + virtual void PostShutdown(); + virtual void Destroy(); + +private: + bool CreateAppWindow( char const *pTitle, int w, int h ); + void AppPumpMessages( void ); + void RenderFrame( void ); + void RenderScene( void ); + bool SetupMaterialSystem(); + bool SetupStudioRender(); + bool LoadModels( void ); + bool LoadModel( const char *pModelName, IHVTestModel *pModel ); + bool CreateMainWindow( int width, int height, bool fullscreen ); + matrix3x4_t* SetUpBones( studiohdr_t *pStudioHdr, const matrix3x4_t &shapeToWorld, int iRun, int model, int boneMask ); + + // Windproc + static LONG WINAPI WinAppWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + LONG WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + HWND m_hWnd; + bool m_bExitMainLoop; + + IHVTestModel *m_pIHVTestModel; +}; + +static CIHVTestApp s_IHVTestApp; +DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT_GLOBALVAR( CIHVTestApp, s_IHVTestApp ); + +//----------------------------------------------------------------------------- +// Create the application window +//----------------------------------------------------------------------------- +bool CIHVTestApp::CreateAppWindow( const char* pAppName, int width, int height ) +{ + // Register the window class + WNDCLASSEX wc; + memset( &wc, 0, sizeof( wc ) ); + wc.cbSize = sizeof( wc ); + wc.style = CS_CLASSDC; + wc.lpfnWndProc = WinAppWindowProc; + wc.hInstance = (HINSTANCE)GetAppInstance(); + wc.lpszClassName = pAppName; + wc.hIcon = NULL; + wc.hIconSm = wc.hIcon; + + RegisterClassEx( &wc ); + + // Create the application's window + m_hWnd = CreateWindow( pAppName, pAppName, + WS_OVERLAPPEDWINDOW, + 0, 0, width, height, + GetDesktopWindow(), NULL, wc.hInstance, NULL ); + + ShowWindow (m_hWnd, SW_SHOWDEFAULT); + + return (m_hWnd != 0); +} + +//#define TREES + +// The maximum number of distinctive models each test may specify. +#ifdef TREES +const int g_nMaxModels = 1; +#else +const int g_nMaxModels = 9; +#endif + +//----------------------------------------------------------------------------- +// Benchmarking +//----------------------------------------------------------------------------- +struct BenchRunInfo +{ + const char *pModelName[g_nMaxModels]; + int numFrames; + int rows; + int cols; + float modelSize; + int sequence1[g_nMaxModels]; + int sequence2; +}; + +struct BenchResults +{ + BenchResults() : totalTime( 0.0f ), totalTris( 0 ) {} + float totalTime; + int totalTris; +}; + + +#define NUM_BENCH_RUNS 1 +static BenchResults g_BenchResults[NUM_BENCH_RUNS][LIGHTING_COMBINATION_COUNT]; + +#ifdef TREES + +#define MODEL_ROWS 13 +#define MODEL_COLUMNS 13 +static BenchRunInfo g_BenchRuns[NUM_BENCH_RUNS] = +{ + { { "models/props_foliage/tree_dead01.mdl" + }, 100, MODEL_ROWS, MODEL_COLUMNS, 1000.0f, { 0 }, -1 }, +}; + +#else + +#define MODEL_ROWS 3 +#define MODEL_COLUMNS 3 +static BenchRunInfo g_BenchRuns[NUM_BENCH_RUNS] = +{ + { { "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + "models/alyx.mdl", + }, 100, MODEL_ROWS, MODEL_COLUMNS, 75.0f, { 1, 4, 20, 23, 25, 30, 34, 38, 1 }, -1 }, +}; + +#endif + +// this is used in "-bench" mode +static IHVTestModel g_BenchModels[NUM_BENCH_RUNS][g_nMaxModels]; + +static void WriteBenchResults( void ) +{ + if( !g_BenchMode ) + { + return; + } + + FILE *fp = fopen( "ihvtest1.csv", "a+" ); + Assert( fp ); + if( !fp ) + { + return; + } + + fprintf( fp, "------------------------------------------------------------------\n" ); + + time_t ltime; + time( <ime ); + + fprintf( fp, "%s\n", GetCommandLine() ); + fprintf( fp, "Run at: %s", ctime( <ime ) ); + + int i; + for( i = 0; i < NUM_BENCH_RUNS; i++ ) + { + int j; + fprintf( fp, "model,light combo,total tris,total time,tris/sec\n" ); + for( j = 0; j < LIGHTING_COMBINATION_COUNT; j++ ) + { + int k; + for( k = 0; k < g_nMaxModels; k++ ) + { + if( g_BenchRuns[i].pModelName[k] ) + { + fprintf( fp, "%s%s", k ? ", " : "", g_BenchRuns[i].pModelName[k] ); + } + } + fprintf( fp, "," ); + fprintf( fp, "%s,", g_LightCombinationNames[j] ); + fprintf( fp, "%d,", g_BenchResults[i][j].totalTris ); + fprintf( fp, "%0.5f,", ( float )g_BenchResults[i][j].totalTime ); + fprintf( fp, "%0.0lf\n", ( double )g_BenchResults[i][j].totalTris / + ( double )g_BenchResults[i][j].totalTime ); + Warning( "%f %d\n", ( float )g_BenchResults[i][j].totalTime, g_BenchResults[i][j].totalTris ); + } + } + + fclose( fp ); +} + + +//----------------------------------------------------------------------------- +// Destroy app +//----------------------------------------------------------------------------- +void CIHVTestApp::Destroy() +{ + // Close the window + if (m_hWnd) + DestroyWindow( m_hWnd ); + + WriteBenchResults(); +} + + +//----------------------------------------------------------------------------- +// Window size helper +//----------------------------------------------------------------------------- +static void CalcWindowSize( int desiredRenderingWidth, int desiredRenderingHeight, + int *windowWidth, int *windowHeight ) +{ + int borderX, borderY; + borderX = (GetSystemMetrics(SM_CXFIXEDFRAME) + 1) * 2; + borderY = (GetSystemMetrics(SM_CYFIXEDFRAME) + 1) * 2 + GetSystemMetrics(SM_CYSIZE) + 1; + *windowWidth = desiredRenderingWidth + borderX; + *windowHeight = desiredRenderingHeight + borderY; +} + + +//----------------------------------------------------------------------------- +// Spew function! +//----------------------------------------------------------------------------- +SpewRetval_t IHVTestSpewFunc( SpewType_t spewType, char const *pMsg ) +{ + g_bInError = true; + + OutputDebugString( pMsg ); + switch( spewType ) + { + case SPEW_MESSAGE: + case SPEW_WARNING: + case SPEW_LOG: + OutputDebugString( pMsg ); + g_bInError = false; + return SPEW_CONTINUE; + + case SPEW_ASSERT: + case SPEW_ERROR: + default: + ::MessageBox( NULL, pMsg, "Error!", MB_OK ); + g_bInError = false; + return SPEW_DEBUGGER; + } +} + + +//----------------------------------------------------------------------------- +// Spew function to write to ihvtest_vprof.txt +//----------------------------------------------------------------------------- +SpewRetval_t IHVTestVProfSpewFunc( SpewType_t spewType, char const *pMsg ) +{ + g_bInError = true; + + switch( spewType ) + { + case SPEW_MESSAGE: + case SPEW_WARNING: + case SPEW_LOG: + fprintf( g_IHVTestFP, "%s", pMsg ); + g_bInError = false; + return SPEW_CONTINUE; + + case SPEW_ASSERT: + case SPEW_ERROR: + default: + ::MessageBox( NULL, pMsg, "Error!", MB_OK ); + g_bInError = false; + return SPEW_DEBUGGER; + } +} + +//----------------------------------------------------------------------------- +// Warnings and Errors... +//----------------------------------------------------------------------------- +#define MAXPRINTMSG 4096 +void DisplayError( const char* pError, ... ) +{ + va_list argptr; + char msg[1024]; + + g_bInError = true; + + va_start( argptr, pError ); + Q_vsnprintf( msg, sizeof( msg ), pError, argptr ); + va_end( argptr ); + + MessageBox( 0, msg, 0, MB_OK ); + + exit( -1 ); +} + +static void MaterialSystem_Warning( const char *fmt, ... ) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start( argptr, fmt ); + Q_vsnprintf( msg, sizeof ( msg ), fmt, argptr ); + va_end( argptr ); + + OutputDebugString( msg ); +} + +// garymcthack +static void MaterialSystem_Warning( char *fmt, ... ) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start( argptr, fmt ); + Q_vsnprintf( msg, sizeof( msg ), fmt, argptr ); + va_end( argptr ); + + OutputDebugString( msg ); +} + +static void MaterialSystem_Error( char *fmt, ... ) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + g_bInError = true; + + va_start( argptr, fmt ); + Q_vsnprintf( msg, sizeof( msg ), fmt, argptr ); + va_end( argptr ); + + MessageBox( NULL, (LPCTSTR)msg, "MaterialSystem Fatal Error", MB_OK | MB_ICONINFORMATION ); + +#ifdef _DEBUG + Assert( 0 ); +#endif + exit( -1 ); +} + + +//----------------------------------------------------------------------------- +// Engine Stats +//----------------------------------------------------------------------------- +// itty bitty interface for stat time +class CStatTime : public IClientStatsTime +{ +public: + float GetTime() + { + return Sys_FloatTime(); + } +}; +CStatTime g_StatTime; + +class CEngineStats +{ +public: + CEngineStats() : m_InFrame( false ) {}; + // + // stats input + // + + void BeginRun( void ); + void BeginFrame( void ); + + void EndFrame( void ); + void EndRun( void ); + + // + // stats output + // call these outside of a BeginFrame/EndFrame pair + // + + // return the frame time in seconds for the whole system (not just graphics) + double GetCurrentSystemFrameTime( void ); + double GetRunTime( void ); +private: + // How many frames worth of data have we logged? + int m_totalNumFrames; + + // frame timing data + double m_frameStartTime; + double m_frameEndTime; + double m_minFrameTime; + double m_maxFrameTime; + + // run timing data + double m_runStartTime; + double m_runEndTime; + + bool m_InFrame; +}; + +void CEngineStats::BeginRun( void ) +{ + m_totalNumFrames = 0; + // frame timing data + m_runStartTime = Sys_FloatTime(); +} + +void CEngineStats::EndRun( void ) +{ + m_runEndTime = Sys_FloatTime(); +} + +void CEngineStats::BeginFrame( void ) +{ + m_InFrame = true; + m_frameStartTime = Sys_FloatTime(); +} + +void CEngineStats::EndFrame( void ) +{ + double deltaTime; + + m_frameEndTime = Sys_FloatTime(); + deltaTime = GetCurrentSystemFrameTime(); + + m_InFrame = false; +} + +double CEngineStats::GetRunTime( void ) +{ + return m_runEndTime - m_runStartTime; +} + +double CEngineStats::GetCurrentSystemFrameTime( void ) +{ + return m_frameEndTime - m_frameStartTime; +} +static CEngineStats g_EngineStats; + + +//----------------------------------------------------------------------------- +// Lighting +//----------------------------------------------------------------------------- +// If you change the number of lighting combinations, change LIGHTING_COMBINATION_COUNT +static LightType_t g_LightCombinations[][MAX_LIGHTS] = +{ + { MATERIAL_LIGHT_DISABLE, MATERIAL_LIGHT_DISABLE }, // 0 +// { MATERIAL_LIGHT_SPOT, MATERIAL_LIGHT_DISABLE }, +// { MATERIAL_LIGHT_POINT, MATERIAL_LIGHT_DISABLE }, + { MATERIAL_LIGHT_DIRECTIONAL, MATERIAL_LIGHT_DISABLE }, + { MATERIAL_LIGHT_SPOT, MATERIAL_LIGHT_SPOT }, + +// { MATERIAL_LIGHT_SPOT, MATERIAL_LIGHT_POINT }, // 5 +// { MATERIAL_LIGHT_SPOT, MATERIAL_LIGHT_DIRECTIONAL }, +// { MATERIAL_LIGHT_POINT, MATERIAL_LIGHT_POINT }, + { MATERIAL_LIGHT_POINT, MATERIAL_LIGHT_DIRECTIONAL }, + { MATERIAL_LIGHT_DIRECTIONAL, MATERIAL_LIGHT_DIRECTIONAL }, // 9 +}; + +LightDesc_t g_TestLights[NUM_LIGHT_TYPES][MAX_LIGHTS]; + +static void FixLight( LightDesc_t *pLight ) +{ + pLight->m_Range = 0.0f; + pLight->m_Falloff = 1.0f; + pLight->m_ThetaDot = cos( pLight->m_Theta * 0.5f ); + pLight->m_PhiDot = cos( pLight->m_Phi * 0.5f ); + pLight->m_Flags = 0; + if( pLight->m_Attenuation0 != 0.0f ) + { + pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0; + } + if( pLight->m_Attenuation1 != 0.0f ) + { + pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1; + } + if( pLight->m_Attenuation2 != 0.0f ) + { + pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2; + } + VectorNormalize( pLight->m_Direction ); +} + + +static void InitTestLights( void ) +{ + LightDesc_t *pLight; + int i; + for( i = 0; i < MAX_LIGHTS; i++ ) + { + // MATERIAL_LIGHT_DISABLE + pLight = &g_TestLights[MATERIAL_LIGHT_DISABLE][i]; + pLight->m_Type = MATERIAL_LIGHT_DISABLE; + } + + // x - right + // y - up + // z - front of model + // MATERIAL_LIGHT_SPOT 0 + pLight = &g_TestLights[MATERIAL_LIGHT_SPOT][0]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_SPOT; + pLight->m_Color.Init( 5000.0f, 3500.0f, 3500.0f ); + pLight->m_Position.Init( 0.0f, 0.0f, 50.0f ); + pLight->m_Direction.Init( 0.0f, 0.5f, -1.0f ); + pLight->m_Attenuation0 = 0.0f; + pLight->m_Attenuation1 = 0.0f; + pLight->m_Attenuation2 = 1.0f / 10; + pLight->m_Theta = DEG2RAD( 20.0f ); + pLight->m_Phi = DEG2RAD( 30.0f ); + + // MATERIAL_LIGHT_SPOT 1 + pLight = &g_TestLights[MATERIAL_LIGHT_SPOT][1]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_SPOT; + pLight->m_Color.Init( 3500.0f, 5000.0f, 3500.0f ); + pLight->m_Position.Init( 0.0f, 0.0f, 150.0f ); + pLight->m_Direction.Init( 0.0f, 0.5f, -1.0f ); + pLight->m_Attenuation0 = 0.0f; + pLight->m_Attenuation1 = 0.0f; + pLight->m_Attenuation2 = 1.0f / 10; + pLight->m_Theta = DEG2RAD( 20.0f ); + pLight->m_Phi = DEG2RAD( 30.0f ); + + // MATERIAL_LIGHT_POINT 0 + pLight = &g_TestLights[MATERIAL_LIGHT_POINT][0]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_POINT; + pLight->m_Color.Init( 1500.0f, 750.0f, 750.0f ); + pLight->m_Position.Init( 200.0f, 200.0f, 200.0f ); + pLight->m_Attenuation0 = 0.0f; + pLight->m_Attenuation1 = 1.0f; + pLight->m_Attenuation2 = 0.0f; + + // MATERIAL_LIGHT_POINT 1 + pLight = &g_TestLights[MATERIAL_LIGHT_POINT][1]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_POINT; + pLight->m_Color.Init( 750.0f, 750.0f, 1500.0f ); + pLight->m_Position.Init( -200.0f, 200.0f, 200.0f ); + pLight->m_Attenuation0 = 0.0f; + pLight->m_Attenuation1 = 1.0f; + pLight->m_Attenuation2 = 0.0f; + + // MATERIAL_LIGHT_DIRECTIONAL 0 + pLight = &g_TestLights[MATERIAL_LIGHT_DIRECTIONAL][0]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_DIRECTIONAL; + pLight->m_Color.Init( 2.0f, 2.0f, 1.0f ); + pLight->m_Direction.Init( -1.0f, 0.0f, 0.0f ); + pLight->m_Attenuation0 = 1.0f; + pLight->m_Attenuation1 = 0.0f; + pLight->m_Attenuation2 = 0.0f; + + // MATERIAL_LIGHT_DIRECTIONAL 1 + pLight = &g_TestLights[MATERIAL_LIGHT_DIRECTIONAL][1]; + memset( pLight, 0, sizeof( LightDesc_t ) ); + pLight->m_Type = MATERIAL_LIGHT_DIRECTIONAL; + pLight->m_Color.Init( 1.0f, 1.0f, 2.0f ); + pLight->m_Direction.Init( 1.0f, 0.0f, 0.0f ); + pLight->m_Attenuation0 = 1.0f; + pLight->m_Attenuation1 = 0.0f; + pLight->m_Attenuation2 = 0.0f; + + for( i = 0; i < MAX_LIGHTS; i++ ) + { + int j; + for( j = 0; j < NUM_LIGHT_TYPES; j++ ) + { + FixLight( &g_TestLights[j][i] ); + } + } +} + + +//----------------------------------------------------------------------------- +// Setup lighting +//----------------------------------------------------------------------------- +static void SetupLighting( int lightingCombination, Vector &lightOffset ) +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + if( lightingCombination == 0 ) + { + g_pStudioRender->SetLocalLights( 0, NULL ); + pRenderContext->SetAmbientLight( 1.0, 1.0, 1.0 ); + + static Vector white[6] = + { + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + }; + g_pStudioRender->SetAmbientLightColors( white ); + } + else + { + pRenderContext->SetAmbientLight( 0.0f, 0.0f, 0.0f ); + + static Vector black[6] = + { + Vector( 0.0, 0.0, 0.0 ), + Vector( 0.0, 0.0, 0.0 ), + Vector( 0.0, 0.0, 0.0 ), + Vector( 0.0, 0.0, 0.0 ), + Vector( 0.0, 0.0, 0.0 ), + Vector( 0.0, 0.0, 0.0 ), + }; + g_pStudioRender->SetAmbientLightColors( black ); + + int lightID; + LightDesc_t lightDescs[MAX_LIGHTS]; + for( lightID = 0; lightID < MAX_LIGHTS; lightID++ ) + { + int lightType = g_LightCombinations[lightingCombination][lightID]; + lightDescs[lightID] = g_TestLights[lightType][lightID]; + lightDescs[lightID].m_Position += lightOffset; + } + + // Feed disabled lights through? + if( g_LightCombinations[lightingCombination][1] == MATERIAL_LIGHT_DISABLE ) + { + g_pStudioRender->SetLocalLights( 1, lightDescs ); + } + else + { + g_pStudioRender->SetLocalLights( MAX_LIGHTS, lightDescs ); + } + } +} + + +//----------------------------------------------------------------------------- +// Models +//----------------------------------------------------------------------------- +static float s_PoseParameter[32]; +static float s_Cycle[9] = { 0.0f }; + +virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const +{ + if ( numincludemodels == 0 ) + return NULL; + return g_pMDLCache->GetVirtualModelFast( this, (MDLHandle_t)virtualModel ); +} + +byte *studiohdr_t::GetAnimBlock( int i ) const +{ + return g_pMDLCache->GetAnimBlock( (MDLHandle_t)virtualModel, i ); +} + +int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const +{ + return g_pMDLCache->GetAutoplayList( (MDLHandle_t)virtualModel, pOut ); +} + +const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const +{ + return g_pMDLCache->GetStudioHdr( (MDLHandle_t)cache ); +} + + +//----------------------------------------------------------------------------- +// Set up the bones for a frame +//----------------------------------------------------------------------------- +matrix3x4_t* CIHVTestApp::SetUpBones( studiohdr_t *pStudioHdr, const matrix3x4_t &shapeToWorld, int iRun, int model, int boneMask ) +{ + CStudioHdr studioHdr( pStudioHdr, g_pMDLCache ); + + // Default to middle of the pose parameter range + float flPoseParameter[MAXSTUDIOPOSEPARAM]; + Studio_CalcDefaultPoseParameters( &studioHdr, flPoseParameter, MAXSTUDIOPOSEPARAM ); + + int nFrameCount = Studio_MaxFrame( &studioHdr, g_BenchRuns[iRun].sequence1[model], flPoseParameter ); + if ( nFrameCount == 0 ) + { + nFrameCount = 1; + } + + Vector pos[MAXSTUDIOBONES]; + Quaternion q[MAXSTUDIOBONES]; + + IBoneSetup boneSetup( &studioHdr, boneMask, flPoseParameter ); + boneSetup.InitPose( pos, q ); + boneSetup.AccumulatePose( pos, q, g_BenchRuns[iRun].sequence1[model], s_Cycle[model], 1.0f, 0.0, NULL ); + + // FIXME: Try enabling this? +// CalcAutoplaySequences( pStudioHdr, NULL, pos, q, flPoseParameter, BoneMask( ), flTime ); + + // Root transform + matrix3x4_t rootToWorld, temp; + + MatrixCopy( shapeToWorld, rootToWorld ); + + matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( studioHdr.numbones() ); + for ( int i = 0; i < studioHdr.numbones(); i++ ) + { + // If it's not being used, fill with NAN for errors + if ( !(studioHdr.pBone( i )->flags & boneMask) ) + { + int j, k; + for (j = 0; j < 3; j++) + { + for (k = 0; k < 4; k++) + { + pBoneToWorld[i][j][k] = VEC_T_NAN; + } + } + continue; + } + + matrix3x4_t boneMatrix; + QuaternionMatrix( q[i], boneMatrix ); + MatrixSetColumn( pos[i], 3, boneMatrix ); + + if (studioHdr.pBone(i)->parent == -1) + { + ConcatTransforms (rootToWorld, boneMatrix, pBoneToWorld[i]); + } + else + { + ConcatTransforms (pBoneToWorld[ studioHdr.pBone(i)->parent ], boneMatrix, pBoneToWorld[i] ); + } + } + g_pStudioRender->UnlockBoneMatrices(); + return pBoneToWorld; +} + + +//----------------------------------------------------------------------------- +// Use mdlcache to load a model +//----------------------------------------------------------------------------- +bool CIHVTestApp::LoadModel( const char* pModelName, IHVTestModel *pModel ) +{ + pModel->hMdl = g_pMDLCache->FindMDL( pModelName ); + + pModel->pStudioHdr = g_pMDLCache->GetStudioHdr( pModel->hMdl ); + + g_pMDLCache->GetVertexData( pModel->hMdl ); + g_pMDLCache->FinishPendingLoads(); + + g_pMDLCache->GetHardwareData( pModel->hMdl ); + g_pMDLCache->FinishPendingLoads(); + + pModel->pHardwareData = g_pMDLCache->GetHardwareData( pModel->hMdl ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Loads all models +//----------------------------------------------------------------------------- +bool CIHVTestApp::LoadModels( void ) +{ + const char *pArgVal; + if( CommandLine()->CheckParm( "-rowcol", &pArgVal ) ) + { + g_NumRows = g_NumCols = atoi( pArgVal ); + } + + /* figure out which LOD we are going to render */ + if( CommandLine()->CheckParm( "-lod", &pArgVal ) ) + { + g_LOD = atoi( pArgVal ); + } + + if( CommandLine()->CheckParm( "-body", &pArgVal ) ) + { + g_BodyGroup = atoi( pArgVal ); + } + + // figure out g_RefreshRate + if( CommandLine()->CheckParm( "-refresh", &pArgVal ) ) + { + g_RefreshRate = atoi( pArgVal ); + } + + if( CommandLine()->CheckParm( "-light", &pArgVal ) ) + { + g_LightingCombination = atoi( pArgVal ); + if( g_LightingCombination < 0 ) + { + g_LightingCombination = 0; + } + if( g_LightingCombination >= LIGHTING_COMBINATION_COUNT ) + { + g_LightingCombination = LIGHTING_COMBINATION_COUNT - 1; + } + } + + g_pForceMaterial = g_pMaterialSystem->FindMaterial( "models/alyx/thigh", TEXTURE_GROUP_OTHER ); +#ifdef MATERIAL_OVERRIDE + g_pStudioRender->ForcedMaterialOverride( g_pForceMaterial ); +#endif + + InitTestLights(); + + if( g_BenchMode ) + { + int i; + for( i = 0; i < NUM_BENCH_RUNS; i++ ) + { + // Load each of the potentially alternating models: + int k; + for( k = 0; k < g_nMaxModels; k++ ) + { + if( g_BenchRuns[i].pModelName[k] ) + { + if( !LoadModel( g_BenchRuns[i].pModelName[k], &g_BenchModels[i][k] ) ) + { + return false; + } + } + } + } + } + else + { + CommandLine()->CheckParm( "-i", &pArgVal ); + if( !LoadModel( pArgVal, m_pIHVTestModel ) ) + { + return false; + } + } + g_pMaterialSystem->CacheUsedMaterials(); + + return true; +} + + +//----------------------------------------------------------------------------- +// App window proc +//----------------------------------------------------------------------------- +LONG CIHVTestApp::WindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + switch( msg ) + { + // abort when ESC is hit + case WM_CHAR: + switch(wParam) + { + case VK_ESCAPE: + SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); + break; + } + break; + + case WM_DESTROY: + m_bExitMainLoop = true; + return 0; + } + + return DefWindowProc( hWnd, msg, wParam, lParam ); +} + + +//----------------------------------------------------------------------------- +// Static registered window proc +//----------------------------------------------------------------------------- +LONG WINAPI CIHVTestApp::WinAppWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + return s_IHVTestApp.WindowProc( hWnd, uMsg, wParam, lParam ); +} + + +//----------------------------------------------------------------------------- +// Pump messages +//----------------------------------------------------------------------------- +void CIHVTestApp::AppPumpMessages() +{ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == TRUE) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + + +//----------------------------------------------------------------------------- +// Advance the frame +//----------------------------------------------------------------------------- +void AdvanceFrame( CStudioHdr *pStudioHdr, int iRun, int model, float dt ) +{ + if (dt > 0.1) + dt = 0.1f; + + float t = Studio_Duration( pStudioHdr, g_BenchRuns[iRun].sequence1[model], s_PoseParameter ); + + if (t > 0) + { + s_Cycle[model] += dt / t; + + // wrap + s_Cycle[model] -= (int)(s_Cycle[model]); + } + else + { + s_Cycle[model] = 0; + } +} + + +//----------------------------------------------------------------------------- +// Render a frame +//----------------------------------------------------------------------------- +void CIHVTestApp::RenderFrame( void ) +{ + VPROF( "RenderFrame" ); + IHVTestModel *pModel = NULL; + static int currentRun = 0; + static int currentFrame = 0; + static int currentLightCombo = 0; + int modelAlternator = 0; + + if (g_bInError) + { + // error context is active + // error may be renderer based, avoid re-entrant render to fatal crash + return; + } + + if( g_BenchMode ) + { + if( currentFrame > g_BenchRuns[currentRun].numFrames ) + { + currentLightCombo++; + if( currentLightCombo >= LIGHTING_COMBINATION_COUNT ) + { + currentRun++; + currentLightCombo = 0; + if( currentRun >= NUM_BENCH_RUNS ) + { + g_BenchFinished = true; + return; + } + } + currentFrame = 0; + } + } + if( g_BenchMode ) + { + pModel = &g_BenchModels[currentRun][0]; + g_NumCols = g_BenchRuns[currentRun].cols; + g_NumRows = g_BenchRuns[currentRun].rows; + } + else + { + pModel = m_pIHVTestModel; + } + Assert( pModel ); + + g_EngineStats.BeginFrame(); + + g_pMaterialSystem->BeginFrame( 0 ); + g_pStudioRender->BeginFrame(); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + pRenderContext->ClearColor3ub( 0, 0, 0 ); + pRenderContext->ClearBuffers( true, true ); + + pRenderContext->Viewport( 0, 0, g_RenderWidth, g_RenderHeight ); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->LoadIdentity(); + pRenderContext->PerspectiveX( 90.0f, ( g_RenderWidth / g_RenderHeight), 1.0f, 500000.0f ); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadIdentity(); + if( g_BenchMode ) + { + pRenderContext->Translate( 0.0f, 0.0f, ( float )-( g_NumCols * g_BenchRuns[currentRun].modelSize * 0.6f ) ); + } + else + { + pRenderContext->Translate( 0.0f, 0.0f, ( float )-( g_NumCols * 80.0f * 0.5f ) ); + } + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->LoadIdentity(); + + QAngle angles; + angles[YAW] = -90.0f; + angles[PITCH] = -90.0f; + angles[ROLL] = 0.0f; + + matrix3x4_t cameraMatrix; + AngleMatrix( angles, cameraMatrix ); + + int r, c; + int trisRendered = 0; + float boneSetupTime = 0.0f; + for( r = 0; r < g_NumRows; r++ ) + { + for( c = 0; c < g_NumCols; c++ ) + { + // If we are alternating models, select the next valid model. + if( g_BenchMode ) + { + do + { + // If I pass my maximum number of models, wrap around to model 0, which must always be valid. + if( ++modelAlternator >= g_nMaxModels ) + { + modelAlternator = 0; + break; + } + } + while( !g_BenchRuns[currentRun].pModelName[modelAlternator] ); + + pModel = &g_BenchModels[currentRun][modelAlternator]; + Assert( pModel ); + } + + if( g_BenchMode ) + { + cameraMatrix[0][3] = ( ( c + 0.5f ) - ( g_NumCols * .5f ) ) * g_BenchRuns[currentRun].modelSize; + cameraMatrix[1][3] = ( ( float )r - ( g_NumCols * .5f ) ) * g_BenchRuns[currentRun].modelSize; + } + else + { + cameraMatrix[0][3] = ( ( c + 0.5f ) - ( g_NumCols * .5f ) ) * 75.0f; + cameraMatrix[1][3] = ( ( float )r - ( g_NumCols * .5f ) ) * 75.0f; + } + + Vector modelOrigin( cameraMatrix[0][3], cameraMatrix[1][3], 0.0f ); + Vector lightOffset( cameraMatrix[0][3], cameraMatrix[1][3], 0.0f ); + + if (g_LightingCombination < 0) + { + SetupLighting( g_BenchMode ? currentLightCombo : 0, lightOffset ); + } + else + { + SetupLighting( g_LightingCombination, lightOffset ); + } + + float startBoneSetupTime = Sys_FloatTime(); + int lod = g_LOD; + lod = clamp( lod, pModel->pHardwareData->m_RootLOD, pModel->pHardwareData->m_NumLODs-1 ); + + int boneMask = BONE_USED_BY_VERTEX_AT_LOD( lod ); + matrix3x4_t *pBoneToWorld = SetUpBones( pModel->pStudioHdr, cameraMatrix, currentRun, modelAlternator, boneMask ); + boneSetupTime += Sys_FloatTime() - startBoneSetupTime; + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + + DrawModelInfo_t modelInfo; + memset( &modelInfo, 0, sizeof( modelInfo ) ); + modelInfo.m_pStudioHdr = pModel->pStudioHdr; + modelInfo.m_pHardwareData = pModel->pHardwareData; + modelInfo.m_Decals = STUDIORENDER_DECAL_INVALID; + modelInfo.m_Skin = 0; + modelInfo.m_Body = g_BodyGroup; + modelInfo.m_HitboxSet = 0; + modelInfo.m_pClientEntity = NULL; + modelInfo.m_Lod = lod; + modelInfo.m_pColorMeshes = NULL; + g_pStudioRender->DrawModel( NULL, modelInfo, pBoneToWorld, NULL, NULL, modelOrigin ); + + DrawModelResults_t results; + g_pStudioRender->GetPerfStats( &results, modelInfo, NULL ); + trisRendered += results.m_ActualTriCount; + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PopMatrix(); + } + } + + pRenderContext->Flush( true ); + g_EngineStats.EndFrame(); + + g_pStudioRender->EndFrame(); + g_pMaterialSystem->EndFrame(); + + // hack - don't count the first frame in case there are any state + // transitions computed on that frame. + if( currentFrame != 0 ) + { + g_BenchResults[currentRun][currentLightCombo].totalTime += g_EngineStats.GetCurrentSystemFrameTime(); + g_BenchResults[currentRun][currentLightCombo].totalTris += trisRendered; + } + + for ( int model = 0; model < g_nMaxModels; ++model ) + { + CStudioHdr studioHdr( g_BenchModels[currentRun][model].pStudioHdr, g_pMDLCache ); + AdvanceFrame( &studioHdr, currentRun, model, g_EngineStats.GetCurrentSystemFrameTime() ); + } + + g_pMaterialSystem->SwapBuffers(); + +#ifdef USE_VPROF + g_VProfCurrentProfile.MarkFrame(); + static bool bBeenHere = false; + if( !bBeenHere ) + { + bBeenHere = true; + g_VProfCurrentProfile.Reset(); + } +#endif + currentFrame++; +} + + +//----------------------------------------------------------------------------- +// Create the application object +//----------------------------------------------------------------------------- +bool CIHVTestApp::Create() +{ + AppSystemInfo_t appSystems[] = + { + { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION }, + { "datacache.dll", DATACACHE_INTERFACE_VERSION }, + { "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION }, + { "datacache.dll", MDLCACHE_INTERFACE_VERSION }, + { "vphysics.dll", VPHYSICS_INTERFACE_VERSION }, + { "", "" } // Required to terminate the list + }; + + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); + + if ( !AddSystems( appSystems ) ) + return false; + + g_pFileSystem = ( IFileSystem * )FindSystem( FILESYSTEM_INTERFACE_VERSION ); + g_pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION ); + g_pStudioRender = (IStudioRender*)FindSystem( STUDIO_RENDER_INTERFACE_VERSION ); + g_pMDLCache = (IMDLCache*)FindSystem( MDLCACHE_INTERFACE_VERSION ); + + if ( !g_pFileSystem || !g_pMaterialSystem || !g_pStudioRender || !g_pMDLCache ) + { + DisplayError( "Unable to load required library interfaces!" ); + return false; + } + +#if defined( _X360 ) + // vxconsole - true will block (legacy behavior) + XBX_InitConsoleMonitor( false ); +#endif + + const char* pDLLName; + if ( CommandLine()->CheckParm( "-null" ) ) + { + g_bUseEmptyShader = true; + pDLLName = "shaderapiempty.dll"; + } + else + { + pDLLName = "shaderapidx9.dll"; + } + +#if defined( _X360 ) + g_pFileSystem->LoadModule( pDLLName ); +#endif + g_pMaterialSystem->SetShaderAPI( pDLLName ); + + return true; +} + + +//----------------------------------------------------------------------------- +// StudioRender... +//----------------------------------------------------------------------------- +bool CIHVTestApp::SetupStudioRender( void ) +{ + StudioRenderConfig_t config; + memset( &config, 0, sizeof(config) ); + + config.bEyeMove = true; + config.bTeeth = true; + config.bEyes = true; + config.bFlex = true; + + config.fEyeShiftX = 0.0f; + config.fEyeShiftY = 0.0f; + config.fEyeShiftZ = 0.0f; + config.fEyeSize = 0.0f; + + config.bNoHardware = false; + config.bNoSoftware = false; + + config.bSoftwareSkin = false; + config.bSoftwareLighting = false; + + config.drawEntities = true; + config.bWireframe = false; + config.bDrawNormals = false; + config.bDrawTangentFrame = false; + config.skin = 0; + + config.fullbright = 0; + + config.bShowEnvCubemapOnly = false; + + g_pStudioRender->UpdateConfig( config ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Material system +//----------------------------------------------------------------------------- +bool InitMaterialSystem( HWND mainWindow ) +{ + MaterialSystem_Config_t config; + if( g_WindowMode ) + { + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true ); + } + config.SetFlag( MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC, IsX360() ? 0 : true ); + + config.m_VideoMode.m_Width = 0; + config.m_VideoMode.m_Height = 0; + config.m_VideoMode.m_Format = IMAGE_FORMAT_BGRX8888; + config.m_VideoMode.m_RefreshRate = g_RefreshRate; + config.dxSupportLevel = IsX360() ? 98 : 0; + + bool modeSet = g_pMaterialSystem->SetMode( (void*)mainWindow, config ); + if (!modeSet) + { + DisplayError( "Unable to set mode\n" ); + return false; + } + + g_pMaterialSystem->OverrideConfig( config, false ); + + return true; +} + + +//----------------------------------------------------------------------------- +// PreInit +//----------------------------------------------------------------------------- +bool CIHVTestApp::PreInit( void ) +{ + CreateInterfaceFn factory = GetFactory(); + ConnectTier1Libraries( &factory, 1 ); + + // Add paths... + if ( !SetupSearchPaths( NULL, false, true ) ) + { + Error( "Failed to setup search paths\n" ); + return false; + } + + const char *pArgVal; + if ( CommandLine()->CheckParm( "-bench" ) ) + { + g_BenchMode = true; + } + + if( !g_BenchMode && !CommandLine()->CheckParm( "-i" ) ) + { + // Set some default parameters for running as a unittest + g_BenchMode = true; + g_WindowMode = IsPC() ? true : false; + } + + if( g_BenchMode ) + { + if ( CommandLine()->CheckParm( "-i", &pArgVal ) ) + { + g_BenchRuns[0].pModelName[0] = pArgVal; + } + } + + if( CommandLine()->CheckParm( "-softwaretl" ) ) + { + g_SoftwareTL = true; + } + + // Explicitly in window/fullscreen mode? + if ( CommandLine()->CheckParm( "-window") ) + { + g_WindowMode = true; + } + else if ( CommandLine()->CheckParm( "-fullscreen" ) ) + { + g_WindowMode = false; + } + + /* figure out g_Renderwidth and g_RenderHeight */ + g_RenderWidth = -1; + g_RenderHeight = -1; + + if( CommandLine()->CheckParm( "-width", &pArgVal ) ) + { + g_RenderWidth = atoi( pArgVal ); + } + if( CommandLine()->CheckParm( "-height", &pArgVal ) ) + { + g_RenderHeight = atoi( pArgVal ); + } + + if( g_RenderWidth == -1 && g_RenderHeight == -1 ) + { + g_RenderWidth = 640; + g_RenderHeight = 480; + } + else if( g_RenderWidth != -1 && g_RenderHeight == -1 ) + { + switch( g_RenderWidth ) + { + case 320: + g_RenderHeight = 240; + break; + case 512: + g_RenderHeight = 384; + break; + case 640: + g_RenderHeight = 480; + break; + case 800: + g_RenderHeight = 600; + break; + case 1024: + g_RenderHeight = 768; + break; + case 1280: + g_RenderHeight = 1024; + break; + case 1600: + g_RenderHeight = 1200; + break; + default: + DisplayError( "Can't figure out window dimensions!!" ); + exit( -1 ); + break; + } + } + + if( g_RenderWidth == -1 || g_RenderHeight == -1 ) + { + DisplayError( "Can't figure out window dimensions!!" ); + exit( -1 ); + } + + int windowWidth, windowHeight; + CalcWindowSize( g_RenderWidth, g_RenderHeight, &windowWidth, &windowHeight ); + + if( !CreateAppWindow( "ihvtest1", windowWidth, windowHeight ) ) + { + return false; + } + return true; +} + +void CIHVTestApp::PostShutdown() +{ + DisconnectTier1Libraries(); +} + + +//----------------------------------------------------------------------------- +// The application main loop +//----------------------------------------------------------------------------- +int CIHVTestApp::Main() +{ + SpewOutputFunc( IHVTestSpewFunc ); + + if ( !SetupStudioRender() ) + { + return 0; + } + + if ( !InitMaterialSystem( m_hWnd ) ) + { + return 0; + } + +#if !defined( _X360 ) // X360TBD: +extern void Sys_InitFloatTime( void ); //garymcthack + Sys_InitFloatTime(); +#endif + + LoadModels(); + +#if USE_VTUNE + VTResume(); +#endif +#ifdef USE_VPROF + g_VProfCurrentProfile.Start(); +#endif + + bool m_bExitMainLoop = false; + while (!m_bExitMainLoop && !g_BenchFinished) + { + AppPumpMessages(); + RenderFrame(); + } + +#ifdef USE_VPROF + g_VProfCurrentProfile.Stop(); +#endif + g_IHVTestFP = fopen( "ihvtest_vprof.txt", "w" ); +#ifdef USE_VPROF + SpewOutputFunc( IHVTestVProfSpewFunc ); + g_VProfCurrentProfile.OutputReport( VPRT_SUMMARY ); + g_VProfCurrentProfile.OutputReport( VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY ); + fclose( g_IHVTestFP ); + SpewOutputFunc( IHVTestSpewFunc ); +#endif +#if USE_VTUNE + VTPause(); +#endif + + return 0; +} + diff --git a/unittests/ihvtest1/ihvtest1.vpc b/unittests/ihvtest1/ihvtest1.vpc new file mode 100644 index 0000000..80731ca --- /dev/null +++ b/unittests/ihvtest1/ihvtest1.vpc @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------------- +// IHVTEST1.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin\unittests" + +$Include "$SRCDIR\vpc_scripts\source_exe_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE;$SRCDIR\game\shared" + $PreprocessorDefinitions "$BASE;IHVTEST" + } +} + +$Project "ihvtest1" +{ + $Folder "Source Files" + { + $File "$SRCDIR\public\bone_setup.cpp" + $File "$SRCDIR\public\collisionutils.cpp" + $File "ihvtest1.cpp" + $File "$SRCDIR\public\studio.cpp" + $File "sys_clock.cpp" [$WIN32] + } + + $Folder "Public Header Files" + { + $File "$SRCDIR\public\mathlib\amd3dx.h" + $File "$SRCDIR\public\basehandle.h" + $File "$SRCDIR\public\tier0\basetypes.h" + $File "$SRCDIR\public\bitvec.h" + $File "$SRCDIR\public\bone_accessor.h" + $File "$SRCDIR\public\bone_setup.h" + $File "$SRCDIR\public\bspflags.h" + $File "$SRCDIR\public\clientstats.h" + $File "$SRCDIR\public\cmodel.h" + $File "$SRCDIR\public\CollisionUtils.h" + $File "$SRCDIR\public\tier0\commonmacros.h" + $File "$SRCDIR\public\mathlib\compressed_vector.h" + $File "$SRCDIR\public\const.h" + $File "$SRCDIR\public\tier0\dbg.h" + $File "$SRCDIR\public\tier0\fasttimer.h" + $File "$SRCDIR\public\filesystem.h" + $File "$SRCDIR\public\gametrace.h" + $File "$SRCDIR\public\appframework\IAppSystem.h" + $File "$SRCDIR\public\tier0\icommandline.h" + $File "$SRCDIR\public\ihandleentity.h" + $File "$SRCDIR\public\materialsystem\imaterialproxyfactory.h" + $File "$SRCDIR\public\materialsystem\imaterialsystem.h" + $File "$SRCDIR\public\materialsystem\imaterialsystemhardwareconfig.h" + $File "$SRCDIR\public\tier1\interface.h" + $File "$SRCDIR\public\istudiorender.h" + $File "$SRCDIR\public\materialsystem\materialsystem_config.h" + $File "$SRCDIR\public\mathlib\mathlib.h" + $File "$SRCDIR\public\tier0\mem.h" + $File "$SRCDIR\public\tier0\memalloc.h" + $File "$SRCDIR\public\tier0\memdbgon.h" + $File "$SRCDIR\public\tier0\platform.h" + $File "$SRCDIR\public\tier0\protected_things.h" + $File "$SRCDIR\public\vstdlib\random.h" + $File "$SRCDIR\public\string_t.h" + $File "$SRCDIR\public\tier1\strtools.h" + $File "$SRCDIR\public\studio.h" + $File "$SRCDIR\public\tier1\utlbuffer.h" + $File "$SRCDIR\public\tier1\utldict.h" + $File "$SRCDIR\public\tier1\utlmemory.h" + $File "$SRCDIR\public\tier1\utlrbtree.h" + $File "$SRCDIR\public\tier1\utlsymbol.h" + $File "$SRCDIR\public\tier1\utlvector.h" + $File "$SRCDIR\public\vcollide.h" + $File "$SRCDIR\public\mathlib\vector.h" + $File "$SRCDIR\public\mathlib\vector2d.h" + $File "$SRCDIR\public\mathlib\vector4d.h" + $File "$SRCDIR\public\tier0\vprof.h" + $File "$SRCDIR\public\vstdlib\vstdlib.h" + } + + $Folder "Build Bat Files" [$0] + { + $File "copybin.bat" + $File "copycommonsrc.bat" + $File "copydx8.bat" + $File "copygamesharedsrc.bat" + $File "copyihvtestsrc.bat" + $File "copylib.bat" + $File "copymatsyssrc.bat" + $File "copypublicsrc.bat" + $File "copyshaderdx8src.bat" + $File "copysrc.bat" + $File "copystudiorendersrc.bat" + } + + $Folder "Link Libraries" + { + $Lib appframework + $Lib mathlib + $Lib $LIBCOMMON\vtuneapi [$WIN32&&!$VS2015] + $Lib $SRCDIR\lib\common\vtuneapi [$WIN32&&$VS2015] + } +} diff --git a/unittests/ihvtest1/sys_clock.cpp b/unittests/ihvtest1/sys_clock.cpp new file mode 100644 index 0000000..4412ed8 --- /dev/null +++ b/unittests/ihvtest1/sys_clock.cpp @@ -0,0 +1,254 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +#include <assert.h> + +#pragma optimize( "", off ) + +#pragma pack( push, thing ) +#pragma pack( 4 ) +static long g_cw, g_single_cw, g_highchop_cw, g_full_cw, g_ceil_cw, g_pushed_cw; +static struct +{ + long dummy[8]; +} g_fpenv; +#pragma pack( pop, thing ) + + +void __declspec ( naked ) MaskExceptions() +{ + _asm + { + fnstenv ds:dword ptr[g_fpenv] + or ds:dword ptr[g_fpenv],03Fh + fldenv ds:dword ptr[g_fpenv] + ret + } +} + +void __declspec ( naked ) Sys_SetFPCW() +{ + _asm + { + fnstcw ds:word ptr[g_cw] + mov eax,ds:dword ptr[g_cw] + and ah,0F0h + or ah,003h + mov ds:dword ptr[g_full_cw],eax + mov ds:dword ptr[g_highchop_cw],eax + and ah,0F0h + or ah,00Ch + mov ds:dword ptr[g_single_cw],eax + and ah,0F0h + or ah,008h + mov ds:dword ptr[g_ceil_cw],eax + ret + } +} + +void __declspec ( naked ) Sys_PushFPCW_SetHigh() +{ + _asm + { + fnstcw ds:word ptr[g_pushed_cw] + fldcw ds:word ptr[g_full_cw] + ret + } +} + +void __declspec ( naked ) Sys_PopFPCW() +{ + _asm + { + fldcw ds:word ptr[g_pushed_cw] + ret + } +} + +#pragma optimize( "", on ) + +//----------------------------------------------------------------------------- +// Purpose: Implements high precision clock +// TODO: Make into an interface? +//----------------------------------------------------------------------------- +class CSysClock +{ +public: + // Construction + CSysClock( void ); + + // Initialization + void Init( void ); + void SetStartTime( void ); + + // Sample the clock + double GetTime( void ); + +private: + // High performance clock frequency + double m_dClockFrequency; + // Current accumulated time + double m_dCurrentTime; + // How many bits to shift raw 64 bit sample count by + int m_nTimeSampleShift; + // Previous 32 bit sample count + unsigned int m_uiPreviousTime; + + bool m_bInitialized; +}; + +static CSysClock g_Clock; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CSysClock::CSysClock( void ) +{ + m_bInitialized = false; +} + +//----------------------------------------------------------------------------- +// Purpose: Initialize the clock +//----------------------------------------------------------------------------- +void CSysClock::Init( void ) +{ + BOOL success; + LARGE_INTEGER PerformanceFreq; + unsigned int lowpart, highpart; + + MaskExceptions (); + Sys_SetFPCW (); + + // Start clock at zero + m_dCurrentTime = 0.0; + + success = QueryPerformanceFrequency( &PerformanceFreq ); + assert( success ); + + // get 32 out of the 64 time bits such that we have around + // 1 microsecond resolution + lowpart = (unsigned int)PerformanceFreq.LowPart; + highpart = (unsigned int)PerformanceFreq.HighPart; + + m_nTimeSampleShift = 0; + + while ( highpart || ( lowpart > 2000000.0 ) ) + { + m_nTimeSampleShift++; + lowpart >>= 1; + lowpart |= (highpart & 1) << 31; + highpart >>= 1; + } + + m_dClockFrequency = 1.0 / (double)lowpart; + + // Get initial sample + unsigned int temp; + LARGE_INTEGER PerformanceCount; + QueryPerformanceCounter( &PerformanceCount ); + if ( !m_nTimeSampleShift ) + { + temp = (unsigned int)PerformanceCount.LowPart; + } + else + { + // Rotate counter to right by m_nTimeSampleShift places + temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) | + ((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift)); + } + + // Set first time stamp + m_uiPreviousTime = temp; + + m_bInitialized = true; + + SetStartTime(); +} + +void CSysClock::SetStartTime( void ) +{ + GetTime(); + + m_dCurrentTime = 0.0; + + m_uiPreviousTime = ( unsigned int )m_dCurrentTime; +} + +double CSysClock::GetTime( void ) +{ + LARGE_INTEGER PerformanceCount; + unsigned int temp, t2; + double time; + + if ( !m_bInitialized ) + { + return 0.0; + } + + Sys_PushFPCW_SetHigh(); + + // Get sample counter + QueryPerformanceCounter( &PerformanceCount ); + + if ( !m_nTimeSampleShift ) + { + temp = (unsigned int)PerformanceCount.LowPart; + } + else + { + // Rotate counter to right by m_nTimeSampleShift places + temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) | + ((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift)); + } + + // check for turnover or backward time + if ( ( temp <= m_uiPreviousTime ) && + ( ( m_uiPreviousTime - temp ) < 0x10000000) ) + { + m_uiPreviousTime = temp; // so we can't get stuck + } + else + { + // gap in performance clocks + t2 = temp - m_uiPreviousTime; + + // Convert to time using frequencey of clock + time = (double)t2 * m_dClockFrequency; + + // Remember old time + m_uiPreviousTime = temp; + + // Increment clock + m_dCurrentTime += time; + } + + Sys_PopFPCW(); + + // Convert to float + return m_dCurrentTime; + +} + +//----------------------------------------------------------------------------- +// Purpose: Sample the high-precision clock +// Output : double +//----------------------------------------------------------------------------- +double Sys_FloatTime( void ) +{ + return g_Clock.GetTime(); +} + +//----------------------------------------------------------------------------- +// Purpose: Initialize high-precision clock +//----------------------------------------------------------------------------- +void Sys_InitFloatTime( void ) +{ + g_Clock.Init(); +} diff --git a/unittests/inputtest/inputtest.cpp b/unittests/inputtest/inputtest.cpp new file mode 100644 index 0000000..5b9781b --- /dev/null +++ b/unittests/inputtest/inputtest.cpp @@ -0,0 +1,250 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Material editor +//============================================================================= + +#include <windows.h> +#include "appframework/tier2app.h" +#include "inputsystem/iinputsystem.h" +#include "filesystem.h" +#include "filesystem_init.h" +#include "tier0/icommandline.h" + + +//----------------------------------------------------------------------------- +// Purpose: Warning/Msg call back through this API +// Input : type - +// *pMsg - +// Output : SpewRetval_t +//----------------------------------------------------------------------------- +SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg ) +{ + OutputDebugString( pMsg ); + return SPEW_CONTINUE; +} + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CInputTestApp : public CTier2SteamApp +{ + typedef CTier2SteamApp BaseClass; + +public: + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit( ); + virtual int Main(); + virtual void PostShutdown( ); + virtual void Destroy(); + virtual const char *GetAppName() { return "InputTest"; } + virtual bool AppUsesReadPixels() { return false; } + +private: + // Window management + bool CreateAppWindow( char const *pTitle, bool bWindowed, int w, int h ); + + // Sets up the game path + bool SetupSearchPaths(); + + HWND m_HWnd; +}; + +DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT( CInputTestApp ); + + +//----------------------------------------------------------------------------- +// Create all singleton systems +//----------------------------------------------------------------------------- +bool CInputTestApp::Create() +{ + SpewOutputFunc( SpewFunc ); + + AppSystemInfo_t appSystems[] = + { + { "inputsystem.dll", INPUTSYSTEM_INTERFACE_VERSION }, + { "", "" } // Required to terminate the list + }; + + if ( !AddSystems( appSystems ) ) + return false; + + return true; +} + +void CInputTestApp::Destroy() +{ +} + + +//----------------------------------------------------------------------------- +// Window management +//----------------------------------------------------------------------------- +bool CInputTestApp::CreateAppWindow( char const *pTitle, bool bWindowed, int w, int h ) +{ + WNDCLASSEX wc; + memset( &wc, 0, sizeof( wc ) ); + wc.cbSize = sizeof( wc ); + wc.style = CS_OWNDC | CS_DBLCLKS; + wc.lpfnWndProc = DefWindowProc; + wc.hInstance = (HINSTANCE)GetAppInstance(); + wc.lpszClassName = "Valve001"; + wc.hIcon = NULL; //LoadIcon( s_HInstance, MAKEINTRESOURCE( IDI_LAUNCHER ) ); + wc.hIconSm = wc.hIcon; + + RegisterClassEx( &wc ); + + // Note, it's hidden + DWORD style = WS_POPUP | WS_CLIPSIBLINGS; + + if ( bWindowed ) + { + // Give it a frame + style |= WS_OVERLAPPEDWINDOW; + style &= ~WS_THICKFRAME; + } + + // Never a max box + style &= ~WS_MAXIMIZEBOX; + + RECT windowRect; + windowRect.top = 0; + windowRect.left = 0; + windowRect.right = w; + windowRect.bottom = h; + + // Compute rect needed for that size client area based on window style + AdjustWindowRectEx(&windowRect, style, FALSE, 0); + + // Create the window + m_HWnd = CreateWindow( wc.lpszClassName, pTitle, style, 0, 0, + windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, + NULL, NULL, (HINSTANCE)GetAppInstance(), NULL ); + + if (!m_HWnd) + return false; + + int CenterX, CenterY; + + CenterX = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; + CenterY = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; + CenterX = (CenterX < 0) ? 0: CenterX; + CenterY = (CenterY < 0) ? 0: CenterY; + + // In VCR modes, keep it in the upper left so mouse coordinates are always relative to the window. + SetWindowPos (m_HWnd, NULL, CenterX, CenterY, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); + + return true; +} + + +//----------------------------------------------------------------------------- +// Sets up the game path +//----------------------------------------------------------------------------- +bool CInputTestApp::SetupSearchPaths() +{ + if ( !BaseClass::SetupSearchPaths( NULL, false, true ) ) + return false; + + g_pFullFileSystem->AddSearchPath( GetGameInfoPath(), "SKIN", PATH_ADD_TO_HEAD ); + return true; +} + + +//----------------------------------------------------------------------------- +// PreInit, PostShutdown +//----------------------------------------------------------------------------- +bool CInputTestApp::PreInit( ) +{ + if ( !BaseClass::PreInit() ) + return false; + + if (!g_pFullFileSystem || !g_pInputSystem ) + return false; + + // Add paths... + if ( !SetupSearchPaths() ) + return false; + + const char *pArg; + int iWidth = 1024; + int iHeight = 768; + bool bWindowed = (CommandLine()->CheckParm( "-fullscreen" ) == NULL); + if (CommandLine()->CheckParm( "-width", &pArg )) + { + iWidth = atoi( pArg ); + } + if (CommandLine()->CheckParm( "-height", &pArg )) + { + iHeight = atoi( pArg ); + } + + if (!CreateAppWindow( "InputTest", bWindowed, iWidth, iHeight )) + return false; + + g_pInputSystem->AttachToWindow( m_HWnd ); + return true; +} + +void CInputTestApp::PostShutdown( ) +{ + g_pInputSystem->DetachFromWindow( ); + BaseClass::PostShutdown(); +} + + + +//----------------------------------------------------------------------------- +// main application +//----------------------------------------------------------------------------- +int CInputTestApp::Main() +{ + while( true ) + { + g_pInputSystem->PollInputState(); + + int nEventCount = g_pInputSystem->GetEventCount(); + const InputEvent_t* pEvents = g_pInputSystem->GetEventData( ); + for ( int i = 0; i < nEventCount; ++i ) + { + const InputEvent_t* pEvent = &pEvents[i]; + switch( pEvent->m_nType ) + { + case IE_ButtonPressed: + Msg("Button Pressed Event %d : Start tick %d\n", pEvent->m_nData, pEvent->m_nTick ); + break; + + case IE_ButtonReleased: + Msg("Button Released Event %d : End tick %d Start tick %d\n", pEvent->m_nData, pEvent->m_nTick, g_pInputSystem->GetButtonPressedTick( (ButtonCode_t)pEvent->m_nData ) ); + break; + + case IE_ButtonDoubleClicked: + Msg("Button Double clicked Event %d : Start tick %d\n", pEvent->m_nData, pEvent->m_nTick ); + break; + + case IE_AnalogValueChanged: + Msg("Analog Value Changed %d : Start tick %d Value %d\n", pEvent->m_nData, pEvent->m_nTick, pEvent->m_nData2 ); + break; + + case IE_Quit: + Msg("Quit"); + return 1; + } + } + } + + return 1; +} + + + diff --git a/unittests/inputtest/inputtest.vpc b/unittests/inputtest/inputtest.vpc new file mode 100644 index 0000000..a377b82 --- /dev/null +++ b/unittests/inputtest/inputtest.vpc @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// INPUTTEST.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_base.vpc" + +$Project "Inputtest" +{ + $Folder "Source Files" + { + $File "inputtest.cpp" + } + + $Folder "Link Libraries" + { + $Lib appframework + $Lib tier2 + } +} diff --git a/unittests/materialsystemtest/materialsystemtest.cpp b/unittests/materialsystemtest/materialsystemtest.cpp new file mode 100644 index 0000000..9a193bf --- /dev/null +++ b/unittests/materialsystemtest/materialsystemtest.cpp @@ -0,0 +1,492 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Material editor +//============================================================================= + +#include <windows.h> +#include "appframework/tier2app.h" +#include "materialsystem/materialsystem_config.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "vstdlib/random.h" +#include "filesystem.h" +#include "filesystem_init.h" +#include "tier0/icommandline.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "materialsystem/imesh.h" + + +//----------------------------------------------------------------------------- +// Purpose: Warning/Msg call back through this API +// Input : type - +// *pMsg - +// Output : SpewRetval_t +//----------------------------------------------------------------------------- +SpewRetval_t SpewFunc( SpewType_t type, const char *pMsg ) +{ + if ( Plat_IsInDebugSession() ) + { + OutputDebugString( pMsg ); + if ( type == SPEW_ASSERT ) + return SPEW_DEBUGGER; + } + return SPEW_CONTINUE; +} + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CMaterialSystemTestApp : public CTier2SteamApp +{ + typedef CTier2SteamApp BaseClass; + +public: + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit( ); + virtual int Main(); + virtual void PostShutdown( ); + virtual void Destroy(); + virtual const char *GetAppName() { return "MaterialSystemTest"; } + virtual bool AppUsesReadPixels() { return false; } + +private: + // Window management + bool CreateAppWindow( const char *pTitle, bool bWindowed, int w, int h ); + + // Sets up the game path + bool SetupSearchPaths(); + + // Waits for a keypress + bool WaitForKeypress(); + + // Sets the video mode + bool SetMode(); + + // Tests dynamic buffers + void TestDynamicBuffers( IMatRenderContext *pRenderContext, bool bBuffered ); + + // Creates, destroys a test material + void CreateWireframeMaterial(); + void DestroyMaterial(); + + CMaterialReference m_pMaterial; + + HWND m_HWnd; +}; + +DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT( CMaterialSystemTestApp ); + + +//----------------------------------------------------------------------------- +// Create all singleton systems +//----------------------------------------------------------------------------- +bool CMaterialSystemTestApp::Create() +{ + SpewOutputFunc( SpewFunc ); + + AppSystemInfo_t appSystems[] = + { + { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION }, + + // Required to terminate the list + { "", "" } + }; + + if ( !AddSystems( appSystems ) ) + return false; + + IMaterialSystem *pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION ); + if ( !pMaterialSystem ) + { + Warning( "CMaterialSystemTestApp::Create: Unable to connect to necessary interface!\n" ); + return false; + } + + bool bIsVistaOrHigher = false; + + OSVERSIONINFO info; + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if ( GetVersionEx( &info ) ) + { + bIsVistaOrHigher = info.dwMajorVersion >= 6; + } + + const char *pShaderDLL = CommandLine()->ParmValue( "-shaderdll" ); + if ( !pShaderDLL ) + { + pShaderDLL = "shaderapidx10.dll"; + } + + if ( !bIsVistaOrHigher && !Q_stricmp( pShaderDLL, "shaderapidx10.dll" ) ) + { + pShaderDLL = "shaderapidx9.dll"; + } + + pMaterialSystem->SetShaderAPI( pShaderDLL ); + return true; +} + +void CMaterialSystemTestApp::Destroy() +{ +} + + +//----------------------------------------------------------------------------- +// Window callback +//----------------------------------------------------------------------------- +static LRESULT CALLBACK MaterialSystemTestWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch( message ) + { + case WM_DESTROY: + PostQuitMessage( 0 ); + break; + + default: + return DefWindowProc( hWnd, message, wParam, lParam ); + } + + return 0; +} + + +//----------------------------------------------------------------------------- +// Window management +//----------------------------------------------------------------------------- +bool CMaterialSystemTestApp::CreateAppWindow( const char *pTitle, bool bWindowed, int w, int h ) +{ + WNDCLASSEX wc; + memset( &wc, 0, sizeof( wc ) ); + wc.cbSize = sizeof( wc ); + wc.style = CS_OWNDC | CS_DBLCLKS; + wc.lpfnWndProc = MaterialSystemTestWndProc; + wc.hInstance = (HINSTANCE)GetAppInstance(); + wc.lpszClassName = "Valve001"; + wc.hIcon = NULL; //LoadIcon( s_HInstance, MAKEINTRESOURCE( IDI_LAUNCHER ) ); + wc.hIconSm = wc.hIcon; + + RegisterClassEx( &wc ); + + // Note, it's hidden + DWORD style = WS_POPUP | WS_CLIPSIBLINGS; + + if ( bWindowed ) + { + // Give it a frame + style |= WS_OVERLAPPEDWINDOW; + style &= ~WS_THICKFRAME; + } + + // Never a max box + style &= ~WS_MAXIMIZEBOX; + + RECT windowRect; + windowRect.top = 0; + windowRect.left = 0; + windowRect.right = w; + windowRect.bottom = h; + + // Compute rect needed for that size client area based on window style + AdjustWindowRectEx(&windowRect, style, FALSE, 0); + + // Create the window + m_HWnd = CreateWindow( wc.lpszClassName, pTitle, style, 0, 0, + windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, + NULL, NULL, (HINSTANCE)GetAppInstance(), NULL ); + + if (!m_HWnd) + return false; + + int CenterX, CenterY; + + CenterX = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; + CenterY = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; + CenterX = (CenterX < 0) ? 0: CenterX; + CenterY = (CenterY < 0) ? 0: CenterY; + + // In VCR modes, keep it in the upper left so mouse coordinates are always relative to the window. + SetWindowPos (m_HWnd, NULL, CenterX, CenterY, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); + + return true; +} + + +//----------------------------------------------------------------------------- +// Sets up the game path +//----------------------------------------------------------------------------- +bool CMaterialSystemTestApp::SetupSearchPaths() +{ + if ( !BaseClass::SetupSearchPaths( NULL, false, true ) ) + return false; + + g_pFullFileSystem->AddSearchPath( GetGameInfoPath(), "SKIN", PATH_ADD_TO_HEAD ); + return true; +} + + +//----------------------------------------------------------------------------- +// PreInit, PostShutdown +//----------------------------------------------------------------------------- +bool CMaterialSystemTestApp::PreInit( ) +{ + if ( !BaseClass::PreInit() ) + return false; + + if ( !g_pFullFileSystem || !g_pMaterialSystem ) + return false; + + // Add paths... + if ( !SetupSearchPaths() ) + return false; + + const char *pArg; + int iWidth = 1024; + int iHeight = 768; + bool bWindowed = (CommandLine()->CheckParm( "-fullscreen" ) == NULL); + if (CommandLine()->CheckParm( "-width", &pArg )) + { + iWidth = atoi( pArg ); + } + if (CommandLine()->CheckParm( "-height", &pArg )) + { + iHeight = atoi( pArg ); + } + + if (!CreateAppWindow( "Press a Key To Continue", bWindowed, iWidth, iHeight )) + return false; + + // Get the adapter from the command line.... + const char *pAdapterString; + int nAdapter = 0; + if ( CommandLine()->CheckParm( "-adapter", &pAdapterString ) ) + { + nAdapter = atoi( pAdapterString ); + } + + int nAdapterFlags = 0; + if ( AppUsesReadPixels() ) + { + nAdapterFlags |= MATERIAL_INIT_ALLOCATE_FULLSCREEN_TEXTURE; + } + + g_pMaterialSystem->SetAdapter( nAdapter, nAdapterFlags ); + + return true; +} + +void CMaterialSystemTestApp::PostShutdown( ) +{ + BaseClass::PostShutdown(); +} + + +//----------------------------------------------------------------------------- +// Waits for a keypress +//----------------------------------------------------------------------------- +bool CMaterialSystemTestApp::WaitForKeypress() +{ + MSG msg = {0}; + while( WM_QUIT != msg.message ) + { + if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + + if ( msg.message == WM_KEYDOWN ) + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Sets the video mode +//----------------------------------------------------------------------------- +bool CMaterialSystemTestApp::SetMode() +{ + MaterialSystem_Config_t config; + if ( CommandLine()->CheckParm( "-fullscreen" ) ) + { + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, false ); + } + else + { + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true ); + } + + if ( CommandLine()->CheckParm( "-resizing" ) ) + { + config.SetFlag( MATSYS_VIDCFG_FLAGS_RESIZING, true ); + } + + if ( CommandLine()->CheckParm( "-mat_vsync" ) ) + { + config.SetFlag( MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC, false ); + } + config.m_nAASamples = CommandLine()->ParmValue( "-mat_antialias", 1 ); + config.m_nAAQuality = CommandLine()->ParmValue( "-mat_aaquality", 0 ); + + config.m_VideoMode.m_Width = config.m_VideoMode.m_Height = 0; + config.m_VideoMode.m_Format = IMAGE_FORMAT_BGRX8888; + config.m_VideoMode.m_RefreshRate = 0; + + bool modeSet = g_pMaterialSystem->SetMode( m_HWnd, config ); + if (!modeSet) + { + Error( "Unable to set mode\n" ); + return false; + } + + g_pMaterialSystem->OverrideConfig( config, false ); + return true; +} + + +//----------------------------------------------------------------------------- +// Creates, destroys a test material +//----------------------------------------------------------------------------- +void CMaterialSystemTestApp::CreateWireframeMaterial() +{ + KeyValues *pVMTKeyValues = new KeyValues( "Wireframe" ); + pVMTKeyValues->SetInt( "$vertexcolor", 1 ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + pVMTKeyValues->SetInt( "$ignorez", 1 ); + m_pMaterial.Init( "__test", pVMTKeyValues ); +} + +void CMaterialSystemTestApp::DestroyMaterial() +{ + m_pMaterial.Shutdown(); +} + + +//----------------------------------------------------------------------------- +// Tests dynamic buffers +//----------------------------------------------------------------------------- +void CMaterialSystemTestApp::TestDynamicBuffers( IMatRenderContext *pMatRenderContext, bool bBuffered ) +{ + CreateWireframeMaterial(); + + g_pMaterialSystem->BeginFrame( 0 ); + + pMatRenderContext->Bind( m_pMaterial ); + IMesh *pMesh = pMatRenderContext->GetDynamicMesh( bBuffered ); + + // clear (so that we can make sure that we aren't getting results from the previous quad) + pMatRenderContext->ClearColor3ub( RandomInt( 0, 100 ), RandomInt( 0, 100 ), RandomInt( 190, 255 ) ); + pMatRenderContext->ClearBuffers( true, true ); + + static unsigned char s_pColors[4][4] = + { + { 255, 0, 0, 255 }, + { 0, 255, 0, 255 }, + { 0, 0, 255, 255 }, + { 255, 255, 255, 255 }, + }; + + static int nCount = 0; + + const int nLoopCount = 8; + float flWidth = 2.0f / nLoopCount; + for ( int i = 0; i < nLoopCount; ++i ) + { + CMeshBuilder mb; + mb.Begin( pMesh, MATERIAL_TRIANGLES, 4, 6 ); + + mb.Position3f( -1.0f + i * flWidth, -1.0f, 0.5f ); + mb.Normal3f( 0.0f, 0.0f, 1.0f ); + mb.Color4ubv( s_pColors[nCount++ % 4] ); + mb.AdvanceVertex(); + + mb.Position3f( -1.0f + i * flWidth + flWidth, -1.0f, 0.5f ); + mb.Normal3f( 0.0f, 0.0f, 1.0f ); + mb.Color4ubv( s_pColors[nCount++ % 4] ); + mb.AdvanceVertex(); + + mb.Position3f( -1.0f + i * flWidth + flWidth, 1.0f, 0.5f ); + mb.Normal3f( 0.0f, 0.0f, 1.0f ); + mb.Color4ubv( s_pColors[nCount++ % 4] ); + mb.AdvanceVertex(); + + mb.Position3f( -1.0f + i * flWidth, 1.0f, 0.5f ); + mb.Normal3f( 0.0f, 0.0f, 1.0f ); + mb.Color4ubv( s_pColors[nCount++ % 4] ); + mb.AdvanceVertex(); + + ++nCount; + + mb.FastIndex( 0 ); + mb.FastIndex( 2 ); + mb.FastIndex( 1 ); + mb.FastIndex( 0 ); + mb.FastIndex( 3 ); + mb.FastIndex( 2 ); + + mb.End( true ); + + pMesh->Draw( ); + } + + ++nCount; + + g_pMaterialSystem->EndFrame(); + g_pMaterialSystem->SwapBuffers(); + + DestroyMaterial(); +} + + +//----------------------------------------------------------------------------- +// main application +//----------------------------------------------------------------------------- +int CMaterialSystemTestApp::Main() +{ + if ( !SetMode() ) + return 0; + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + // Sets up a full-screen viewport + int w, h; + pRenderContext->GetWindowSize( w, h ); + pRenderContext->Viewport( 0, 0, w, h ); + pRenderContext->DepthRange( 0.0f, 1.0f ); + + // Clears the screen + g_pMaterialSystem->BeginFrame( 0 ); + pRenderContext->ClearColor4ub( 76, 88, 68, 255 ); + pRenderContext->ClearBuffers( true, true ); + g_pMaterialSystem->EndFrame(); + g_pMaterialSystem->SwapBuffers(); + + SetWindowText( m_HWnd, "Buffer clearing . . hit a key" ); + if ( !WaitForKeypress() ) + return 1; + + SetWindowText( m_HWnd, "Dynamic buffer test.. hit a key" ); + TestDynamicBuffers( pRenderContext, false ); + if ( !WaitForKeypress() ) + return 1; + + SetWindowText( m_HWnd, "Buffered dynamic buffer test.. hit a key" ); + TestDynamicBuffers( pRenderContext, true ); + if ( !WaitForKeypress() ) + return 1; + + return 1; +}
\ No newline at end of file diff --git a/unittests/materialsystemtest/materialsystemtest.vpc b/unittests/materialsystemtest/materialsystemtest.vpc new file mode 100644 index 0000000..5c3cbbe --- /dev/null +++ b/unittests/materialsystemtest/materialsystemtest.vpc @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// MATERIALSYSTEMTEST.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_base.vpc" + +$Project "MaterialSystemTest" +{ + $Folder "Source Files" + { + $File "materialsystemtest.cpp" + } + + $Folder "Link Libraries" + { + $Lib appframework + $Lib tier2 + } +} diff --git a/unittests/mathlib_test/mathlib_test.cpp b/unittests/mathlib_test/mathlib_test.cpp new file mode 100644 index 0000000..c3c1191 --- /dev/null +++ b/unittests/mathlib_test/mathlib_test.cpp @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "tier0/platform.h" +#include "mathlib/mathlib.h" +#include "mathlib/spherical_geometry.h" +#include "tier2/tier2.h" +#include "mathlib/halton.h" +#include "bitmap/float_bm.h" +#include "tier0/memdbgon.h" + +void main(int argc,char **argv) +{ + InitCommandLineProgram( argc, argv ); + + // 1/8th of the sphere + float a1=UnitSphereTriangleArea( Vector( 1, 0, 0 ), Vector( 0, 0, -1 ), Vector( 0, 1, 0 ) ); + printf( "right spherical triangle projected percentage=%2.4f\n", a1 / ( 4 * M_PI )); + + // a small one + Vector v1 = Vector( 1, 0, 0 ); + Vector v2 = v1 + Vector( 0, 0.2, 0 ); + Vector v3 = v1 + Vector( 0, 0, 0.2 ); + v2.NormalizeInPlace(); + v3.NormalizeInPlace(); + float a2=UnitSphereTriangleArea( v1, v2, v3 ); + printf( "small spherical triangle projected percentage=%2.5f\n", a2 / ( 4* M_PI ) ); + + // now, create a cubemap and sum the area of each of its cells + FloatCubeMap_t envMap( 10, 10 ); + float flAreaSum = 0.; + for( int nFace = 0 ; nFace < 6; nFace ++ ) + { + for( int nY = 0 ; nY < 9; nY++ ) + for( int nX = 0 ; nX < 9; nX++ ) + { + Vector v00 = envMap.PixelDirection( nFace, nX, nY ); + Vector v01 = envMap.PixelDirection( nFace, nX, nY + 1 ); + Vector v10 = envMap.PixelDirection( nFace, nX + 1, nY ); + Vector v11 = envMap.PixelDirection( nFace, nX + 1 , nY + 1 ); + v00.NormalizeInPlace(); + v01.NormalizeInPlace(); + v10.NormalizeInPlace(); + v11.NormalizeInPlace(); + flAreaSum += UnitSphereTriangleArea( v00, v01, v10 ); + flAreaSum += UnitSphereTriangleArea( v10, v11, v01 ); + } + } + printf( "sum of areas of cubemap cells = %2.2f\n", flAreaSum / ( 4.0 * M_PI ) ); + +#if 0 // visual spherical harmonics as (confusing) point sets + // spherical harmonics + DirectionalSampler_t sampler; + for(int i = 0 ; i < 50000; i++ ) + { + Vector dir=sampler.NextValue(); + float SH = SphericalHarmonic( 4, 3, dir ); + float r=0; + float g=1; //0.5+0.5*DotProduct( dir, Vector( 0, 0, 1 ) ); + float b=0; + if ( SH < 0 ) + { + SH = -SH; + r=g; + g=0; + } + r *= SH; + g *= SH; + b *= SH; + float rad= SH * 4.0; //4.0; //SH *= 8.0; + printf( "2\n" ); + printf( "%f %f %f %f %f %f\n", + dir.x * rad, dir.y * rad, dir.z * rad, r, g, b ); + rad += 0.03; + printf( "%f %f %f %f %f %f\n", + dir.x * rad, dir.y * rad, dir.z * rad, r, g, b ); + } +#endif + +} + diff --git a/unittests/mathlib_test/mathlib_test.vpc b/unittests/mathlib_test/mathlib_test.vpc new file mode 100644 index 0000000..32dd5f3 --- /dev/null +++ b/unittests/mathlib_test/mathlib_test.vpc @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// mathlib_test.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\unittests\mathlib_test" + +$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc" + +$Configuration "Debug" +{ + $Compiler + { + $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE" + } + + $Linker + { + $AdditionalDependencies "$BASE winmm.lib" + } +} + +$Project "mathlib_test" +{ + $Folder "Source Files" + { + $File "mathlib_test.cpp" + } + + $Folder "Link Libraries" + { + $Lib bitmap + $Lib mathlib + $Lib tier2 + } +} diff --git a/unittests/networktest/networktest.cpp b/unittests/networktest/networktest.cpp new file mode 100644 index 0000000..5e8c9a4 --- /dev/null +++ b/unittests/networktest/networktest.cpp @@ -0,0 +1,395 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Material editor +//============================================================================= + +#include <windows.h> +#include "appframework/appframework.h" +#include "networksystem/inetworksystem.h" +#include "networksystem/inetworkmessage.h" +#include "bitbuf.h" +#include "filesystem.h" +#include "filesystem_init.h" +#include "tier0/icommandline.h" +#include "vstdlib/cvar.h" + + +//----------------------------------------------------------------------------- +// Singleton interfaces +//----------------------------------------------------------------------------- +IFileSystem *g_pFileSystem; +INetworkSystem *g_pNetworkSystem; + + +//----------------------------------------------------------------------------- +// Purpose: Warning/Msg call back through this API +// Input : type - +// *pMsg - +// Output : SpewRetval_t +//----------------------------------------------------------------------------- +SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg ) +{ + OutputDebugString( pMsg ); + if ( type == SPEW_ASSERT ) + { + DebuggerBreak(); + } + return SPEW_CONTINUE; +} + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CNetworkTestApp : public CSteamAppSystemGroup +{ + typedef CSteamAppSystemGroup BaseClass; + +public: + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit( ); + virtual int Main(); + virtual void PostShutdown( ); + virtual void Destroy(); + virtual const char *GetAppName() { return "NetworkTest"; } + virtual bool AppUsesReadPixels() { return false; } + +private: + // Window management + bool CreateAppWindow( char const *pTitle, bool bWindowed, int w, int h ); + + // Sets up the game path + bool SetupSearchPaths(); + + HWND m_HWnd; +}; + +DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT( CNetworkTestApp ); + + +//----------------------------------------------------------------------------- +// Create all singleton systems +//----------------------------------------------------------------------------- +bool CNetworkTestApp::Create() +{ + SpewOutputFunc( SpewFunc ); + + // Add in the cvar factory + AppModule_t cvarModule = LoadModule( VStdLib_GetICVarFactory() ); + AddSystem( cvarModule, CVAR_INTERFACE_VERSION ); + + AppSystemInfo_t appSystems[] = + { + { "networksystem.dll", NETWORKSYSTEM_INTERFACE_VERSION }, + { "", "" } // Required to terminate the list + }; + + if ( !AddSystems( appSystems ) ) + return false; + + g_pFileSystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION ); + g_pNetworkSystem = (INetworkSystem*)FindSystem( NETWORKSYSTEM_INTERFACE_VERSION ); + + if (!g_pFileSystem || !g_pNetworkSystem ) + return false; + + return true; +} + +void CNetworkTestApp::Destroy() +{ + g_pFileSystem = NULL; + g_pNetworkSystem = NULL; +} + + +//----------------------------------------------------------------------------- +// Window management +//----------------------------------------------------------------------------- +bool CNetworkTestApp::CreateAppWindow( char const *pTitle, bool bWindowed, int w, int h ) +{ + WNDCLASSEX wc; + memset( &wc, 0, sizeof( wc ) ); + wc.cbSize = sizeof( wc ); + wc.style = CS_OWNDC | CS_DBLCLKS; + wc.lpfnWndProc = DefWindowProc; + wc.hInstance = (HINSTANCE)GetAppInstance(); + wc.lpszClassName = "Valve001"; + wc.hIcon = NULL; //LoadIcon( s_HInstance, MAKEINTRESOURCE( IDI_LAUNCHER ) ); + wc.hIconSm = wc.hIcon; + + RegisterClassEx( &wc ); + + // Note, it's hidden + DWORD style = WS_POPUP | WS_CLIPSIBLINGS; + + if ( bWindowed ) + { + // Give it a frame + style |= WS_OVERLAPPEDWINDOW; + style &= ~WS_THICKFRAME; + } + + // Never a max box + style &= ~WS_MAXIMIZEBOX; + + RECT windowRect; + windowRect.top = 0; + windowRect.left = 0; + windowRect.right = w; + windowRect.bottom = h; + + // Compute rect needed for that size client area based on window style + AdjustWindowRectEx(&windowRect, style, FALSE, 0); + + // Create the window + m_HWnd = CreateWindow( wc.lpszClassName, pTitle, style, 0, 0, + windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, + NULL, NULL, (HINSTANCE)GetAppInstance(), NULL ); + + if (!m_HWnd) + return false; + + int CenterX, CenterY; + + CenterX = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; + CenterY = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; + CenterX = (CenterX < 0) ? 0: CenterX; + CenterY = (CenterY < 0) ? 0: CenterY; + + // In VCR modes, keep it in the upper left so mouse coordinates are always relative to the window. + SetWindowPos (m_HWnd, NULL, CenterX, CenterY, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); + + return true; +} + + +//----------------------------------------------------------------------------- +// Sets up the game path +//----------------------------------------------------------------------------- +bool CNetworkTestApp::SetupSearchPaths() +{ + CFSSteamSetupInfo steamInfo; + steamInfo.m_pDirectoryName = NULL; + steamInfo.m_bOnlyUseDirectoryName = false; + steamInfo.m_bToolsMode = true; + steamInfo.m_bSetSteamDLLPath = true; + steamInfo.m_bSteam = g_pFileSystem->IsSteam(); + if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK ) + return false; + + CFSMountContentInfo fsInfo; + fsInfo.m_pFileSystem = g_pFileSystem; + fsInfo.m_bToolsMode = true; + fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath; + + if ( FileSystem_MountContent( fsInfo ) != FS_OK ) + return false; + + // Finally, load the search paths for the "GAME" path. + CFSSearchPathsInit searchPathsInit; + searchPathsInit.m_pDirectoryName = steamInfo.m_GameInfoPath; + searchPathsInit.m_pFileSystem = g_pFileSystem; + if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK ) + return false; + + g_pFileSystem->AddSearchPath( steamInfo.m_GameInfoPath, "SKIN", PATH_ADD_TO_HEAD ); + + char platform[MAX_PATH]; + Q_strncpy( platform, steamInfo.m_GameInfoPath, MAX_PATH ); + Q_StripTrailingSlash( platform ); + Q_strncat( platform, "/../platform", MAX_PATH, MAX_PATH ); + + g_pFileSystem->AddSearchPath( platform, "PLATFORM" ); + + return true; +} + + +//----------------------------------------------------------------------------- +// PreInit, PostShutdown +//----------------------------------------------------------------------------- +bool CNetworkTestApp::PreInit( ) +{ + // Add paths... + if ( !SetupSearchPaths() ) + return false; + + const char *pArg; + int iWidth = 1024; + int iHeight = 768; + bool bWindowed = (CommandLine()->CheckParm( "-fullscreen" ) == NULL); + if (CommandLine()->CheckParm( "-width", &pArg )) + { + iWidth = atoi( pArg ); + } + if (CommandLine()->CheckParm( "-height", &pArg )) + { + iHeight = atoi( pArg ); + } + + if (!CreateAppWindow( "NetworkTest", bWindowed, iWidth, iHeight )) + return false; + + return true; +} + +void CNetworkTestApp::PostShutdown( ) +{ +} + + +//----------------------------------------------------------------------------- +// Network message ids +//----------------------------------------------------------------------------- +enum +{ + TEST_GROUP = NETWORKSYSTEM_FIRST_GROUP, +}; + +enum +{ + TEST_MESSAGE_1 = 0, +}; + + + +//----------------------------------------------------------------------------- +// Test network message +//----------------------------------------------------------------------------- +class CTestNetworkMessage : public CNetworkMessage +{ +public: + CTestNetworkMessage() { SetReliable( false ); } + CTestNetworkMessage( int nValue ) : m_Data( nValue ) { SetReliable( false ); } + + DECLARE_BASE_MESSAGE( TEST_GROUP, TEST_MESSAGE_1, "Test Message 1" ) + + bool Process(); + + int m_Data; +}; + +bool CTestNetworkMessage::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteShort( m_Data ); + return !buffer.IsOverflowed(); +} + +bool CTestNetworkMessage::ReadFromBuffer( bf_read &buffer ) +{ + m_Data = buffer.ReadShort(); + return !buffer.IsOverflowed(); +} + +bool CTestNetworkMessage::Process() +{ + Msg( "Received test message %d\n", m_Data ); + return true; +} + + +//----------------------------------------------------------------------------- +// main application +//----------------------------------------------------------------------------- +int CNetworkTestApp::Main() +{ + // Network messages must be registered before the server or client is started + g_pNetworkSystem->RegisterMessage( new CTestNetworkMessage() ); + + int nRetVal = 0; + if ( !g_pNetworkSystem->StartServer( ) ) + return 0; + + if ( !g_pNetworkSystem->StartClient( ) ) + goto shutdownServer; + + // Set the channel up for receiving + INetChannel *pChan = g_pNetworkSystem->ConnectClientToServer( "localhost", 27001 ); + if ( !pChan ) + goto shutdownClient; + + INetChannel *pServerChan = NULL; + + { + while( true ) + { + // Helps avoid a buffer overflow + Sleep( 1 ); + + // Send a message out + if ( pChan->GetConnectionState() == CONNECTION_STATE_CONNECTED ) + { + CTestNetworkMessage msg( 5 ); + pChan->AddNetMsg( &msg, false ); + msg.m_Data = 4; + pChan->AddNetMsg( &msg, false ); + } + + if ( pServerChan ) + { + CTestNetworkMessage msg( 6 ); + pServerChan->AddNetMsg( &msg, false ); + msg.m_Data = 7; + pServerChan->AddNetMsg( &msg, false ); + } + + g_pNetworkSystem->ClientSendMessages(); + g_pNetworkSystem->ServerReceiveMessages(); + g_pNetworkSystem->ServerSendMessages(); + g_pNetworkSystem->ClientReceiveMessages(); + + NetworkEvent_t *pEvent = g_pNetworkSystem->FirstNetworkEvent(); + for ( ; pEvent; pEvent = g_pNetworkSystem->NextNetworkEvent( ) ) + { + switch ( pEvent->m_nType ) + { + case NETWORK_EVENT_CONNECTED: + pServerChan = ((NetworkConnectionEvent_t*)pEvent)->m_pChannel; + break; + + case NETWORK_EVENT_DISCONNECTED: + if ( pServerChan == ((NetworkDisconnectionEvent_t*)pEvent)->m_pChannel ) + { + pServerChan = NULL; + } + break; + + case NETWORK_EVENT_MESSAGE_RECEIVED: + { + NetworkMessageReceivedEvent_t *pReceivedEvent = static_cast<NetworkMessageReceivedEvent_t*>( pEvent ); + if ( ( pReceivedEvent->m_pNetworkMessage->GetGroup() == TEST_GROUP ) && ( pReceivedEvent->m_pNetworkMessage->GetType() == TEST_MESSAGE_1 ) ) + { + static_cast<CTestNetworkMessage*>( pReceivedEvent->m_pNetworkMessage )->Process(); + } + } + break; + } + } + } + nRetVal = 1; + + g_pNetworkSystem->DisconnectClientFromServer( pChan ); + } + +shutdownClient: + g_pNetworkSystem->ShutdownClient( ); + +shutdownServer: + g_pNetworkSystem->ShutdownServer( ); + + return nRetVal; +} + + + diff --git a/unittests/networktest/networktest.vpc b/unittests/networktest/networktest.vpc new file mode 100644 index 0000000..27edf6b --- /dev/null +++ b/unittests/networktest/networktest.vpc @@ -0,0 +1,23 @@ +//----------------------------------------------------------------------------- +// NETWORKTEST.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_win_win32_base.vpc" + +$Project "Networktest" +{ + $Folder "Source Files" + { + $File "networktest.cpp" + } + + $Folder "Link Libraries" + { + $DynamicFile "$SRCDIR\lib\public\appframework.lib" + } +} diff --git a/unittests/rt_test/gwolf.tga b/unittests/rt_test/gwolf.tga Binary files differnew file mode 100644 index 0000000..b7af1d9 --- /dev/null +++ b/unittests/rt_test/gwolf.tga diff --git a/unittests/rt_test/rt_test.cpp b/unittests/rt_test/rt_test.cpp new file mode 100644 index 0000000..c9399e8 --- /dev/null +++ b/unittests/rt_test/rt_test.cpp @@ -0,0 +1,87 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "tier0/platform.h" +#include "tier0/progressbar.h" +#include "bitmap/float_bm.h" +#include "mathlib/mathlib.h" +#include "tier2/tier2.h" +#include "tier0/memdbgon.h" +#include "raytrace.h" +#include "bitmap/tgawriter.h" + +void main(int argc,char **argv) +{ + InitCommandLineProgram( argc, argv ); + + if (argc != 5) + { + printf("format is 'rt_test src_image dest_image xsize ysize'\n"); + } + else + { + ReportProgress("reading src texture",0,0); + FloatBitMap_t src_texture(argv[1]); + int xsize = atoi( argv[3] ); + int ysize = atoi( argv[4] ); + + // render a simple scene of a terrain, using a bitmap for color data and its alpha channel for the height + RayTracingEnvironment rt_Env; + int id = 1; + float flXScale = (1.0/(src_texture.Width-1) ); + float flZScale = (1.0/(src_texture.Height-1) ); + for( int y=0; y < src_texture.Height-1; y++ ) + for(int x=0 ; x < src_texture.Width-1; x++ ) + { + Vector vecVerts[2][2]; + for(int iy=0 ; iy < 2; iy++) + for(int ix=0 ; ix < 2; ix++) + { + vecVerts[ix][iy].x = 2.0* ( ( x+ix )*flXScale-0.5 ); + if ( ( x+ix == src_texture.Width-1 ) || ( y+iy==src_texture.Height-1 ) ) + vecVerts[ix][iy].y = 0; + else + vecVerts[ix][iy].y = 0.3*src_texture.Pixel( x+ix, y+iy, 1 ); + vecVerts[ix][iy].z = -2.0* ( ( y+iy )*flZScale-0.5 ); + } + Vector vecColor( GammaToLinear(src_texture.Pixel(x,y,0)), + GammaToLinear( src_texture.Pixel( x, y, 1 )), + GammaToLinear( src_texture.Pixel( x, y, 2 )) ); + rt_Env.AddTriangle( id++, vecVerts[0][0], vecVerts[1][0], vecVerts[1][1], vecColor ); + rt_Env.AddTriangle( id++, vecVerts[0][0], vecVerts[0][1], vecVerts[1][1], vecColor ); + } + rt_Env.AddTriangle( id++, Vector(0,0,-.2), Vector(.2,0,.2), Vector( -.2,0,.2), Vector( 0,0,1 ) ); + printf("n triangles %d\n",id); + ReportProgress("Creating kd-tree",0,0); + float stime = Plat_FloatTime(); + rt_Env.SetupAccelerationStructure(); + printf("kd built time := %d\n", (int) ( Plat_FloatTime() - stime ) ); + rt_Env.AddInfinitePointLight( Vector( 0,5, 0), Vector( .1,.1,.1 )); + // lets render a frame + uint32 *buf=reinterpret_cast<uint32 *> ( MemAlloc_AllocAligned( xsize * ysize * 4 , 16 ) ); + + Vector EyePos(0,2,0); + ReportProgress("Rendering",0,0); + +// rt_Env.RenderScene( xsize, ysize, xsize, buf, Vector( 0, 0.5, -1.0 ), +// Vector( -1, 1, 0), +// Vector( 1, 1, 0 ), +// Vector( -1, -1, 0 ), +// Vector( 1, -1, 0 ) ); + float curtime = Plat_FloatTime(); + for(int i=0;i<10;i++) + { + rt_Env.RenderScene( xsize, ysize, xsize, buf, + EyePos, + Vector( -1, 0,1)-EyePos, + Vector( 1, 0, 1 )-EyePos, + Vector( -1, 0, -1 )-EyePos, + Vector( 1, 0, -1 )-EyePos ); + } + float etime=Plat_FloatTime()-curtime; + printf("pixels traced and lit per second := %f\n",(10*xsize*ysize)*(1.0/etime)); + TGAWriter::WriteTGAFile( "test.tga", xsize, ysize, IMAGE_FORMAT_RGBA8888, + reinterpret_cast<uint8 *> (buf), 4*xsize ); + + MemAlloc_FreeAligned( buf ); + } + +} diff --git a/unittests/rt_test/rt_test.exe b/unittests/rt_test/rt_test.exe Binary files differnew file mode 100644 index 0000000..afda31c --- /dev/null +++ b/unittests/rt_test/rt_test.exe diff --git a/unittests/rt_test/rt_test.pdb b/unittests/rt_test/rt_test.pdb Binary files differnew file mode 100644 index 0000000..6928711 --- /dev/null +++ b/unittests/rt_test/rt_test.pdb diff --git a/unittests/rt_test/rt_test.vpc b/unittests/rt_test/rt_test.vpc new file mode 100644 index 0000000..07a9d6b --- /dev/null +++ b/unittests/rt_test/rt_test.vpc @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// rt_test.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\unittests\rt_test" + +$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc" + +$Configuration "Debug" +{ + $Compiler + { + $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE" + } + + $Linker + { + $AdditionalDependencies "$BASE winmm.lib" + } +} + +$Project "rt_test" +{ + $Folder "Source Files" + { + $File "rt_test.cpp" + } + + $Folder "Link Libraries" + { + $Lib bitmap + $Lib mathlib + $Lib raytrace + $Lib tier2 + } +} diff --git a/unittests/shaderapitest/shaderapitest.cpp b/unittests/shaderapitest/shaderapitest.cpp new file mode 100644 index 0000000..2f94b2f --- /dev/null +++ b/unittests/shaderapitest/shaderapitest.cpp @@ -0,0 +1,1056 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Material editor +//============================================================================= + +#include <windows.h> +#include "appframework/tier2app.h" +#include "shaderapi/ishaderdevice.h" +#include "shaderapi/ishaderutil.h" +#include "shaderapi/ishaderapi.h" +#include "materialsystem/materialsystem_config.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "vstdlib/random.h" +#include "filesystem.h" +#include "filesystem_init.h" +#include "tier0/icommandline.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "tier1/lzmadecoder.h" +#include "materialsystem/imesh.h" +#include "materialsystem/shader_vcs_version.h" +#include "../utils/bzip2/bzlib.h" + + +class CShaderUtilTemp : public CBaseAppSystem< IShaderUtil > +{ +public: + // Method to allow clients access to the MaterialSystem_Config + virtual MaterialSystem_Config_t& GetConfig() + { + static MaterialSystem_Config_t config; + return config; + } + + // Allows us to convert image formats + virtual bool ConvertImageFormat( unsigned char *src, enum ImageFormat srcImageFormat, + unsigned char *dst, enum ImageFormat dstImageFormat, + int width, int height, int srcStride = 0, int dstStride = 0 ) + { + return true; + } + + // Figures out the amount of memory needed by a bitmap + virtual int GetMemRequired( int width, int height, int depth, ImageFormat format, bool mipmap ) + { + return 0; + } + + // Gets image format info + virtual const ImageFormatInfo_t& ImageFormatInfo( ImageFormat fmt ) const + { + static ImageFormatInfo_t info; + return info; + } + + // Allows us to set the default shadow state + virtual void SetDefaultShadowState() { } + + // Allows us to set the default shader state + virtual void SetDefaultState( ) { } + + // Bind standard textures + virtual void BindStandardTexture( Sampler_t stage, StandardTextureId_t id ) { } + virtual void BindStandardVertexTexture( VertexTextureSampler_t stage, StandardTextureId_t id ) { } + virtual void GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id ) { *pWidth = *pHeight = 0; } + + // What are the lightmap dimensions? + virtual void GetLightmapDimensions( int *w, int *h ) { *w = *h = 0; } + + // These methods are called when the shader must eject + restore HW memory + virtual void ReleaseShaderObjects() {} + virtual void RestoreShaderObjects( CreateInterfaceFn shaderFactory, int nChangeFlags = 0 ) {} + + // Used to prevent meshes from drawing. + virtual bool IsInStubMode() { return false; } + virtual bool InFlashlightMode() const { return false; } + + // For the shader API to shove the current version of aniso level into the + // "definitive" place (g_config) when the shader API decides to change it. + // Eventually, we should have a better system of who owns the definitive + // versions of config vars. + virtual void NoteAnisotropicLevel( int currentLevel ) {} + + // NOTE: Stuff after this is added after shipping HL2. + + // Are we rendering through the editor? + virtual bool InEditorMode() const { return false; } + + // Gets the bound morph's vertex format; returns 0 if no morph is bound + virtual MorphFormat_t GetBoundMorphFormat() { return 0; } + + virtual ITexture *GetRenderTargetEx( int nRenderTargetID ) { return 0; } + + // Tells the material system to draw a buffer clearing quad + virtual void DrawClearBufferQuad( unsigned char r, unsigned char g, unsigned char b, unsigned char a, bool bClearColor, bool bClearAlpha, bool bClearDepth ) OVERRIDE {} + +#if defined( _X360 ) + virtual void ReadBackBuffer( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *pData, ImageFormat dstFormat, int nDstStride ) {} +#endif + + // Calls from meshes to material system to handle queing/threading + virtual bool OnDrawMesh( IMesh *pMesh, int firstIndex, int numIndices ) { return false; } + virtual bool OnDrawMesh( IMesh *pMesh, CPrimList *pLists, int nLists ) { return false; } + virtual bool OnSetFlexMesh( IMesh *pStaticMesh, IMesh *pMesh, int nVertexOffsetInBytes ) { return false; } + virtual bool OnSetColorMesh( IMesh *pStaticMesh, IMesh *pMesh, int nVertexOffsetInBytes ) { return false; } + virtual bool OnSetPrimitiveType( IMesh *pMesh, MaterialPrimitiveType_t type ) { return false; } + virtual bool OnFlushBufferedPrimitives() { return false; } + + + virtual void SyncMatrices() {} + virtual void SyncMatrix( MaterialMatrixMode_t ) {} + virtual int MaxHWMorphBatchCount() const { return 0; } + + virtual void GetCurrentColorCorrection( ShaderColorCorrectionInfo_t* pInfo ) + { + pInfo->m_bIsEnabled = false; + pInfo->m_nLookupCount = 0; + pInfo->m_flDefaultWeight = 0.0f; + } + virtual void OnThreadEvent( uint32 threadEvent ) {} + + ShaderAPITextureHandle_t GetShaderAPITextureBindHandle( ITexture *pTexture, int nFrame, int nTextureChannel ) { return 0; } + + // Remove any materials from memory that aren't in use as determined + // by the IMaterial's reference count. + virtual void UncacheUnusedMaterials( bool bRecomputeStateSnapshots = false ) {} + + virtual MaterialThreadMode_t GetThreadMode( ) { return MATERIAL_SINGLE_THREADED; } + virtual bool IsRenderThreadSafe( ) { return true; } +}; + + +static CShaderUtilTemp g_pTemp; + +static IShaderDeviceMgr *g_pShaderDeviceMgr; + +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderUtilTemp, IShaderUtil, + SHADER_UTIL_INTERFACE_VERSION, g_pTemp ) + +//----------------------------------------------------------------------------- +// Purpose: Warning/Msg call back through this API +// Input : type - +// *pMsg - +// Output : SpewRetval_t +//----------------------------------------------------------------------------- +SpewRetval_t SpewFunc( SpewType_t type, const char *pMsg ) +{ + if ( Plat_IsInDebugSession() ) + { + OutputDebugString( pMsg ); + if ( type == SPEW_ASSERT ) + return SPEW_DEBUGGER; + } + return SPEW_CONTINUE; +} + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CShaderAPITestApp : public CTier2SteamApp +{ + typedef CTier2SteamApp BaseClass; + +public: + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit( ); + virtual int Main(); + virtual void PostShutdown( ); + virtual void Destroy(); + virtual const char *GetAppName() { return "InputTest"; } + virtual bool AppUsesReadPixels() { return false; } + +private: + // Window management + bool CreateAppWindow( const char *pTitle, bool bWindowed, int w, int h ); + + // Sets up the game path + bool SetupSearchPaths(); + + // Waits for a keypress + bool WaitForKeypress(); + + // Displays information about all adapters + void DisplayAdapterInfo(); + + // Sets the video mode + bool SetMode(); + + // Creates really simple vertex + index buffers + void CreateSimpleBuffers( ShaderBufferType_t nVBType, ShaderBufferType_t nIBType, bool bBuffered ); + + // Destroys the buffers + void DestroyBuffers(); + + // Creates shaders + void CreateShaders( const char *pVShader, int nVBufLen, const char *pGShader, int nGBufLen, const char *pPShader, int nPBufLen ); + + // Destroys the buffers + void DestroyShaders(); + + // DrawUsingShaders + void TestColoredQuad( ShaderBufferType_t nVBType, ShaderBufferType_t nIBType, bool bBuffered ); + + // Tests dynamic buffers + void TestDynamicBuffers(); + + bool CreateDynamicCombos_Ver5( uint8 *pComboBuffer, bool bVertexShader ); + void LoadShaderFile( const char *pName, bool bVertexShader ); + + HWND m_HWnd; + IShaderAPI *m_pShaderAPI; + IShaderDevice *m_pShaderDevice; + + IIndexBuffer *m_pIndexBuffer; + IVertexBuffer *m_pVertexBuffer; + + VertexShaderHandle_t m_hVertexShader; + GeometryShaderHandle_t m_hGeometryShader; + PixelShaderHandle_t m_hPixelShader; +}; + +DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT( CShaderAPITestApp ); + + +//----------------------------------------------------------------------------- +// Create all singleton systems +//----------------------------------------------------------------------------- +bool CShaderAPITestApp::Create() +{ + SpewOutputFunc( SpewFunc ); + + bool bIsVistaOrHigher = false; + + OSVERSIONINFO info; + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if ( GetVersionEx( &info ) ) + { + bIsVistaOrHigher = info.dwMajorVersion >= 6; + } + + const char *pShaderDLL = CommandLine()->ParmValue( "-shaderdll" ); + if ( !pShaderDLL ) + { + pShaderDLL = "shaderapidx10.dll"; + } + + if ( !bIsVistaOrHigher && !Q_stricmp( pShaderDLL, "shaderapidx10.dll" ) ) + { + pShaderDLL = "shaderapidx9.dll"; + } + + AppModule_t module = LoadModule( pShaderDLL ); + if ( module == APP_MODULE_INVALID ) + { + if ( module == APP_MODULE_INVALID ) + { + pShaderDLL = "shaderapidx9.dll"; + module = LoadModule( pShaderDLL ); + if ( module == APP_MODULE_INVALID ) + { + pShaderDLL = "shaderapiempty.dll"; + module = LoadModule( pShaderDLL ); + if ( module == APP_MODULE_INVALID ) + return false; + } + } + } + + g_pShaderDeviceMgr = (IShaderDeviceMgr*)AddSystem( module, SHADER_DEVICE_MGR_INTERFACE_VERSION ); + + // So that shaderapi can get ahold of our bogus IShaderUtil + module = LoadModule( Sys_GetFactoryThis() ); + AddSystem( module, SHADER_UTIL_INTERFACE_VERSION ); + + return ( g_pShaderDeviceMgr != NULL ); +} + +void CShaderAPITestApp::Destroy() +{ +} + + +//----------------------------------------------------------------------------- +// Window callback +//----------------------------------------------------------------------------- +static LRESULT CALLBACK ShaderAPITestWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch( message ) + { + case WM_DESTROY: + PostQuitMessage( 0 ); + break; + + default: + return DefWindowProc( hWnd, message, wParam, lParam ); + } + + return 0; +} + + +//----------------------------------------------------------------------------- +// Window management +//----------------------------------------------------------------------------- +bool CShaderAPITestApp::CreateAppWindow( const char *pTitle, bool bWindowed, int w, int h ) +{ + WNDCLASSEX wc; + memset( &wc, 0, sizeof( wc ) ); + wc.cbSize = sizeof( wc ); + wc.style = CS_OWNDC | CS_DBLCLKS; + wc.lpfnWndProc = ShaderAPITestWndProc; + wc.hInstance = (HINSTANCE)GetAppInstance(); + wc.lpszClassName = "Valve001"; + wc.hIcon = NULL; //LoadIcon( s_HInstance, MAKEINTRESOURCE( IDI_LAUNCHER ) ); + wc.hIconSm = wc.hIcon; + + RegisterClassEx( &wc ); + + // Note, it's hidden + DWORD style = WS_POPUP | WS_CLIPSIBLINGS; + + if ( bWindowed ) + { + // Give it a frame + style |= WS_OVERLAPPEDWINDOW; + style &= ~WS_THICKFRAME; + } + + // Never a max box + style &= ~WS_MAXIMIZEBOX; + + RECT windowRect; + windowRect.top = 0; + windowRect.left = 0; + windowRect.right = w; + windowRect.bottom = h; + + // Compute rect needed for that size client area based on window style + AdjustWindowRectEx(&windowRect, style, FALSE, 0); + + // Create the window + m_HWnd = CreateWindow( wc.lpszClassName, pTitle, style, 0, 0, + windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, + NULL, NULL, (HINSTANCE)GetAppInstance(), NULL ); + + if (!m_HWnd) + return false; + + int CenterX, CenterY; + + CenterX = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; + CenterY = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; + CenterX = (CenterX < 0) ? 0: CenterX; + CenterY = (CenterY < 0) ? 0: CenterY; + + // In VCR modes, keep it in the upper left so mouse coordinates are always relative to the window. + SetWindowPos (m_HWnd, NULL, CenterX, CenterY, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); + + return true; +} + + +//----------------------------------------------------------------------------- +// Sets up the game path +//----------------------------------------------------------------------------- +bool CShaderAPITestApp::SetupSearchPaths() +{ + if ( !BaseClass::SetupSearchPaths( NULL, false, true ) ) + return false; + + g_pFullFileSystem->AddSearchPath( GetGameInfoPath(), "SKIN", PATH_ADD_TO_HEAD ); + return true; +} + + +//----------------------------------------------------------------------------- +// PreInit, PostShutdown +//----------------------------------------------------------------------------- +bool CShaderAPITestApp::PreInit( ) +{ + if ( !BaseClass::PreInit() ) + return false; + + if (!g_pFullFileSystem || !g_pShaderDeviceMgr ) + return false; + + // Add paths... + if ( !SetupSearchPaths() ) + return false; + + const char *pArg; + int iWidth = 1024; + int iHeight = 768; + bool bWindowed = (CommandLine()->CheckParm( "-fullscreen" ) == NULL); + if (CommandLine()->CheckParm( "-width", &pArg )) + { + iWidth = atoi( pArg ); + } + if (CommandLine()->CheckParm( "-height", &pArg )) + { + iHeight = atoi( pArg ); + } + + if (!CreateAppWindow( "Press a Key To Continue", bWindowed, iWidth, iHeight )) + return false; + + return true; +} + +void CShaderAPITestApp::PostShutdown( ) +{ + BaseClass::PostShutdown(); +} + + +//----------------------------------------------------------------------------- +// Waits for a keypress +//----------------------------------------------------------------------------- +bool CShaderAPITestApp::WaitForKeypress() +{ + MSG msg = {0}; + while( WM_QUIT != msg.message ) + { + if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + + if ( msg.message == WM_KEYDOWN ) + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Displays adapter information +//----------------------------------------------------------------------------- +void CShaderAPITestApp::DisplayAdapterInfo() +{ + int nAdapterCount = g_pShaderDeviceMgr->GetAdapterCount(); + for ( int i = 0; i < nAdapterCount; ++i ) + { + MaterialAdapterInfo_t info; + g_pShaderDeviceMgr->GetAdapterInfo( i, info ); + + Msg( "Adapter %d\n", i ); + Msg( "\tName: %s\n\tVendor: 0x%X\n\tDevice: 0x%X\n\tSubSystem: 0x%X\n\tRevision: 0x%X\n\tRecommended DX Level: %d\n\tMax DX Level: %d\n", + info.m_pDriverName, info.m_VendorID, info.m_DeviceID, info.m_SubSysID, info.m_Revision, info.m_nDXSupportLevel, info.m_nMaxDXSupportLevel ); + + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + KeyValues *pConfiguration = new KeyValues( "Config" ); + g_pShaderDeviceMgr->GetRecommendedConfigurationInfo( i, info.m_nDXSupportLevel, pConfiguration ); + pConfiguration->RecursiveSaveToFile( buf, 1 ); + Msg( "\tConfiguration:\n%s", ( const char * )buf.Base() ); + Msg( "\n" ); + + int nModeCount = g_pShaderDeviceMgr->GetModeCount( i ); + Msg( "\tMode Count : %d\n", nModeCount ); + for ( int j = 0; j < nModeCount; ++j ) + { + ShaderDisplayMode_t mode; + g_pShaderDeviceMgr->GetModeInfo( &mode, i, j ); + Msg( "\t\tH: %5d W: %5d Format: %3d Refresh %3d/%3d\n", + mode.m_nWidth, mode.m_nHeight, mode.m_Format, mode.m_nRefreshRateNumerator, mode.m_nRefreshRateDenominator ); + } + } +} + + +//----------------------------------------------------------------------------- +// Sets the video mode +//----------------------------------------------------------------------------- +bool CShaderAPITestApp::SetMode() +{ + int nAdapterCount = g_pShaderDeviceMgr->GetAdapterCount(); + int nAdapter = CommandLine()->ParmValue( "-adapter", 0 ); + if ( nAdapter >= nAdapterCount ) + { + Warning( "Specified too high an adapter number on the command-line (%d/%d)!\n", nAdapter, nAdapterCount ); + return false; + } + + ShaderDeviceInfo_t mode; + mode.m_DisplayMode.m_nWidth = 1024; + mode.m_DisplayMode.m_nHeight = 768; + mode.m_DisplayMode.m_Format = IMAGE_FORMAT_BGRA8888; + mode.m_DisplayMode.m_nRefreshRateNumerator = 60; + mode.m_DisplayMode.m_nRefreshRateDenominator = 1; + mode.m_bWindowed = true; + mode.m_nBackBufferCount = 1; + + CreateInterfaceFn shaderFactory = g_pShaderDeviceMgr->SetMode( m_HWnd, nAdapter, mode ); + if ( !shaderFactory ) + { + Warning( "Unable to set mode!\n" ); + return false; + } + + m_pShaderAPI = (IShaderAPI*)shaderFactory( SHADERAPI_INTERFACE_VERSION, NULL ); + m_pShaderDevice = (IShaderDevice*)shaderFactory( SHADER_DEVICE_INTERFACE_VERSION, NULL ); + if ( !m_pShaderAPI || !m_pShaderDevice ) + { + Warning( "Unable to get IShaderAPI or IShaderDevice interface!\n" ); + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Creates really simple vertex + index buffers +//----------------------------------------------------------------------------- +void CShaderAPITestApp::CreateSimpleBuffers( ShaderBufferType_t nVBType, ShaderBufferType_t nIBType, bool bBuffered ) +{ + VertexFormat_t fmt = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_COLOR; + if ( IsDynamicBufferType( nVBType ) ) + { + m_pVertexBuffer = m_pShaderDevice->CreateVertexBuffer( + nVBType, VERTEX_FORMAT_UNKNOWN, 1024, "test" ); + } + else + { + m_pVertexBuffer = m_pShaderDevice->CreateVertexBuffer( + nVBType, fmt, 4, "test" ); + } + + static unsigned char s_pColors[4][4] = + { + { 255, 0, 0, 255 }, + { 0, 255, 0, 255 }, + { 0, 0, 255, 255 }, + { 255, 255, 255, 255 }, + }; + + static int nCount = 0; + + CVertexBuilder vb( m_pVertexBuffer, fmt ); + vb.Lock( 4 ); + + vb.Position3f( -1.0f, -1.0f, 0.5f ); + vb.Normal3f( 0.0f, 0.0f, 1.0f ); + vb.Color4ubv( s_pColors[nCount++ % 4] ); + vb.AdvanceVertex(); + + vb.Position3f( 1.0f, -1.0f, 0.5f ); + vb.Normal3f( 0.0f, 0.0f, 1.0f ); + vb.Color4ubv( s_pColors[nCount++ % 4] ); + vb.AdvanceVertex(); + + vb.Position3f( 1.0f, 1.0f, 0.5f ); + vb.Normal3f( 0.0f, 0.0f, 1.0f ); + vb.Color4ubv( s_pColors[nCount++ % 4] ); + vb.AdvanceVertex(); + + vb.Position3f( -1.0f, 1.0f, 0.5f ); + vb.Normal3f( 0.0f, 0.0f, 1.0f ); + vb.Color4ubv( s_pColors[nCount++ % 4] ); + vb.AdvanceVertex(); + + vb.SpewData( ); + vb.Unlock( ); + + ++nCount; + + if ( IsDynamicBufferType( nIBType ) ) + { + m_pIndexBuffer = m_pShaderDevice->CreateIndexBuffer( nIBType, MATERIAL_INDEX_FORMAT_UNKNOWN, 64, "test" ); + } + else + { + m_pIndexBuffer = m_pShaderDevice->CreateIndexBuffer( nIBType, MATERIAL_INDEX_FORMAT_16BIT, 6, "test" ); + } + CIndexBuilder ib( m_pIndexBuffer, MATERIAL_INDEX_FORMAT_16BIT ); + + ib.Lock( 6, 0 ); + ib.FastIndex( 0 ); + ib.FastIndex( 2 ); + ib.FastIndex( 1 ); + ib.FastIndex( 0 ); + ib.FastIndex( 3 ); + ib.FastIndex( 2 ); + ib.SpewData(); + ib.Unlock( ); + + m_pShaderAPI->BindVertexBuffer( 0, m_pVertexBuffer, vb.Offset(), 0, vb.TotalVertexCount(), fmt ); + m_pShaderAPI->BindIndexBuffer( m_pIndexBuffer, ib.Offset() ); +} + + +//----------------------------------------------------------------------------- +// Destroys the buffers +//----------------------------------------------------------------------------- +void CShaderAPITestApp::DestroyBuffers() +{ + if ( m_pVertexBuffer ) + { + m_pShaderDevice->DestroyVertexBuffer( m_pVertexBuffer ); + m_pVertexBuffer = NULL; + } + + if ( m_pIndexBuffer ) + { + m_pShaderDevice->DestroyIndexBuffer( m_pIndexBuffer ); + m_pIndexBuffer = NULL; + } +} + + +//----------------------------------------------------------------------------- +// shader programs +//----------------------------------------------------------------------------- +static const char s_pSimpleVertexShader[] = + "struct VS_INPUT " + "{ " + " float3 vPos : POSITION0; " + " float4 vColor : COLOR0; " + "}; " + " " + "struct VS_OUTPUT " + "{ " + " float4 projPos : POSITION0; " + " float4 vertexColor : COLOR0; " + "}; " + " " + "VS_OUTPUT main( const VS_INPUT v ) " + "{ " + " VS_OUTPUT o = ( VS_OUTPUT )0; " + " " + " o.projPos.xyz = v.vPos; " + " o.projPos.w = 1.0f; " + " o.vertexColor = v.vColor; " + " return o; " + "} " + ""; + +static const char s_pSimplePixelShader[] = + "struct PS_INPUT " + "{ " + " float4 projPos : POSITION0; " + " float4 vColor : COLOR0; " + "}; " + " " + "float4 main( const PS_INPUT i ) : COLOR " + "{ " + " return i.vColor; " + "} " + ""; + + +//----------------------------------------------------------------------------- +// Create, destroy shaders +//----------------------------------------------------------------------------- +void CShaderAPITestApp::CreateShaders( const char *pVShader, int nVBufLen, const char *pGShader, int nGBufLen, const char *pPShader, int nPBufLen ) +{ + const char *pVertexShaderVersion = g_pMaterialSystemHardwareConfig->GetDXSupportLevel() == 100 ? "vs_4_0" : "vs_2_0"; + const char *pPixelShaderVersion = g_pMaterialSystemHardwareConfig->GetDXSupportLevel() == 100 ? "ps_4_0" : "ps_2_0"; + + // Compile shaders + m_hVertexShader = m_pShaderDevice->CreateVertexShader( pVShader, nVBufLen, pVertexShaderVersion ); + Assert( m_hVertexShader != VERTEX_SHADER_HANDLE_INVALID ); + + m_hGeometryShader = GEOMETRY_SHADER_HANDLE_INVALID; + if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 100 ) + { + // m_hGeometryShader = m_pShaderDevice->CreateGeometryShader( pGShader, nGBufLen, "gs_4_0" ); + // Assert( m_hGeometryShader != GEOMETRY_SHADER_HANDLE_INVALID ); + } + + m_hPixelShader = m_pShaderDevice->CreatePixelShader( pPShader, nPBufLen, pPixelShaderVersion ); + Assert( m_hPixelShader != PIXEL_SHADER_HANDLE_INVALID ); + + m_pShaderAPI->BindVertexShader( m_hVertexShader ); + m_pShaderAPI->BindGeometryShader( m_hGeometryShader ); + m_pShaderAPI->BindPixelShader( m_hPixelShader ); +} + +void CShaderAPITestApp::DestroyShaders() +{ + m_pShaderDevice->DestroyVertexShader( m_hVertexShader ); + m_pShaderDevice->DestroyGeometryShader( m_hGeometryShader ); + m_pShaderDevice->DestroyPixelShader( m_hPixelShader ); + + m_hVertexShader = VERTEX_SHADER_HANDLE_INVALID; + m_hGeometryShader = GEOMETRY_SHADER_HANDLE_INVALID; + m_hPixelShader = PIXEL_SHADER_HANDLE_INVALID; +} + + +//----------------------------------------------------------------------------- +// DrawQuad +//----------------------------------------------------------------------------- +void CShaderAPITestApp::TestColoredQuad( ShaderBufferType_t nVBType, ShaderBufferType_t nIBType, bool bBuffered ) +{ + // clear (so that we can make sure that we aren't getting results from the previous quad) + m_pShaderAPI->ClearColor3ub( RandomInt( 0, 100 ), RandomInt( 0, 100 ), RandomInt( 190, 255 ) ); + m_pShaderAPI->ClearBuffers( true, false, false, -1, -1 ); + + CreateSimpleBuffers( nVBType, nIBType, bBuffered ); + + // Draw a quad! + CreateShaders( s_pSimpleVertexShader, sizeof(s_pSimpleVertexShader), + NULL, 0, s_pSimplePixelShader, sizeof(s_pSimplePixelShader) ); + + m_pShaderAPI->Draw( MATERIAL_TRIANGLES, 0, 6 ); + m_pShaderDevice->Present(); + + DestroyShaders(); + + DestroyBuffers(); +} + + +//----------------------------------------------------------------------------- +// Tests dynamic buffers +//----------------------------------------------------------------------------- +void CShaderAPITestApp::TestDynamicBuffers() +{ + m_pVertexBuffer = m_pShaderDevice->CreateVertexBuffer( + SHADER_BUFFER_TYPE_DYNAMIC, VERTEX_FORMAT_UNKNOWN, 0x100, "test" ); + m_pIndexBuffer = m_pShaderDevice->CreateIndexBuffer( + SHADER_BUFFER_TYPE_DYNAMIC, MATERIAL_INDEX_FORMAT_UNKNOWN, 30, "test" ); + + CreateShaders( s_pSimpleVertexShader, sizeof(s_pSimpleVertexShader), + NULL, 0, s_pSimplePixelShader, sizeof(s_pSimplePixelShader) ); + + // clear (so that we can make sure that we aren't getting results from the previous quad) + m_pShaderAPI->ClearColor3ub( RandomInt( 0, 100 ), RandomInt( 0, 100 ), RandomInt( 190, 255 ) ); + m_pShaderAPI->ClearBuffers( true, false, false, -1, -1 ); + + static unsigned char s_pColors[4][4] = + { + { 255, 0, 0, 255 }, + { 0, 255, 0, 255 }, + { 0, 0, 255, 255 }, + { 255, 255, 255, 255 }, + }; + + static int nCount = 0; + + VertexFormat_t fmt = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_COLOR; + const int nLoopCount = 8; + float flWidth = 2.0f / nLoopCount; + for ( int i = 0; i < nLoopCount; ++i ) + { + CVertexBuilder vb( m_pVertexBuffer, fmt ); + vb.Lock( 4 ); + + vb.Position3f( -1.0f + i * flWidth, -1.0f, 0.5f ); + vb.Normal3f( 0.0f, 0.0f, 1.0f ); + vb.Color4ubv( s_pColors[nCount++ % 4] ); + vb.AdvanceVertex(); + + vb.Position3f( -1.0f + i * flWidth + flWidth, -1.0f, 0.5f ); + vb.Normal3f( 0.0f, 0.0f, 1.0f ); + vb.Color4ubv( s_pColors[nCount++ % 4] ); + vb.AdvanceVertex(); + + vb.Position3f( -1.0f + i * flWidth + flWidth, 1.0f, 0.5f ); + vb.Normal3f( 0.0f, 0.0f, 1.0f ); + vb.Color4ubv( s_pColors[nCount++ % 4] ); + vb.AdvanceVertex(); + + vb.Position3f( -1.0f + i * flWidth, 1.0f, 0.5f ); + vb.Normal3f( 0.0f, 0.0f, 1.0f ); + vb.Color4ubv( s_pColors[nCount++ % 4] ); + vb.AdvanceVertex(); + vb.SpewData(); + vb.Unlock( ); + + ++nCount; + + CIndexBuilder ib( m_pIndexBuffer, MATERIAL_INDEX_FORMAT_16BIT ); + + ib.Lock( 6, vb.GetFirstVertex() ); + ib.FastIndex( 0 ); + ib.FastIndex( 2 ); + ib.FastIndex( 1 ); + ib.FastIndex( 0 ); + ib.FastIndex( 3 ); + ib.FastIndex( 2 ); + ib.SpewData(); + ib.Unlock( ); + + m_pShaderAPI->BindVertexBuffer( 0, m_pVertexBuffer, vb.Offset(), vb.GetFirstVertex(), vb.TotalVertexCount(), fmt ); + m_pShaderAPI->BindIndexBuffer( m_pIndexBuffer, ib.Offset() ); + m_pShaderAPI->Draw( MATERIAL_TRIANGLES, ib.GetFirstIndex(), ib.TotalIndexCount() ); + } + + m_pShaderDevice->Present(); + + ++nCount; + + DestroyShaders(); + DestroyBuffers(); +} + + +//----------------------------------------------------------------------------- +// Create dynamic combos +//----------------------------------------------------------------------------- +static uint32 NextULONG( uint8 * &pData ) +{ + // handle unaligned read + uint32 nRet; + memcpy( &nRet, pData, sizeof( nRet ) ); + pData += sizeof( nRet ); + return nRet; +} + +bool CShaderAPITestApp::CreateDynamicCombos_Ver5( uint8 *pComboBuffer, bool bVertexShader ) +{ + uint8 *pCompressedShaders = pComboBuffer; + uint8 *pUnpackBuffer = new uint8[MAX_SHADER_UNPACKED_BLOCK_SIZE]; + + // now, loop through all blocks + bool bOK = true; + while ( bOK ) + { + uint32 nBlockSize = NextULONG( pCompressedShaders ); + if ( nBlockSize == 0xffffffff ) + { + // any more blocks? + break; + } + + switch( nBlockSize & 0xc0000000 ) + { + case 0: // bzip2 + { + // uncompress + uint32 nOutsize = MAX_SHADER_UNPACKED_BLOCK_SIZE; + int nRslt = BZ2_bzBuffToBuffDecompress( + reinterpret_cast<char *>( pUnpackBuffer ), + &nOutsize, + reinterpret_cast<char *>( pCompressedShaders ), + nBlockSize, 1, 0 ); + if ( nRslt < 0 ) + { + // errors are negative for bzip + Assert( 0 ); + Warning( "BZIP Error (%d) decompressing shader", nRslt ); + bOK = false; + } + + pCompressedShaders += nBlockSize; + nBlockSize = nOutsize; // how much data there is + } + break; + + case 0x80000000: // uncompressed + { + // not compressed, as is + nBlockSize &= 0x3fffffff; + memcpy( pUnpackBuffer, pCompressedShaders, nBlockSize ); + pCompressedShaders += nBlockSize; + } + break; + + case 0x40000000: // lzma compressed + { + nBlockSize &= 0x3fffffff; + + size_t nOutsize = CLZMA::Uncompress( + reinterpret_cast<uint8 *>( pCompressedShaders ), + pUnpackBuffer ); + pCompressedShaders += nBlockSize; + nBlockSize = nOutsize; // how much data there is + } + break; + + default: + { + Assert( 0 ); + Error(" unrecognized shader compression type = file corrupt?"); + bOK = false; + } + } + + uint8 *pReadPtr = pUnpackBuffer; + while ( pReadPtr < pUnpackBuffer+nBlockSize ) + { + uint32 nCombo_ID = NextULONG( pReadPtr ); + (void)nCombo_ID; // Suppress local variable is initialized but not referenced warning + uint32 nShaderSize = NextULONG( pReadPtr ); + + CUtlBuffer buf( pReadPtr, nShaderSize ); + if ( bVertexShader ) + { + m_pShaderDevice->CreateVertexShader( buf, "vs_2_0" ); + } + else + { + m_pShaderDevice->CreatePixelShader( buf, "ps_2_b" ); + } + + pReadPtr += nShaderSize; + } + } + + delete[] pUnpackBuffer; + + return bOK; +} + + +//----------------------------------------------------------------------------- +// Load shader +//----------------------------------------------------------------------------- +void CShaderAPITestApp::LoadShaderFile( const char *pName, bool bVertexShader ) +{ + // next, try the fxc dir + char pFileName[MAX_PATH]; + Q_snprintf( pFileName, MAX_PATH, "..\\hl2\\shaders\\fxc\\%s.vcs", pName ); + + FileHandle_t hFile = g_pFullFileSystem->Open( pFileName, "rb", "EXECUTABLE_PATH" ); + if ( hFile == FILESYSTEM_INVALID_HANDLE ) + { + Warning( "Couldn't load %s shader %s\n", bVertexShader ? "vertex" : "pixel", pName ); + return; + } + + ShaderHeader_t header; + g_pFullFileSystem->Read( &header, sizeof( ShaderHeader_t ), hFile ); + + // cache the dictionary + int nComboSize = header.m_nNumStaticCombos * sizeof( StaticComboRecord_t ); + StaticComboRecord_t *pRecords = (StaticComboRecord_t *)malloc( nComboSize ); + g_pFullFileSystem->Read( pRecords, nComboSize, hFile ); + + for ( unsigned int i = 0; i < header.m_nNumStaticCombos - 1; ++i ) + { + int nStartingOffset = pRecords[i].m_nFileOffset; + int nEndingOffset = pRecords[i+1].m_nFileOffset; + int nShaderSize = nEndingOffset - nStartingOffset; + + uint8 *pBuf = (uint8*)malloc( nShaderSize ); + g_pFullFileSystem->Seek( hFile, nStartingOffset, FILESYSTEM_SEEK_HEAD ); + g_pFullFileSystem->Read( pBuf, nShaderSize, hFile ); + + CreateDynamicCombos_Ver5( pBuf, bVertexShader ); + free( pBuf ); + + } + + free( pRecords ); + g_pFullFileSystem->Close( hFile ); + +} + + +//----------------------------------------------------------------------------- +// main application +//----------------------------------------------------------------------------- +int CShaderAPITestApp::Main() +{ + DisplayAdapterInfo(); + if ( !SetMode() ) + return 0; + + // Test buffer clearing + m_pShaderAPI->ClearColor3ub( RandomInt( 0, 100 ), RandomInt( 0, 100 ), RandomInt( 190, 255 ) ); + m_pShaderAPI->ClearBuffers( true, false, false, -1, -1 ); + m_pShaderDevice->Present(); + + SetWindowText( m_HWnd, "ClearBuffers test results . . hit a key" ); + + if ( !WaitForKeypress() ) + return 1; + + // Test viewport + int nMaxViewports = g_pMaterialSystemHardwareConfig->MaxViewports(); + ShaderViewport_t* pViewports = ( ShaderViewport_t* )_alloca( nMaxViewports * sizeof(ShaderViewport_t) ); + for ( int i = 0; i < nMaxViewports; ++i ) + { + int x = RandomInt( 0, 100 ); + int y = RandomInt( 0, 100 ); + int w = RandomInt( 100, 200 ); + int h = RandomInt( 100, 200 ); + pViewports[i].Init( x, y, w, h ); + + m_pShaderAPI->SetViewports( i+1, pViewports ); + } + + SetWindowText( m_HWnd, "SetViewports test results . . hit a key" ); + + if ( !WaitForKeypress() ) + return 1; + + // Sets up a full-screen viewport + int w, h; + m_pShaderDevice->GetWindowSize( w, h ); + + ShaderViewport_t viewport; + viewport.Init( 0, 0, w, h ); + m_pShaderAPI->SetViewports( 1, &viewport ); + + // Test drawing a full-screen quad with interpolated vertex colors for every combo of static/dynamic VB, static dynamic IB, buffered/non-buffered. + char buf[1024]; + for ( int nVBType = 0; nVBType < SHADER_BUFFER_TYPE_COUNT; ++nVBType ) + { + // FIXME: Remove + if ( nVBType > SHADER_BUFFER_TYPE_DYNAMIC ) + continue; + + for( int nIBType = 0; nIBType < SHADER_BUFFER_TYPE_COUNT; ++nIBType ) + { + // FIXME: Remove + if ( nIBType > SHADER_BUFFER_TYPE_DYNAMIC ) + continue; + + // MESHFIXME: make buffered vertex buffers/index buffers work. + int nBuffered = 0; +// for( nBuffered = 0; nBuffered < 2; nBuffered++ ) + { + TestColoredQuad( (ShaderBufferType_t)nVBType, (ShaderBufferType_t)nIBType, nBuffered != 0 ); + + sprintf( buf, "TestColoredQuad results VB: %d IB: %d Buffered: %d HIT A KEY!", + nVBType, nIBType, nBuffered != 0 ); + SetWindowText( m_HWnd, buf ); + + if ( !WaitForKeypress() ) + return 1; + } + } + } + + SetWindowText( m_HWnd, "Dynamic Buffer Test: HIT A KEY!" ); + TestDynamicBuffers(); + if ( !WaitForKeypress() ) + return 1; + + g_pMaterialSystemHardwareConfig->OverrideStreamOffsetSupport( true, false ); + + SetWindowText( m_HWnd, "Dynamic Buffer Test (no stream offset): HIT A KEY!" ); + TestDynamicBuffers(); + if ( !WaitForKeypress() ) + return 1; + + g_pMaterialSystemHardwareConfig->OverrideStreamOffsetSupport( false, false ); + + return 1; +} diff --git a/unittests/shaderapitest/shaderapitest.vpc b/unittests/shaderapitest/shaderapitest.vpc new file mode 100644 index 0000000..30ba082 --- /dev/null +++ b/unittests/shaderapitest/shaderapitest.vpc @@ -0,0 +1,25 @@ +//----------------------------------------------------------------------------- +// SHADERAPITEST.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_base.vpc" + +$Project "ShaderAPITest" +{ + $Folder "Source Files" + { + $File "shaderapitest.cpp" + } + + $Folder "Link Libraries" + { + $Lib appframework + $Lib tier2 + $Lib $LIBCOMMON\bzip2 + } +} diff --git a/unittests/soundtest/soundtest.cpp b/unittests/soundtest/soundtest.cpp new file mode 100644 index 0000000..e43b3c5 --- /dev/null +++ b/unittests/soundtest/soundtest.cpp @@ -0,0 +1,306 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Sound unit test application +// +//============================================================================= + +#include <windows.h> +#include "tier0/dbg.h" +#include "tier0/icommandline.h" +#include "filesystem.h" +#include "datacache/idatacache.h" +#include "appframework/appframework.h" +#include "soundsystem/isoundsystem.h" +#include "vstdlib/cvar.h" +#include "filesystem_init.h" + + +//----------------------------------------------------------------------------- +// Main system interfaces +//----------------------------------------------------------------------------- +IFileSystem *g_pFileSystem; +ISoundSystem *g_pSoundSystem; + + +//----------------------------------------------------------------------------- +// Standard spew functions +//----------------------------------------------------------------------------- +static SpewRetval_t SoundTestOutputFunc( SpewType_t spewType, char const *pMsg ) +{ + printf( pMsg ); + fflush( stdout ); + + if (spewType == SPEW_ERROR) + return SPEW_ABORT; + return (spewType == SPEW_ASSERT) ? SPEW_DEBUGGER : SPEW_CONTINUE; +} + + + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CSoundTestApp : public CDefaultAppSystemGroup<CSteamAppSystemGroup> +{ +public: + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit(); + virtual int Main(); + virtual void PostShutdown(); + virtual void Destroy(); + +private: + bool CreateAppWindow( char const *pTitle, bool bWindowed, int w, int h ); + bool SetupSearchPaths(); + void AppPumpMessages(); + + // Windproc + static LONG WINAPI WinAppWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + LONG WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + HWND m_hWnd; + bool m_bExitMainLoop; +}; + +static CSoundTestApp s_SoundTestApp; +DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT_GLOBALVAR( CSoundTestApp, s_SoundTestApp ); + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +bool CSoundTestApp::Create() +{ + SpewOutputFunc( SoundTestOutputFunc ); + + // Add in the cvar factory + AppModule_t cvarModule = LoadModule( VStdLib_GetICVarFactory() ); + AddSystem( cvarModule, CVAR_INTERFACE_VERSION ); + + AppSystemInfo_t appSystems[] = + { + { "datacache.dll", DATACACHE_INTERFACE_VERSION }, + { "soundsystem.dll", SOUNDSYSTEM_INTERFACE_VERSION }, + { "", "" } // Required to terminate the list + }; + + if ( !AddSystems( appSystems ) ) + return false; + + g_pFileSystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION ); + g_pSoundSystem = (ISoundSystem*)FindSystem( SOUNDSYSTEM_INTERFACE_VERSION ); + + return ( g_pFileSystem && g_pSoundSystem ); +} + +void CSoundTestApp::Destroy() +{ + g_pFileSystem = NULL; + g_pSoundSystem = NULL; +} + + +//----------------------------------------------------------------------------- +// Window management +//----------------------------------------------------------------------------- +bool CSoundTestApp::CreateAppWindow( char const *pTitle, bool bWindowed, int w, int h ) +{ + WNDCLASSEX wc; + memset( &wc, 0, sizeof( wc ) ); + wc.cbSize = sizeof( wc ); + wc.style = CS_OWNDC | CS_DBLCLKS; + wc.lpfnWndProc = WinAppWindowProc; + wc.hInstance = (HINSTANCE)GetAppInstance(); + wc.lpszClassName = "Valve001"; + wc.hIcon = NULL; //LoadIcon( s_HInstance, MAKEINTRESOURCE( IDI_LAUNCHER ) ); + wc.hIconSm = wc.hIcon; + + RegisterClassEx( &wc ); + + // Note, it's hidden + DWORD style = WS_POPUP | WS_CLIPSIBLINGS; + + if ( bWindowed ) + { + // Give it a frame + style |= WS_OVERLAPPEDWINDOW; + style &= ~WS_THICKFRAME; + } + + // Never a max box + style &= ~WS_MAXIMIZEBOX; + + RECT windowRect; + windowRect.top = 0; + windowRect.left = 0; + windowRect.right = w; + windowRect.bottom = h; + + // Compute rect needed for that size client area based on window style + AdjustWindowRectEx(&windowRect, style, FALSE, 0); + + // Create the window + m_hWnd = CreateWindow( wc.lpszClassName, pTitle, style, 0, 0, + windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, + NULL, NULL, (HINSTANCE)GetAppInstance(), NULL ); + + if ( m_hWnd == INVALID_HANDLE_VALUE ) + return false; + + int CenterX, CenterY; + + CenterX = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; + CenterY = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; + CenterX = (CenterX < 0) ? 0: CenterX; + CenterY = (CenterY < 0) ? 0: CenterY; + + // In VCR modes, keep it in the upper left so mouse coordinates are always relative to the window. + SetWindowPos (m_hWnd, NULL, CenterX, CenterY, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); + + return true; +} + + +//----------------------------------------------------------------------------- +// Message handler +//----------------------------------------------------------------------------- +LONG CSoundTestApp::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if ( uMsg == WM_CLOSE ) + { + m_bExitMainLoop = true; + } + return DefWindowProc( hWnd, uMsg, wParam, lParam ); +} + +LONG WINAPI CSoundTestApp::WinAppWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + return s_SoundTestApp.WindowProc( hWnd, uMsg, wParam, lParam ); +} + + +//----------------------------------------------------------------------------- +// Sets up the game path +//----------------------------------------------------------------------------- +bool CSoundTestApp::SetupSearchPaths() +{ + CFSSteamSetupInfo steamInfo; + steamInfo.m_pDirectoryName = NULL; + steamInfo.m_bOnlyUseDirectoryName = false; + steamInfo.m_bToolsMode = true; + steamInfo.m_bSetSteamDLLPath = true; + steamInfo.m_bSteam = g_pFileSystem->IsSteam(); + if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK ) + return false; + + CFSMountContentInfo fsInfo; + fsInfo.m_pFileSystem = g_pFileSystem; + fsInfo.m_bToolsMode = true; + fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath; + + if ( FileSystem_MountContent( fsInfo ) != FS_OK ) + return false; + + // Finally, load the search paths for the "GAME" path. + CFSSearchPathsInit searchPathsInit; + searchPathsInit.m_pDirectoryName = steamInfo.m_GameInfoPath; + searchPathsInit.m_pFileSystem = g_pFileSystem; + if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK ) + return false; + + g_pFileSystem->AddSearchPath( steamInfo.m_GameInfoPath, "SKIN", PATH_ADD_TO_HEAD ); + + FileSystem_AddSearchPath_Platform( g_pFileSystem, steamInfo.m_GameInfoPath ); + + // and now add episodic to the GAME searchpath + char shorts[MAX_PATH]; + Q_strncpy( shorts, steamInfo.m_GameInfoPath, MAX_PATH ); + Q_StripTrailingSlash( shorts ); + Q_strncat( shorts, "/../episodic", MAX_PATH, MAX_PATH ); + + g_pFileSystem->AddSearchPath( shorts, "GAME", PATH_ADD_TO_HEAD ); + + return true; +} + + +//----------------------------------------------------------------------------- +// PreInit, PostShutdown +//----------------------------------------------------------------------------- +bool CSoundTestApp::PreInit( ) +{ + // Add paths... + if ( !SetupSearchPaths() ) + return false; + + const char *pArg; + int iWidth = 1024; + int iHeight = 768; + bool bWindowed = (CommandLine()->CheckParm( "-fullscreen" ) == NULL); + if (CommandLine()->CheckParm( "-width", &pArg )) + { + iWidth = atoi( pArg ); + } + if (CommandLine()->CheckParm( "-height", &pArg )) + { + iHeight = atoi( pArg ); + } + + if ( !CreateAppWindow( "SoundTest", bWindowed, iWidth, iHeight ) ) + return false; + + return true; +} + +void CSoundTestApp::PostShutdown() +{ +} + + +//----------------------------------------------------------------------------- +// Pump messages +//----------------------------------------------------------------------------- +void CSoundTestApp::AppPumpMessages() +{ + MSG msg; + while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } +} + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +int CSoundTestApp::Main() +{ + CAudioSource *pSource = g_pSoundSystem->LoadSound( "sound/ambient/alarms/alarm1.wav" ); + + CAudioMixer *pMixer; + g_pSoundSystem->PlaySound( pSource, 1.0f, &pMixer ); + + m_bExitMainLoop = false; + while ( !m_bExitMainLoop ) + { + AppPumpMessages(); + g_pSoundSystem->Update( Plat_FloatTime() ); + } + + return 1; +} + + + diff --git a/unittests/soundtest/soundtest.vpc b/unittests/soundtest/soundtest.vpc new file mode 100644 index 0000000..c98027e --- /dev/null +++ b/unittests/soundtest/soundtest.vpc @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// SOUNDTEST.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_win_win32_base.vpc" + +$Project "Soundtest" +{ + $Folder "Source Files" + { + $File "$SRCDIR\public\filesystem_init.cpp" + $File "soundtest.cpp" + } + + $Folder "Link Libraries" + { + $DynamicFile "$SRCDIR\lib\public\appframework.lib" + } +} diff --git a/unittests/testprocess/testprocess.cpp b/unittests/testprocess/testprocess.cpp new file mode 100644 index 0000000..23fbde8 --- /dev/null +++ b/unittests/testprocess/testprocess.cpp @@ -0,0 +1,191 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#include <windows.h> +#include "tier0/icommandline.h" +#include <stdio.h> +#include "tier0/dbg.h" + + +static unsigned short g_InitialColor = 0xFFFF; +static unsigned short g_LastColor = 0xFFFF; +static unsigned short g_BadColor = 0xFFFF; +static WORD g_BackgroundFlags = 0xFFFF; + +static void GetInitialColors( ) +{ + // Get the old background attributes. + CONSOLE_SCREEN_BUFFER_INFO oldInfo; + GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &oldInfo ); + g_InitialColor = g_LastColor = oldInfo.wAttributes & (FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY); + g_BackgroundFlags = oldInfo.wAttributes & (BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY); + + g_BadColor = 0; + if (g_BackgroundFlags & BACKGROUND_RED) + g_BadColor |= FOREGROUND_RED; + if (g_BackgroundFlags & BACKGROUND_GREEN) + g_BadColor |= FOREGROUND_GREEN; + if (g_BackgroundFlags & BACKGROUND_BLUE) + g_BadColor |= FOREGROUND_BLUE; + if (g_BackgroundFlags & BACKGROUND_INTENSITY) + g_BadColor |= FOREGROUND_INTENSITY; +} + +static WORD SetConsoleTextColor( int red, int green, int blue, int intensity ) +{ + WORD ret = g_LastColor; + + g_LastColor = 0; + if( red ) g_LastColor |= FOREGROUND_RED; + if( green ) g_LastColor |= FOREGROUND_GREEN; + if( blue ) g_LastColor |= FOREGROUND_BLUE; + if( intensity ) g_LastColor |= FOREGROUND_INTENSITY; + + // Just use the initial color if there's a match... + if (g_LastColor == g_BadColor) + g_LastColor = g_InitialColor; + + SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), g_LastColor | g_BackgroundFlags ); + return ret; +} + + +static void RestoreConsoleTextColor( WORD color ) +{ + SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), color | g_BackgroundFlags ); + g_LastColor = color; +} + +void CmdLib_Exit( int exitCode ) +{ + TerminateProcess( GetCurrentProcess(), 1 ); +} + +CRITICAL_SECTION g_SpewCS; +bool g_bSpewCSInitted = false; +bool g_bSuppressPrintfOutput = false; + +SpewRetval_t CmdLib_SpewOutputFunc( SpewType_t type, char const *pMsg ) +{ + // Hopefully two threads won't call this simultaneously right at the start! + if ( !g_bSpewCSInitted ) + { + InitializeCriticalSection( &g_SpewCS ); + g_bSpewCSInitted = true; + } + + WORD old; + SpewRetval_t retVal; + + EnterCriticalSection( &g_SpewCS ); + { + if (( type == SPEW_MESSAGE ) || (type == SPEW_LOG )) + { + old = SetConsoleTextColor( 1, 1, 1, 0 ); + retVal = SPEW_CONTINUE; + } + else if( type == SPEW_WARNING ) + { + old = SetConsoleTextColor( 1, 1, 0, 1 ); + retVal = SPEW_CONTINUE; + } + else if( type == SPEW_ASSERT ) + { + old = SetConsoleTextColor( 1, 0, 0, 1 ); + retVal = SPEW_DEBUGGER; + +#ifdef MPI + // VMPI workers don't want to bring up dialogs and suchlike. + if ( g_bUseMPI && !g_bMPIMaster ) + { + VMPI_HandleCrash( pMsg, true ); + exit( 0 ); + } +#endif + } + else if( type == SPEW_ERROR ) + { + old = SetConsoleTextColor( 1, 0, 0, 1 ); + retVal = SPEW_ABORT; // doesn't matter.. we exit below so we can return an errorlevel (which dbg.dll doesn't do). + } + else + { + old = SetConsoleTextColor( 1, 1, 1, 1 ); + retVal = SPEW_CONTINUE; + } + + if ( !g_bSuppressPrintfOutput || type == SPEW_ERROR ) + printf( "%s", pMsg ); + + OutputDebugString( pMsg ); + + if ( type == SPEW_ERROR ) + { + printf( "\n" ); + OutputDebugString( "\n" ); + } + + RestoreConsoleTextColor( old ); + } + LeaveCriticalSection( &g_SpewCS ); + + if ( type == SPEW_ERROR ) + { + CmdLib_Exit( 1 ); + } + + return retVal; +} + + +void InstallSpewFunction() +{ + setvbuf( stdout, NULL, _IONBF, 0 ); + setvbuf( stderr, NULL, _IONBF, 0 ); + + SpewOutputFunc( CmdLib_SpewOutputFunc ); + GetInitialColors(); +} + + +//----------------------------------------------------------------------------- +// Tests the process.cpp stuff +//----------------------------------------------------------------------------- +int main( int argc, char **argv ) +{ + CommandLine()->CreateCmdLine( argc, argv ); + InstallSpewFunction(); + + float flDelay = CommandLine()->ParmValue( "-delay", 0.0f ); + const char *pEndMessage = CommandLine()->ParmValue( "-message", "Test Finished!\n" ); + int nEndExtraBytes = CommandLine()->ParmValue( "-extrabytes", 0 ); + + if ( flDelay > 0.0f ) + { + float t = Plat_FloatTime(); + while ( Plat_FloatTime() - t < flDelay ) + { + } + } + + Msg( pEndMessage ); + + if ( nEndExtraBytes ) + { + while( --nEndExtraBytes >= 0 ) + { + Msg( "%c", ( nEndExtraBytes % 10 ) + '0' ); + } + } + + return 0; +} + + + + diff --git a/unittests/testprocess/testprocess.exe b/unittests/testprocess/testprocess.exe Binary files differnew file mode 100644 index 0000000..eee66a3 --- /dev/null +++ b/unittests/testprocess/testprocess.exe diff --git a/unittests/testprocess/testprocess.pdb b/unittests/testprocess/testprocess.pdb Binary files differnew file mode 100644 index 0000000..d40bd3c --- /dev/null +++ b/unittests/testprocess/testprocess.pdb diff --git a/unittests/testprocess/testprocess.vpc b/unittests/testprocess/testprocess.vpc new file mode 100644 index 0000000..44cc746 --- /dev/null +++ b/unittests/testprocess/testprocess.vpc @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// TESTPROCESS.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$MacroRequired "PLATSUBDIR" + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\unittests\testprocess" + +$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc" + +$Configuration "Debug" +{ + $Compiler + { + $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE" + } + + $Linker + { + $AdditionalDependencies "$BASE winmm.lib" + } +} + +$Project "Testprocess" +{ + $Folder "Source Files" + { + $File "testprocess.cpp" + } + + $Folder "Link Libraries" + { + $Lib tier2 + } +} diff --git a/unittests/tier1test/commandbuffertest.cpp b/unittests/tier1test/commandbuffertest.cpp new file mode 100644 index 0000000..e51d647 --- /dev/null +++ b/unittests/tier1test/commandbuffertest.cpp @@ -0,0 +1,308 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for CommandBuffer +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "tier1/commandbuffer.h" +#include "tier1/strtools.h" + + +DEFINE_TESTSUITE( CommandBufferTestSuite ) + +DEFINE_TESTCASE( CommandBufferTestSimple, CommandBufferTestSuite ) +{ + Msg( "Simple command buffer test...\n" ); + + CCommandBuffer buffer; + buffer.AddText( "test_command test_arg1 test_arg2" ); + buffer.AddText( "test_command2 test_arg3; test_command3 test_arg4" ); + buffer.AddText( "test_command4\ntest_command5" ); + buffer.AddText( "test_command6 // Comment; test_command7" ); + buffer.AddText( "test_command8 // Comment; test_command9\ntest_command10" ); + buffer.AddText( "test_command11 \"test_arg5 test_arg6\"" ); + buffer.AddText( "test_command12 \"\"" ); + buffer.AddText( "// Comment\ntest_command13\t\t\"test_arg7\"" ); + buffer.AddText( "test_command14\"test_arg8\"test_arg9" ); + buffer.AddText( "test_command15 test_arg10" ); + buffer.AddText( "test_command16 test_arg11:test_arg12" ); + + int argc; + const char **argv; + buffer.BeginProcessingCommands( 1 ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 3 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg1" ) ); + Shipping_Assert( !Q_stricmp( argv[2], "test_arg2" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "test_arg1 test_arg2" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 2 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command2" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg3" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "test_arg3" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 2 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command3" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg4" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "test_arg4" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command4" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command5" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command6" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command8" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command10" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 2 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command11" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg5 test_arg6" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "\"test_arg5 test_arg6\"" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 2 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command12" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "\"\"" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 2 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command13" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg7" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "\"test_arg7\"" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 3 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command14" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg8" ) ); + Shipping_Assert( !Q_stricmp( argv[2], "test_arg9" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "\"test_arg8\"test_arg9" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 2 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command15" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg10" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "test_arg10" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 4 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command16" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg11" ) ); + Shipping_Assert( !Q_stricmp( argv[2], ":" ) ); + Shipping_Assert( !Q_stricmp( argv[3], "test_arg12" ) ); + Shipping_Assert( !Q_stricmp( buffer.ArgS(), "test_arg11:test_arg12" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); + + buffer.EndProcessingCommands( ); +} + + +DEFINE_TESTCASE( CommandBufferTestTiming, CommandBufferTestSuite ) +{ + Msg( "Delayed command buffer test...\n" ); + + CCommandBuffer buffer; + + buffer.AddText( "test_command test_arg1 test_arg2" ); + buffer.AddText( "test_command2 test_arg1 test_arg2 test_arg3", 1 ); + buffer.AddText( "test_command3;wait;test_command4;wait 2;test_command5" ); + + int argc; + const char **argv; + { + buffer.BeginProcessingCommands( 1 ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 3 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg1" ) ); + Shipping_Assert( !Q_stricmp( argv[2], "test_arg2" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command3" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); + + buffer.EndProcessingCommands( ); + } + { + buffer.BeginProcessingCommands( 1 ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 4 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command2" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg1" ) ); + Shipping_Assert( !Q_stricmp( argv[2], "test_arg2" ) ); + Shipping_Assert( !Q_stricmp( argv[3], "test_arg3" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command4" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); + + buffer.EndProcessingCommands( ); + } + { + buffer.BeginProcessingCommands( 1 ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); + + buffer.EndProcessingCommands( ); + } + { + buffer.BeginProcessingCommands( 1 ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command5" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); + + buffer.EndProcessingCommands( ); + } +} + + +DEFINE_TESTCASE( CommandBufferTestNested, CommandBufferTestSuite ) +{ + Msg( "Nested command buffer test...\n" ); + + CCommandBuffer buffer; + buffer.AddText( "test_command test_arg1 test_arg2" ); + buffer.AddText( "test_command2 test_arg3 test_arg4 test_arg5", 2 ); + + int argc; + const char **argv; + { + buffer.BeginProcessingCommands( 2 ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 3 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg1" ) ); + Shipping_Assert( !Q_stricmp( argv[2], "test_arg2" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); + + buffer.AddText( "test_command3;test_command4", 1 ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command3" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command4" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); + + buffer.EndProcessingCommands( ); + } + { + buffer.BeginProcessingCommands( 1 ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 4 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command2" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg3" ) ); + Shipping_Assert( !Q_stricmp( argv[2], "test_arg4" ) ); + Shipping_Assert( !Q_stricmp( argv[3], "test_arg5" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); + + buffer.EndProcessingCommands( ); + } +} + + +DEFINE_TESTCASE( CommandBufferTestOverflow, CommandBufferTestSuite ) +{ + Msg( "Command buffer overflow test...\n" ); + + CCommandBuffer buffer; + + buffer.LimitArgumentBufferSize( 40 ); + bool bOk = buffer.AddText( "test_command test_arg1 test_arg2" ); // 32 chars + Shipping_Assert( bOk ); + bOk = buffer.AddText( "test_command2 test_arg3 test_arg4 test_arg5", 2 ); // 43 chars + Shipping_Assert( !bOk ); + + int argc; + const char **argv; + { + buffer.BeginProcessingCommands( 1 ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 3 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg1" ) ); + Shipping_Assert( !Q_stricmp( argv[2], "test_arg2" ) ); + + bOk = buffer.AddText( "test_command3 test_arg6;wait;test_command4" ); + Shipping_Assert( bOk ); + + // This makes sure that AddText doesn't cause argv to become bogus after + // compacting memory + Shipping_Assert( !Q_stricmp( argv[0], "test_command" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg1" ) ); + Shipping_Assert( !Q_stricmp( argv[2], "test_arg2" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 2 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command3" ) ); + Shipping_Assert( !Q_stricmp( argv[1], "test_arg6" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); + + buffer.EndProcessingCommands( ); + } + { + buffer.BeginProcessingCommands( 1 ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 1 ); + Shipping_Assert( !Q_stricmp( argv[0], "test_command4" ) ); + + argc = buffer.DequeueNextCommand( argv ); + Shipping_Assert( argc == 0 ); + + buffer.EndProcessingCommands( ); + } +} + diff --git a/unittests/tier1test/processtest.cpp b/unittests/tier1test/processtest.cpp new file mode 100644 index 0000000..e83d7dc --- /dev/null +++ b/unittests/tier1test/processtest.cpp @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for processes +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "vstdlib/iprocessutils.h" +#include "tier1/strtools.h" +#include "tier1/tier1.h" +#include "tier0/dbg.h" + + +DEFINE_TESTSUITE( ProcessTestSuite ) + +DEFINE_TESTCASE( ProcessTestSimple, ProcessTestSuite ) +{ + Msg( "Simple process test...\n" ); + + ProcessHandle_t hProcess = g_pProcessUtils->StartProcess( "unittests\\testprocess.exe -delay 1.0", true ); + g_pProcessUtils->WaitUntilProcessCompletes( hProcess ); + int nLen = g_pProcessUtils->GetProcessOutputSize( hProcess ); + char *pBuf = (char*)_alloca( nLen ); + g_pProcessUtils->GetProcessOutput( hProcess, pBuf, nLen ); + g_pProcessUtils->CloseProcess( hProcess ); + Shipping_Assert( !Q_stricmp( pBuf, "Test Finished!\n" ) ); +} + + +DEFINE_TESTCASE( ProcessTestBufferOverflow, ProcessTestSuite ) +{ + Msg( "Buffer overflow process test...\n" ); + + ProcessHandle_t hProcess = g_pProcessUtils->StartProcess( "unittests\\testprocess.exe -delay 1.0 -extrabytes 32768", true ); + g_pProcessUtils->WaitUntilProcessCompletes( hProcess ); + int nLen = g_pProcessUtils->GetProcessOutputSize( hProcess ); + Shipping_Assert( nLen == 32768 + 16 ); + char *pBuf = (char*)_alloca( nLen ); + g_pProcessUtils->GetProcessOutput( hProcess, pBuf, nLen ); + g_pProcessUtils->CloseProcess( hProcess ); + Shipping_Assert( !Q_strnicmp( pBuf, "Test Finished!\n", 15 ) ); + + int nEndExtraBytes = 32768; + char *pTest = pBuf + 15; + while( --nEndExtraBytes >= 0 ) + { + Shipping_Assert( *pTest == (( nEndExtraBytes % 10 ) + '0') ); + ++pTest; + } +} + diff --git a/unittests/tier1test/tier1test.cpp b/unittests/tier1test/tier1test.cpp new file mode 100644 index 0000000..2dc85d7 --- /dev/null +++ b/unittests/tier1test/tier1test.cpp @@ -0,0 +1,47 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for testing of tier1 libraries +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "tier1/tier1.h" +#include "mathlib/mathlib.h" +#include "tier1/convar.h" +#include "vstdlib/iprocessutils.h" + + +//----------------------------------------------------------------------------- +// Used to connect/disconnect the DLL +//----------------------------------------------------------------------------- +class CTier1TestAppSystem : public CTier1AppSystem< IAppSystem > +{ + typedef CTier1AppSystem< IAppSystem > BaseClass; + +public: + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + return true; + } + + virtual InitReturnVal_t Init() + { + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); + + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + return INIT_OK; + } + + virtual void Shutdown() + { + BaseClass::Shutdown(); + } +}; + +USE_UNITTEST_APPSYSTEM( CTier1TestAppSystem ) diff --git a/unittests/tier1test/tier1test.vpc b/unittests/tier1test/tier1test.vpc new file mode 100644 index 0000000..9ba27aa --- /dev/null +++ b/unittests/tier1test/tier1test.vpc @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// TIER1TEST.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin\unittests" + +$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc" + +$Configuration +{ + $Compiler + { + $PreprocessorDefinitions "$BASE;TIER1TEST_EXPORTS" + } +} + +$Project "tier1test" +{ + $Folder "Source Files" + { + $File "commandbuffertest.cpp" + $File "processtest.cpp" + $File "tier1test.cpp" + $File "utlstringtest.cpp" + } + + $Folder "Header Files" + { + } + + $Folder "Link Libraries" + { + $Lib mathlib + $Lib unitlib + } +} diff --git a/unittests/tier1test/utlstringtest.cpp b/unittests/tier1test/utlstringtest.cpp new file mode 100644 index 0000000..c0fe872 --- /dev/null +++ b/unittests/tier1test/utlstringtest.cpp @@ -0,0 +1,224 @@ +#include "tier0/dbg.h" +#include "unitlib/unitlib.h" +#include "tier1/utlstring.h" + +DEFINE_TESTSUITE( UtlStringTestSuite ) + +static void ConstructorTests() +{ + CUtlString string; + Shipping_Assert( string.Length() == 0 ); + Shipping_Assert( string.IsEmpty() == true ); + Shipping_Assert( string.GetForModify() && string.GetForModify()[ 0 ] == 0 ); + + CUtlString string2( "shiz" ); + Shipping_Assert( string2.Length() == 4 ); + Shipping_Assert( !V_stricmp( string2.Get(), "shiz" ) ); + + CUtlString string3( "thisstringismuchlongerthantwentywholehugecharacters", 20 ); + Shipping_Assert( string3.Length() == 20 ); +} + +static void BasicFunctionalityTests() +{ + CUtlString empty; + empty.SetLength( 10 ); + Assert( empty.Length() == 10 ); + V_memcpy( empty.GetForModify(), "blah", 4 ); + empty.GetForModify()[ 4 ] = 0; + Assert( empty.Length() == 4 ); + Shipping_Assert( !V_stricmp( empty.Get(), "blah" ) ); + + empty.Clear(); + Shipping_Assert( empty.IsEmpty() ); + empty = "blah"; + Shipping_Assert( !empty.IsEmpty() ); + empty.Purge(); + Shipping_Assert( empty.IsEmpty() ); + + empty = "CaMeLcAsE"; + + Shipping_Assert( empty.IsEqual_CaseSensitive( "CaMeLcAsE" ) ); + Shipping_Assert( empty.IsEqual_CaseInsensitive( "camelCASE" ) ); + + CUtlString copy( empty ); + Shipping_Assert( empty == copy ); + empty.ToLower(); + Shipping_Assert( empty != copy ); + + empty.Append( "271" ); + Shipping_Assert( !V_stricmp( empty.Get(), "camelcase271" ) ); + empty.Append( "35123", 3 ); + Shipping_Assert( !V_stricmp( empty.Get(), "camelcase271351" ) ); + empty.Append( 'A' ); + Shipping_Assert( !V_stricmp( empty.Get(), "camelcase271351A" ) ); + + empty.Append( '/' ); + empty.Append( '\\' ); + Shipping_Assert( !V_stricmp( empty.Get(), "camelcase271351A/\\" ) ); + empty.StripTrailingSlash(); + empty.StripTrailingSlash(); + Shipping_Assert( !V_stricmp( empty.Get(), "camelcase271351A" ) ); + + empty = "sometext"; + empty.SetLength( 4 ); + Shipping_Assert( empty.Get()[ 4 ] == '\0' ); // Check for null terminator + Shipping_Assert( empty.Length() == 4 ); + Shipping_Assert( empty == "some" ); +} + +static void TrimAPITests() +{ + CUtlString orig( " testy " ); + CUtlString orig2( "\n \n\ttesty\t\r\n \n\t\r" ); + CUtlString s; + + s = orig; + s.TrimLeft( ' ' ); + Shipping_Assert( !V_stricmp( s.Get(), "testy " ) ); + + s = orig; + s.TrimRight( ' ' ); + Shipping_Assert( !V_stricmp( s.Get(), " testy" ) ); + + s = orig2; + s.TrimLeft(); + s.TrimRight(); + Shipping_Assert( !V_stricmp( s.Get(), "testy" ) ); + + s = orig; + s.Trim( ' ' ); + Shipping_Assert( !V_stricmp( s.Get(), "testy" ) ); + s = orig2; + s.Trim(); + Shipping_Assert( !V_stricmp( s.Get(), "testy" ) ); +} + +static void OperatorAPITests() +{ + CUtlString orig( "base" ); + CUtlString orig2( "different" ); + + // operator = on CUtlString + orig = orig2; + Shipping_Assert( !V_stricmp( orig.Get(), "different" ) ); + // perator = on const char * + orig = "different2"; + Shipping_Assert( !V_stricmp( orig.Get(), "different2" ) ); + + orig = orig2; + // op == + Shipping_Assert( orig == orig2 ); + orig = "base"; + // op != + Shipping_Assert( orig != orig2 ); + + orig += "1"; + Shipping_Assert( !V_stricmp( orig.Get(), "base1" ) ); + orig2 = "2"; + orig += orig2; + Shipping_Assert( !V_stricmp( orig.Get(), "base12" ) ); + orig += '3'; + Shipping_Assert( !V_stricmp( orig.Get(), "base123" ) ); + // integer + orig += 123; + Shipping_Assert( !V_stricmp( orig.Get(), "base123123" ) ); + orig += 1.5f; + Shipping_Assert( !V_stricmp( orig.Get(), "base1231231.5" ) ); + + orig = "1"; + orig2 = "2"; + CUtlString newString = orig + orig2; + Shipping_Assert( !V_stricmp( newString.Get(), "12" ) ); + newString = orig + "3"; + Shipping_Assert( !V_stricmp( newString.Get(), "13" ) ); + newString = orig + 42; + Shipping_Assert( !V_stricmp( newString.Get(), "142" ) ); + + orig = "this is a long string"; + newString = orig.Slice( 4 ); + Shipping_Assert( !V_stricmp( newString.Get(), " is a long string" ) ); + newString = orig.Slice( 5, 10 ); + Shipping_Assert( !V_stricmp( newString.Get(), "is a " ) ); + + newString = orig.Left( 4 ); + Shipping_Assert( !V_stricmp( newString.Get(), "this" ) ); + newString = orig.Right( 6 ); + Shipping_Assert( !V_stricmp( newString.Get(), "string" ) ); + newString = orig.Replace( 's', 'q' ); + Shipping_Assert( !V_stricmp( newString.Get(), "thiq iq a long qtring" ) ); +} + +static void PatternTests() +{ + CUtlString str( "this is a very long pattern of very long things" ); + CUtlString pattern( "this is*" ); + + Shipping_Assert( str.MatchesPattern( pattern ) ); + + pattern = "notpresent"; + Shipping_Assert( !str.MatchesPattern( pattern ) ); +} + +static void FmtStr( CUtlString &str, const char *pFmt, ... ) +{ + va_list argptr; + va_start( argptr, pFmt ); + str.FormatV( pFmt, argptr ); + va_end( argptr ); +} + +static void FormatTests() +{ + CUtlString str; + str.Format( "%s %s %i", "shiz", "baz", 1 ); + Shipping_Assert( !V_stricmp( str.Get(), "shiz baz 1" ) ); + + FmtStr( str, "blah%i", 3 ); + Shipping_Assert( !V_stricmp( str.Get(), "blah3" ) ); +} + +static void FileNameAPITests() +{ + CUtlString path( "c:\\source2\\game\\source2\\somefile.ext" ); + + CUtlString absPath = path.AbsPath(); + Shipping_Assert( absPath == path ); + CUtlString file = path.UnqualifiedFilename(); + Shipping_Assert( !V_stricmp( file.Get(), "somefile.ext" ) ); + CUtlString dir = path.DirName(); + Shipping_Assert( !V_stricmp( dir.Get(), "c:\\source2\\game\\source2" ) ); + dir = dir.DirName(); + Shipping_Assert( !V_stricmp( dir.Get(), "c:\\source2\\game" ) ); + CUtlString baseName = path.StripExtension(); + Shipping_Assert( !V_stricmp( baseName.Get(), "c:\\source2\\game\\source2\\somefile" ) ); + dir = path.StripFilename(); + Shipping_Assert( !V_stricmp( dir.Get(), "c:\\source2\\game\\source2" ) ); + + file = path.GetBaseFilename(); + Shipping_Assert( !V_stricmp( file.Get(), "somefile" ) ); + CUtlString ext = path.GetExtension(); + Shipping_Assert( !V_stricmp( ext.Get(), "ext" ) ); + + absPath = path.PathJoin( dir.Get(), file.Get() ); + Shipping_Assert( !V_stricmp( absPath.Get(), "c:\\source2\\game\\source2\\somefile" ) ); +} + +DEFINE_TESTCASE( UtlStringTest, UtlStringTestSuite ) +{ + Msg( "Running CUtlString tests\n" ); + + ConstructorTests(); + + BasicFunctionalityTests(); + + TrimAPITests(); + + OperatorAPITests(); + + PatternTests(); + + FormatTests(); + + FileNameAPITests(); +}
\ No newline at end of file diff --git a/unittests/tier2test/tier2test.cpp b/unittests/tier2test/tier2test.cpp new file mode 100644 index 0000000..24e072b --- /dev/null +++ b/unittests/tier2test/tier2test.cpp @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for testing of tier2 libraries +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "filesystem.h" +#include "tier2/tier2.h" +#include "mathlib/mathlib.h" + + +//----------------------------------------------------------------------------- +// Used to connect/disconnect the DLL +//----------------------------------------------------------------------------- +class CTier2TestAppSystem : public CTier2AppSystem< IAppSystem > +{ + typedef CTier2AppSystem< IAppSystem > BaseClass; + +public: + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + + if ( !g_pFullFileSystem ) + return false; + return true; + } + + virtual InitReturnVal_t Init() + { + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); + + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + return INIT_OK; + } +}; + +USE_UNITTEST_APPSYSTEM( CTier2TestAppSystem ) diff --git a/unittests/tier2test/tier2test.vpc b/unittests/tier2test/tier2test.vpc new file mode 100644 index 0000000..4560e44 --- /dev/null +++ b/unittests/tier2test/tier2test.vpc @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// TIER2TEST.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin\unittests" + +$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc" + +$Configuration +{ + $Compiler + { + $PreprocessorDefinitions "$BASE;TIER2TEST_EXPORTS" + } +} + +$Project "tier2test" +{ + $Folder "Source Files" + { + $File "tier2test.cpp" + } + + $Folder "Header Files" + { + } + + $Folder "Link Libraries" + { + $Lib mathlib + $Lib unitlib + $Lib bitmap + $Lib tier2 + } +} diff --git a/unittests/tier3test/tier3test.cpp b/unittests/tier3test/tier3test.cpp new file mode 100644 index 0000000..2ccd66d --- /dev/null +++ b/unittests/tier3test/tier3test.cpp @@ -0,0 +1,44 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Unit test program for tier3 level libraries testing +// +// $NoKeywords: $ +//=============================================================================// + +#include "unitlib/unitlib.h" +#include "filesystem.h" +#include "tier3/tier3.h" +#include "mathlib/mathlib.h" + + +//----------------------------------------------------------------------------- +// Used to connect/disconnect the DLL +//----------------------------------------------------------------------------- +class CTier3TestAppSystem : public CTier3AppSystem< IAppSystem > +{ + typedef CTier3AppSystem< IAppSystem > BaseClass; + +public: + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + + if ( !g_pFullFileSystem ) + return false; + return true; + } + + virtual InitReturnVal_t Init() + { + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); + + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + return INIT_OK; + } +}; + +USE_UNITTEST_APPSYSTEM( CTier3TestAppSystem ) diff --git a/unittests/tier3test/tier3test.vpc b/unittests/tier3test/tier3test.vpc new file mode 100644 index 0000000..8cd6d62 --- /dev/null +++ b/unittests/tier3test/tier3test.vpc @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------------- +// TIER3TEST.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin\unittests" + +$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc" + +$Configuration +{ + $Compiler + { + $PreprocessorDefinitions "$BASE;TIER3TEST_EXPORTS" + } +} + +$Project "tier3test" +{ + $Folder "Source Files" + { + $File "tier3test.cpp" + } + + $Folder "Header Files" + { + $File "$SRCDIR\public\movieobjects\dmx_to_vcd.h" + $File "$SRCDIR\public\interpolatortypes.h" + } + + $Folder "Link Libraries" + { + $Lib mathlib + $Lib unitlib + $Lib bitmap + $Lib tier2 + $Lib tier3 + } +} |