forked from 0ad/0ad
Fix line endings of all files in source/ except source/third_party/.
This was SVN commit r18558.
This commit is contained in:
parent
ba25ffef74
commit
bcbf25bfbd
@ -1,2 +1,2 @@
|
||||
@cd ..\..\..\binaries\system
|
||||
@pyrogenesis_dbg.exe -editor -actorviewer -mod=_test.minimal -mod=_test.collada
|
||||
@cd ..\..\..\binaries\system
|
||||
@pyrogenesis_dbg.exe -editor -actorviewer -mod=_test.minimal -mod=_test.collada
|
||||
|
@ -1,95 +1,95 @@
|
||||
/* Copyright (c) 2013 Wildfire Games
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <AvailabilityMacros.h> // MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <string>
|
||||
|
||||
#import "osx_pasteboard.h"
|
||||
|
||||
bool osx_GetStringFromPasteboard(std::string& out)
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
NSString* string = nil;
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
||||
// As of 10.6, pasteboards can hold multiple items
|
||||
if ([pasteboard respondsToSelector: @selector(readObjectsForClasses:)])
|
||||
{
|
||||
NSArray* classes = [NSArray arrayWithObjects:[NSString class], nil];
|
||||
NSDictionary* options = [NSDictionary dictionary];
|
||||
NSArray* copiedItems = [pasteboard readObjectsForClasses:classes options:options];
|
||||
// We only need to support a single item, so grab the first string
|
||||
if (copiedItems != nil && [copiedItems count] > 0)
|
||||
string = [copiedItems objectAtIndex:0];
|
||||
else
|
||||
return false; // No strings found on pasteboard
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif // fallback to 10.5 API
|
||||
// Verify that there is a string available for us
|
||||
NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil];
|
||||
if ([pasteboard availableTypeFromArray:types] != nil)
|
||||
string = [pasteboard stringForType:NSStringPboardType];
|
||||
else
|
||||
return false; // No strings found on pasteboard
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
||||
}
|
||||
#endif
|
||||
|
||||
if (string != nil)
|
||||
out = std::string([string UTF8String]);
|
||||
else
|
||||
return false; // fail
|
||||
|
||||
return true; // success
|
||||
}
|
||||
|
||||
bool osx_SendStringToPasteboard(const std::string& string)
|
||||
{
|
||||
// We're only working with strings, so we don't need to lazily write
|
||||
// anything (otherwise we'd need to set up an owner and data provider)
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
NSString* type;
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
||||
if ([pasteboard respondsToSelector: @selector(clearContents)])
|
||||
{
|
||||
type = NSPasteboardTypeString;
|
||||
[pasteboard clearContents];
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif // fallback to 10.5 API
|
||||
type = NSStringPboardType;
|
||||
NSArray* types = [NSArray arrayWithObjects: type, nil];
|
||||
// Roughly equivalent to clearContents followed by addTypes:owner
|
||||
[pasteboard declareTypes:types owner:nil];
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// May raise a NSPasteboardCommunicationException
|
||||
BOOL ok = [pasteboard setString:[NSString stringWithUTF8String:string.c_str()] forType:type];
|
||||
return ok == YES;
|
||||
}
|
||||
/* Copyright (c) 2013 Wildfire Games
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <AvailabilityMacros.h> // MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <string>
|
||||
|
||||
#import "osx_pasteboard.h"
|
||||
|
||||
bool osx_GetStringFromPasteboard(std::string& out)
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
NSString* string = nil;
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
||||
// As of 10.6, pasteboards can hold multiple items
|
||||
if ([pasteboard respondsToSelector: @selector(readObjectsForClasses:)])
|
||||
{
|
||||
NSArray* classes = [NSArray arrayWithObjects:[NSString class], nil];
|
||||
NSDictionary* options = [NSDictionary dictionary];
|
||||
NSArray* copiedItems = [pasteboard readObjectsForClasses:classes options:options];
|
||||
// We only need to support a single item, so grab the first string
|
||||
if (copiedItems != nil && [copiedItems count] > 0)
|
||||
string = [copiedItems objectAtIndex:0];
|
||||
else
|
||||
return false; // No strings found on pasteboard
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif // fallback to 10.5 API
|
||||
// Verify that there is a string available for us
|
||||
NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil];
|
||||
if ([pasteboard availableTypeFromArray:types] != nil)
|
||||
string = [pasteboard stringForType:NSStringPboardType];
|
||||
else
|
||||
return false; // No strings found on pasteboard
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
||||
}
|
||||
#endif
|
||||
|
||||
if (string != nil)
|
||||
out = std::string([string UTF8String]);
|
||||
else
|
||||
return false; // fail
|
||||
|
||||
return true; // success
|
||||
}
|
||||
|
||||
bool osx_SendStringToPasteboard(const std::string& string)
|
||||
{
|
||||
// We're only working with strings, so we don't need to lazily write
|
||||
// anything (otherwise we'd need to set up an owner and data provider)
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
NSString* type;
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
||||
if ([pasteboard respondsToSelector: @selector(clearContents)])
|
||||
{
|
||||
type = NSPasteboardTypeString;
|
||||
[pasteboard clearContents];
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif // fallback to 10.5 API
|
||||
type = NSStringPboardType;
|
||||
NSArray* types = [NSArray arrayWithObjects: type, nil];
|
||||
// Roughly equivalent to clearContents followed by addTypes:owner
|
||||
[pasteboard declareTypes:types owner:nil];
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// May raise a NSPasteboardCommunicationException
|
||||
BOOL ok = [pasteboard setString:[NSString stringWithUTF8String:string.c_str()] forType:type];
|
||||
return ok == YES;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,87 +1,87 @@
|
||||
@ECHO OFF
|
||||
|
||||
"%systemroot%\system32\cacls.exe" "%systemroot%\system32\config\system" >nul 2>&1
|
||||
IF ERRORLEVEL 1 GOTO relaunch
|
||||
|
||||
REM detect whether OS is 32/64 bit
|
||||
IF "%ProgramW6432%" == "%ProgramFiles%" (
|
||||
SET aken_bits=64
|
||||
) ELSE (
|
||||
SET aken_bits=32
|
||||
)
|
||||
|
||||
IF "%1" == "enabletest" GOTO enabletest
|
||||
IF "%1" == "disabletest" GOTO disabletest
|
||||
IF "%1" == "install" GOTO install
|
||||
IF "%1" == "remove" GOTO remove
|
||||
GOTO usage
|
||||
|
||||
:enabletest
|
||||
bcdedit.exe /set TESTSIGNING ON
|
||||
GOTO end
|
||||
|
||||
:disabletest
|
||||
bcdedit.exe /set TESTSIGNING OFF
|
||||
GOTO end
|
||||
|
||||
:install
|
||||
IF (%2) == () (
|
||||
SET aken_path="%~p0\aken%aken_bits%.sys"
|
||||
) ELSE (
|
||||
echo %2\aken%aken_bits%.sys
|
||||
SET aken_path=%2\aken%aken_bits%.sys
|
||||
)
|
||||
echo %aken_path%
|
||||
IF NOT EXIST %aken_path% GOTO notfound
|
||||
sc create Aken DisplayName= Aken type= kernel start= auto binpath= %aken_path%
|
||||
REM error= normal is default
|
||||
IF ERRORLEVEL 1 GOTO failed
|
||||
sc start Aken
|
||||
IF ERRORLEVEL 1 GOTO failed
|
||||
ECHO Success!
|
||||
GOTO end
|
||||
|
||||
:remove
|
||||
sc stop Aken
|
||||
sc delete Aken
|
||||
IF ERRORLEVEL 1 GOTO failed
|
||||
ECHO Success! (The previous line should read: [SC] DeleteService SUCCESS)
|
||||
GOTO end
|
||||
|
||||
:usage
|
||||
ECHO To install the driver, please first enable test mode:
|
||||
ECHO %0 enabletest
|
||||
ECHO (This is necessary because Vista/Win7 x64 require signing with
|
||||
ECHO a Microsoft "cross certificate". The Fraunhofer code signing certificate
|
||||
ECHO is not enough, even though its chain of trust is impeccable.
|
||||
ECHO Going the WHQL route, perhaps as an "unclassified" driver, might work.
|
||||
ECHO see http://www.freeotfe.org/docs/Main/impact_of_kernel_driver_signing.htm )
|
||||
ECHO Then reboot (!) and install the driver:
|
||||
ECHO %0 install ["path_to_directory_containing_aken*.sys"]
|
||||
ECHO (If no path is given, we will use the directory of this batch file)
|
||||
ECHO To remove the driver and disable test mode, execute the following:
|
||||
ECHO %0 remove
|
||||
ECHO %0 disabletest
|
||||
PAUSE
|
||||
GOTO end
|
||||
|
||||
:relaunch
|
||||
SET aken_vbs="%temp%\aken_run.vbs"
|
||||
ECHO Set UAC = CreateObject^("Shell.Application"^) > %aken_vbs%
|
||||
ECHO UAC.ShellExecute "cmd.exe", "/k %~s0 %1 %2", "", "runas", 1 >> %aken_vbs%
|
||||
ECHO "To re-run this batch file as admin, we have created %aken_vbs% with the following contents:"
|
||||
type %aken_vbs%
|
||||
PAUSE
|
||||
cscript //Nologo %aken_vbs%
|
||||
DEL %aken_vbs%
|
||||
GOTO end
|
||||
|
||||
:notfound
|
||||
ECHO Driver not found at specified path (%aken_path%)
|
||||
GOTO end
|
||||
|
||||
:failed
|
||||
ECHO Something went wrong -- see previous line
|
||||
GOTO end
|
||||
|
||||
@ECHO OFF
|
||||
|
||||
"%systemroot%\system32\cacls.exe" "%systemroot%\system32\config\system" >nul 2>&1
|
||||
IF ERRORLEVEL 1 GOTO relaunch
|
||||
|
||||
REM detect whether OS is 32/64 bit
|
||||
IF "%ProgramW6432%" == "%ProgramFiles%" (
|
||||
SET aken_bits=64
|
||||
) ELSE (
|
||||
SET aken_bits=32
|
||||
)
|
||||
|
||||
IF "%1" == "enabletest" GOTO enabletest
|
||||
IF "%1" == "disabletest" GOTO disabletest
|
||||
IF "%1" == "install" GOTO install
|
||||
IF "%1" == "remove" GOTO remove
|
||||
GOTO usage
|
||||
|
||||
:enabletest
|
||||
bcdedit.exe /set TESTSIGNING ON
|
||||
GOTO end
|
||||
|
||||
:disabletest
|
||||
bcdedit.exe /set TESTSIGNING OFF
|
||||
GOTO end
|
||||
|
||||
:install
|
||||
IF (%2) == () (
|
||||
SET aken_path="%~p0\aken%aken_bits%.sys"
|
||||
) ELSE (
|
||||
echo %2\aken%aken_bits%.sys
|
||||
SET aken_path=%2\aken%aken_bits%.sys
|
||||
)
|
||||
echo %aken_path%
|
||||
IF NOT EXIST %aken_path% GOTO notfound
|
||||
sc create Aken DisplayName= Aken type= kernel start= auto binpath= %aken_path%
|
||||
REM error= normal is default
|
||||
IF ERRORLEVEL 1 GOTO failed
|
||||
sc start Aken
|
||||
IF ERRORLEVEL 1 GOTO failed
|
||||
ECHO Success!
|
||||
GOTO end
|
||||
|
||||
:remove
|
||||
sc stop Aken
|
||||
sc delete Aken
|
||||
IF ERRORLEVEL 1 GOTO failed
|
||||
ECHO Success! (The previous line should read: [SC] DeleteService SUCCESS)
|
||||
GOTO end
|
||||
|
||||
:usage
|
||||
ECHO To install the driver, please first enable test mode:
|
||||
ECHO %0 enabletest
|
||||
ECHO (This is necessary because Vista/Win7 x64 require signing with
|
||||
ECHO a Microsoft "cross certificate". The Fraunhofer code signing certificate
|
||||
ECHO is not enough, even though its chain of trust is impeccable.
|
||||
ECHO Going the WHQL route, perhaps as an "unclassified" driver, might work.
|
||||
ECHO see http://www.freeotfe.org/docs/Main/impact_of_kernel_driver_signing.htm )
|
||||
ECHO Then reboot (!) and install the driver:
|
||||
ECHO %0 install ["path_to_directory_containing_aken*.sys"]
|
||||
ECHO (If no path is given, we will use the directory of this batch file)
|
||||
ECHO To remove the driver and disable test mode, execute the following:
|
||||
ECHO %0 remove
|
||||
ECHO %0 disabletest
|
||||
PAUSE
|
||||
GOTO end
|
||||
|
||||
:relaunch
|
||||
SET aken_vbs="%temp%\aken_run.vbs"
|
||||
ECHO Set UAC = CreateObject^("Shell.Application"^) > %aken_vbs%
|
||||
ECHO UAC.ShellExecute "cmd.exe", "/k %~s0 %1 %2", "", "runas", 1 >> %aken_vbs%
|
||||
ECHO "To re-run this batch file as admin, we have created %aken_vbs% with the following contents:"
|
||||
type %aken_vbs%
|
||||
PAUSE
|
||||
cscript //Nologo %aken_vbs%
|
||||
DEL %aken_vbs%
|
||||
GOTO end
|
||||
|
||||
:notfound
|
||||
ECHO Driver not found at specified path (%aken_path%)
|
||||
GOTO end
|
||||
|
||||
:failed
|
||||
ECHO Something went wrong -- see previous line
|
||||
GOTO end
|
||||
|
||||
:end
|
@ -1,32 +1,32 @@
|
||||
@echo off
|
||||
REM ensure header is up to date (simpler than setting include path)
|
||||
copy ..\..\..\..\..\include\lib\sysdep\os\win\aken\aken.h
|
||||
|
||||
cmd /c build_single.bat chk x64
|
||||
cmd /c build_single.bat fre x64
|
||||
cmd /c build_single.bat chk x86
|
||||
REM must come last because each build_single.bat deletes aken.sys,
|
||||
REM and that is the final output name of this step
|
||||
cmd /c build_single.bat fre x86
|
||||
|
||||
cd amd64
|
||||
copy /y aken64*.pdb ..\..\..\..\..\..\..\bin\x64
|
||||
copy /y aken64*.sys ..\..\..\..\..\..\..\bin\x64
|
||||
cd ..
|
||||
|
||||
cd i386
|
||||
copy /y aken*.pdb ..\..\..\..\..\..\..\bin\Win32
|
||||
copy /y aken*.sys ..\..\..\..\..\..\..\bin\Win32
|
||||
cd ..
|
||||
|
||||
echo outputs copied to bin directory; will delete ALL output files after pressing a key
|
||||
pause
|
||||
if exist amd64 (rmdir /S /Q amd64)
|
||||
if exist i386 (rmdir /S /Q i386)
|
||||
if exist objchk_wnet_amd64 (rmdir /S /Q objchk_wnet_amd64)
|
||||
if exist objfre_wnet_amd64 (rmdir /S /Q objfre_wnet_amd64)
|
||||
if exist objchk_wnet_x86 (rmdir /S /Q objchk_wnet_x86)
|
||||
if exist objfre_wnet_x86 (rmdir /S /Q objfre_wnet_x86)
|
||||
if exist *.log (del /Q *.log)
|
||||
if exist *.err (del /Q *.err)
|
||||
@echo off
|
||||
REM ensure header is up to date (simpler than setting include path)
|
||||
copy ..\..\..\..\..\include\lib\sysdep\os\win\aken\aken.h
|
||||
|
||||
cmd /c build_single.bat chk x64
|
||||
cmd /c build_single.bat fre x64
|
||||
cmd /c build_single.bat chk x86
|
||||
REM must come last because each build_single.bat deletes aken.sys,
|
||||
REM and that is the final output name of this step
|
||||
cmd /c build_single.bat fre x86
|
||||
|
||||
cd amd64
|
||||
copy /y aken64*.pdb ..\..\..\..\..\..\..\bin\x64
|
||||
copy /y aken64*.sys ..\..\..\..\..\..\..\bin\x64
|
||||
cd ..
|
||||
|
||||
cd i386
|
||||
copy /y aken*.pdb ..\..\..\..\..\..\..\bin\Win32
|
||||
copy /y aken*.sys ..\..\..\..\..\..\..\bin\Win32
|
||||
cd ..
|
||||
|
||||
echo outputs copied to bin directory; will delete ALL output files after pressing a key
|
||||
pause
|
||||
if exist amd64 (rmdir /S /Q amd64)
|
||||
if exist i386 (rmdir /S /Q i386)
|
||||
if exist objchk_wnet_amd64 (rmdir /S /Q objchk_wnet_amd64)
|
||||
if exist objfre_wnet_amd64 (rmdir /S /Q objfre_wnet_amd64)
|
||||
if exist objchk_wnet_x86 (rmdir /S /Q objchk_wnet_x86)
|
||||
if exist objfre_wnet_x86 (rmdir /S /Q objfre_wnet_x86)
|
||||
if exist *.log (del /Q *.log)
|
||||
if exist *.err (del /Q *.err)
|
||||
if exist *.wrn (del /Q *.wrn)
|
@ -1,67 +1,67 @@
|
||||
@echo off
|
||||
REM build a single configuration ({chk,fre} x {x64,x64})
|
||||
REM (must be in a separate file to allow invoking in a new cmd - otherwise,
|
||||
REM setenv complains that the environment have already been set)
|
||||
REM arguments: chk|fre x64|x86
|
||||
if %1==chk (goto configOK)
|
||||
if %1==fre (goto configOK)
|
||||
echo first parameter must be either chk or fre
|
||||
goto :eof
|
||||
:configOK
|
||||
if %2==x64 (goto archOK)
|
||||
if %2==x86 (goto archOK)
|
||||
echo second parameter must be either x64 or x64
|
||||
goto :eof
|
||||
:archOK
|
||||
|
||||
|
||||
call C:\WinDDK\7600.16385.1\bin\setenv.bat C:\WinDDK\7600.16385.1\ %1 %2 WNET
|
||||
e:
|
||||
cd \FOM_Work\Programmierung\lowlevel\src\sysdep\os\win\aken
|
||||
|
||||
|
||||
REM delete outputs to ensure they get rebuilt
|
||||
if %2==x64 (goto delete64) else (goto delete32)
|
||||
|
||||
:delete64
|
||||
if not exist amd64 (goto deleteEnd)
|
||||
cd amd64
|
||||
if exist aken.sys (del /Q aken.sys)
|
||||
if exist aken.pdb (del /Q aken.pdb)
|
||||
cd ..
|
||||
goto deleteEnd
|
||||
|
||||
:delete32
|
||||
if not exist i386 (goto deleteEnd)
|
||||
cd i386
|
||||
if exist aken.sys (del /Q aken.sys)
|
||||
if exist aken.pdb (del /Q aken.pdb)
|
||||
cd ..
|
||||
goto deleteEnd
|
||||
|
||||
:deleteEnd
|
||||
|
||||
|
||||
build
|
||||
|
||||
|
||||
REM rename outputs in preparation for build_all's copying them to the binaries directories
|
||||
if %2==x64 (goto rename64) else (goto rename32)
|
||||
|
||||
:rename64
|
||||
if not exist amd64 (goto renameEnd)
|
||||
cd amd64
|
||||
if %1==chk (ren aken.pdb aken64d.pdb) else (ren aken.pdb aken64.pdb)
|
||||
if %1==chk (ren aken.sys aken64d.sys) else (ren aken.sys aken64.sys)
|
||||
cd ..
|
||||
goto renameEnd
|
||||
|
||||
:rename32
|
||||
if not exist i386 (goto renameEnd)
|
||||
cd i386
|
||||
if %1==chk (ren aken.pdb akend.pdb)
|
||||
if %1==chk (ren aken.sys akend.sys)
|
||||
cd ..
|
||||
goto renameEnd
|
||||
|
||||
:renameEnd
|
||||
@echo off
|
||||
REM build a single configuration ({chk,fre} x {x64,x64})
|
||||
REM (must be in a separate file to allow invoking in a new cmd - otherwise,
|
||||
REM setenv complains that the environment have already been set)
|
||||
REM arguments: chk|fre x64|x86
|
||||
if %1==chk (goto configOK)
|
||||
if %1==fre (goto configOK)
|
||||
echo first parameter must be either chk or fre
|
||||
goto :eof
|
||||
:configOK
|
||||
if %2==x64 (goto archOK)
|
||||
if %2==x86 (goto archOK)
|
||||
echo second parameter must be either x64 or x64
|
||||
goto :eof
|
||||
:archOK
|
||||
|
||||
|
||||
call C:\WinDDK\7600.16385.1\bin\setenv.bat C:\WinDDK\7600.16385.1\ %1 %2 WNET
|
||||
e:
|
||||
cd \FOM_Work\Programmierung\lowlevel\src\sysdep\os\win\aken
|
||||
|
||||
|
||||
REM delete outputs to ensure they get rebuilt
|
||||
if %2==x64 (goto delete64) else (goto delete32)
|
||||
|
||||
:delete64
|
||||
if not exist amd64 (goto deleteEnd)
|
||||
cd amd64
|
||||
if exist aken.sys (del /Q aken.sys)
|
||||
if exist aken.pdb (del /Q aken.pdb)
|
||||
cd ..
|
||||
goto deleteEnd
|
||||
|
||||
:delete32
|
||||
if not exist i386 (goto deleteEnd)
|
||||
cd i386
|
||||
if exist aken.sys (del /Q aken.sys)
|
||||
if exist aken.pdb (del /Q aken.pdb)
|
||||
cd ..
|
||||
goto deleteEnd
|
||||
|
||||
:deleteEnd
|
||||
|
||||
|
||||
build
|
||||
|
||||
|
||||
REM rename outputs in preparation for build_all's copying them to the binaries directories
|
||||
if %2==x64 (goto rename64) else (goto rename32)
|
||||
|
||||
:rename64
|
||||
if not exist amd64 (goto renameEnd)
|
||||
cd amd64
|
||||
if %1==chk (ren aken.pdb aken64d.pdb) else (ren aken.pdb aken64.pdb)
|
||||
if %1==chk (ren aken.sys aken64d.sys) else (ren aken.sys aken64.sys)
|
||||
cd ..
|
||||
goto renameEnd
|
||||
|
||||
:rename32
|
||||
if not exist i386 (goto renameEnd)
|
||||
cd i386
|
||||
if %1==chk (ren aken.pdb akend.pdb)
|
||||
if %1==chk (ren aken.sys akend.sys)
|
||||
cd ..
|
||||
goto renameEnd
|
||||
|
||||
:renameEnd
|
||||
|
@ -1,7 +1,7 @@
|
||||
#
|
||||
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
|
||||
# file to this component. This file merely indirects to the real make file
|
||||
# that is shared by all the driver components of the Windows NT DDK
|
||||
#
|
||||
|
||||
!INCLUDE $(NTMAKEENV)\makefile.def
|
||||
#
|
||||
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
|
||||
# file to this component. This file merely indirects to the real make file
|
||||
# that is shared by all the driver components of the Windows NT DDK
|
||||
#
|
||||
|
||||
!INCLUDE $(NTMAKEENV)\makefile.def
|
||||
|
@ -1,5 +1,5 @@
|
||||
TARGETNAME=aken
|
||||
TARGETPATH=.
|
||||
TARGETTYPE=DRIVER
|
||||
|
||||
SOURCES=aken.c
|
||||
TARGETNAME=aken
|
||||
TARGETPATH=.
|
||||
TARGETTYPE=DRIVER
|
||||
|
||||
SOURCES=aken.c
|
||||
|
@ -1 +1 @@
|
||||
IDI_ICON1 ICON "..\\AtlasUI\\Misc\\Graphics\\ActorEditor.ico"
|
||||
IDI_ICON1 ICON "..\\AtlasUI\\Misc\\Graphics\\ActorEditor.ico"
|
||||
|
@ -1 +1 @@
|
||||
IDI_ICON1 ICON "..\\AtlasUI\\Misc\\Graphics\\$$PROJECT_NAME$$.ico"
|
||||
IDI_ICON1 ICON "..\\AtlasUI\\Misc\\Graphics\\$$PROJECT_NAME$$.ico"
|
||||
|
@ -1,22 +1,22 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my @files = qw( .cpp .rc );
|
||||
|
||||
my @progs = (
|
||||
{
|
||||
PROJECT_NAME => "ActorEditor",
|
||||
WINDOW_NAME => "ActorEditor",
|
||||
},
|
||||
);
|
||||
|
||||
for my $p (@progs) {
|
||||
for my $f (@files) {
|
||||
open IN, "<", "_template$f" or die "Error opening _template$f: $!";
|
||||
open OUT, ">", "$p->{PROJECT_NAME}$f" or die "Error opening $p->{PROJECT_NAME}$f: $!";
|
||||
while (<IN>) {
|
||||
s/\$\$([A-Z_]+)\$\$/ $p->{$1} /eg;
|
||||
print OUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my @files = qw( .cpp .rc );
|
||||
|
||||
my @progs = (
|
||||
{
|
||||
PROJECT_NAME => "ActorEditor",
|
||||
WINDOW_NAME => "ActorEditor",
|
||||
},
|
||||
);
|
||||
|
||||
for my $p (@progs) {
|
||||
for my $f (@files) {
|
||||
open IN, "<", "_template$f" or die "Error opening _template$f: $!";
|
||||
open OUT, ">", "$p->{PROJECT_NAME}$f" or die "Error opening $p->{PROJECT_NAME}$f: $!";
|
||||
while (<IN>) {
|
||||
s/\$\$([A-Z_]+)\$\$/ $p->{$1} /eg;
|
||||
print OUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
wxVirtualDirTreeCtrl (v1.0b) from http://www.solidsteel.nl/jorg/components/virtualdirtreectrl/wxVirtualDirTreeCtrl.php
|
||||
|
||||
wxVirtualDirTreeCtrl (v1.0b) from http://www.solidsteel.nl/jorg/components/virtualdirtreectrl/wxVirtualDirTreeCtrl.php
|
||||
|
||||
"wxVirtualDirTreeCtrl is freeware and distributed under the wxWidgets license."
|
@ -1,36 +1,36 @@
|
||||
/* XPM */
|
||||
static const char *xpm_file[] = {
|
||||
"16 16 16 2",
|
||||
"00 c black",
|
||||
"01 c #848484",
|
||||
"02 c #D6D6CE",
|
||||
"03 c gray100",
|
||||
"04 c none",
|
||||
"05 c gray100",
|
||||
"06 c gray100",
|
||||
"07 c gray100",
|
||||
"08 c gray100",
|
||||
"09 c gray100",
|
||||
"10 c gray100",
|
||||
"11 c gray100",
|
||||
"12 c gray100",
|
||||
"13 c gray100",
|
||||
"14 c gray100",
|
||||
"15 c gray100",
|
||||
"04040404040404040404040404040404",
|
||||
"04040101010101010101010104040404",
|
||||
"04040103030303030303030001040404",
|
||||
"04040103030303030303030002010404",
|
||||
"04040103030000000000030000000004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040103030000000000000003030004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040103030000000000000003030004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040103030000000000000003030004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040103030000000000000003030004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040000000000000000000000000004"
|
||||
};
|
||||
/* XPM */
|
||||
static const char *xpm_file[] = {
|
||||
"16 16 16 2",
|
||||
"00 c black",
|
||||
"01 c #848484",
|
||||
"02 c #D6D6CE",
|
||||
"03 c gray100",
|
||||
"04 c none",
|
||||
"05 c gray100",
|
||||
"06 c gray100",
|
||||
"07 c gray100",
|
||||
"08 c gray100",
|
||||
"09 c gray100",
|
||||
"10 c gray100",
|
||||
"11 c gray100",
|
||||
"12 c gray100",
|
||||
"13 c gray100",
|
||||
"14 c gray100",
|
||||
"15 c gray100",
|
||||
"04040404040404040404040404040404",
|
||||
"04040101010101010101010104040404",
|
||||
"04040103030303030303030001040404",
|
||||
"04040103030303030303030002010404",
|
||||
"04040103030000000000030000000004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040103030000000000000003030004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040103030000000000000003030004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040103030000000000000003030004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040103030000000000000003030004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040103030303030303030303030004",
|
||||
"04040000000000000000000000000004"
|
||||
};
|
||||
|
@ -1,36 +1,36 @@
|
||||
/* XPM */
|
||||
static const char *xpm_folder[] = {
|
||||
"16 16 16 2",
|
||||
"00 c #A06B04",
|
||||
"01 c #B17B14",
|
||||
"02 c #C18C25",
|
||||
"03 c #CE9831",
|
||||
"04 c gray29",
|
||||
"05 c #777777",
|
||||
"06 c gray55",
|
||||
"07 c none",
|
||||
"08 c #ECB94F",
|
||||
"09 c #FFE178",
|
||||
"10 c #FFF388",
|
||||
"11 c #FFFB98",
|
||||
"12 c #CECECE",
|
||||
"13 c #DADADA",
|
||||
"14 c gray97",
|
||||
"15 c gray100",
|
||||
"07070707070707070707070707070707",
|
||||
"07070303030313140707070707070707",
|
||||
"07031515151502121407070707070707",
|
||||
"03151111111115020202010101131407",
|
||||
"03111010101010151515151501061307",
|
||||
"03100902020202020202020201010113",
|
||||
"03090215151515151515151509150006",
|
||||
"02090311111111111111111108110005",
|
||||
"02090311111111111111111108110005",
|
||||
"02090211101010101010101008110005",
|
||||
"02090211090909090909090908110005",
|
||||
"02090211090909090909090903110005",
|
||||
"13010101010101000000000000000406",
|
||||
"14120605050505050505050505050612",
|
||||
"07141313131313131313131313131314",
|
||||
"07070707070707070707070707070707"
|
||||
};
|
||||
/* XPM */
|
||||
static const char *xpm_folder[] = {
|
||||
"16 16 16 2",
|
||||
"00 c #A06B04",
|
||||
"01 c #B17B14",
|
||||
"02 c #C18C25",
|
||||
"03 c #CE9831",
|
||||
"04 c gray29",
|
||||
"05 c #777777",
|
||||
"06 c gray55",
|
||||
"07 c none",
|
||||
"08 c #ECB94F",
|
||||
"09 c #FFE178",
|
||||
"10 c #FFF388",
|
||||
"11 c #FFFB98",
|
||||
"12 c #CECECE",
|
||||
"13 c #DADADA",
|
||||
"14 c gray97",
|
||||
"15 c gray100",
|
||||
"07070707070707070707070707070707",
|
||||
"07070303030313140707070707070707",
|
||||
"07031515151502121407070707070707",
|
||||
"03151111111115020202010101131407",
|
||||
"03111010101010151515151501061307",
|
||||
"03100902020202020202020201010113",
|
||||
"03090215151515151515151509150006",
|
||||
"02090311111111111111111108110005",
|
||||
"02090311111111111111111108110005",
|
||||
"02090211101010101010101008110005",
|
||||
"02090211090909090909090908110005",
|
||||
"02090211090909090909090903110005",
|
||||
"13010101010101000000000000000406",
|
||||
"14120605050505050505050505050612",
|
||||
"07141313131313131313131313131314",
|
||||
"07070707070707070707070707070707"
|
||||
};
|
||||
|
@ -1,36 +1,36 @@
|
||||
/* XPM */
|
||||
static const char *xpm_root[] = {
|
||||
"16 16 16 2",
|
||||
"00 c #976911",
|
||||
"01 c gray42",
|
||||
"02 c #C18B24",
|
||||
"03 c #E3B552",
|
||||
"04 c #6482B3",
|
||||
"05 c #8E9CAA",
|
||||
"06 c #FFEE86",
|
||||
"07 c gray74",
|
||||
"08 c #68BDFF",
|
||||
"09 c #B9CDE6",
|
||||
"10 c #D2D2D2",
|
||||
"11 c #D8E9F1",
|
||||
"12 c #E7F7FF",
|
||||
"13 c #F3F7FB",
|
||||
"14 c #F7FFFF",
|
||||
"15 c none",
|
||||
"15151515040404040404040811131515",
|
||||
"15151515041313131313130808101315",
|
||||
"15150202041309090909130808081013",
|
||||
"15021313041313131313131111040111",
|
||||
"02130606041209090909090912040110",
|
||||
"02060606041212121212121212040110",
|
||||
"02060202040707070707070707040207",
|
||||
"02060213111313131313131313110001",
|
||||
"02060206071109090909090911070001",
|
||||
"02030206071111111111111111070001",
|
||||
"02030206071111111111111111070001",
|
||||
"02030206070707070707070707070001",
|
||||
"02030206060303030303030303060001",
|
||||
"11020202020000000000000000000101",
|
||||
"13100101010101010101010101010110",
|
||||
"15131110101010101010101010101113"
|
||||
};
|
||||
/* XPM */
|
||||
static const char *xpm_root[] = {
|
||||
"16 16 16 2",
|
||||
"00 c #976911",
|
||||
"01 c gray42",
|
||||
"02 c #C18B24",
|
||||
"03 c #E3B552",
|
||||
"04 c #6482B3",
|
||||
"05 c #8E9CAA",
|
||||
"06 c #FFEE86",
|
||||
"07 c gray74",
|
||||
"08 c #68BDFF",
|
||||
"09 c #B9CDE6",
|
||||
"10 c #D2D2D2",
|
||||
"11 c #D8E9F1",
|
||||
"12 c #E7F7FF",
|
||||
"13 c #F3F7FB",
|
||||
"14 c #F7FFFF",
|
||||
"15 c none",
|
||||
"15151515040404040404040811131515",
|
||||
"15151515041313131313130808101315",
|
||||
"15150202041309090909130808081013",
|
||||
"15021313041313131313131111040111",
|
||||
"02130606041209090909090912040110",
|
||||
"02060606041212121212121212040110",
|
||||
"02060202040707070707070707040207",
|
||||
"02060213111313131313131313110001",
|
||||
"02060206071109090909090911070001",
|
||||
"02030206071111111111111111070001",
|
||||
"02030206071111111111111111070001",
|
||||
"02030206070707070707070707070001",
|
||||
"02030206060303030303030303060001",
|
||||
"11020202020000000000000000000101",
|
||||
"13100101010101010101010101010110",
|
||||
"15131110101010101010101010101113"
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
ICON_ActorEditor ICON "Graphics\\ActorEditor.ico"
|
||||
ICON_ArchiveViewer ICON "Graphics\\ArchiveViewer.ico"
|
||||
ICON_FileConverter ICON "Graphics\\FileConverter.ico"
|
||||
ICON_ScenarioEditor ICON "Graphics\\ScenarioEditor.ico"
|
||||
|
||||
#define wxUSE_NO_MANIFEST 1
|
||||
#include "wx/msw/wx.rc"
|
||||
ICON_ActorEditor ICON "Graphics\\ActorEditor.ico"
|
||||
ICON_ArchiveViewer ICON "Graphics\\ArchiveViewer.ico"
|
||||
ICON_FileConverter ICON "Graphics\\FileConverter.ico"
|
||||
ICON_ScenarioEditor ICON "Graphics\\ScenarioEditor.ico"
|
||||
|
||||
#define wxUSE_NO_MANIFEST 1
|
||||
#include "wx/msw/wx.rc"
|
||||
|
@ -1,93 +1,93 @@
|
||||
wxWidgets:
|
||||
* alt+f with notebook tab focussed
|
||||
* wxLogTrace "%s" wxGetMessage (msw/window.cpp)
|
||||
|
||||
==============================
|
||||
|
||||
Colour tester:
|
||||
|
||||
==============================
|
||||
|
||||
Actor editor:
|
||||
|
||||
* Fix new actor fields
|
||||
|
||||
|
||||
==============================
|
||||
|
||||
General and/or unsorted miscellany:
|
||||
|
||||
* Regression testing
|
||||
|
||||
* Open actors from prop-actor selection
|
||||
|
||||
* Make import undo work with multi-control windows, and update the title bar
|
||||
|
||||
===
|
||||
|
||||
* Better input controls (=> export nicely, support undo, etc)
|
||||
|
||||
* Help (tooltips, etc)
|
||||
|
||||
* More efficient Datafile::ReadList (don't read from disk every time)
|
||||
|
||||
* Version number
|
||||
|
||||
* Better colouring in test_dude.xml, where some variants have no data
|
||||
|
||||
* Tab to move between fields
|
||||
|
||||
===
|
||||
|
||||
* Test/fix when running with large fonts, or weird XP styles
|
||||
|
||||
* Better copy and paste (e.g. between multiple instances of the program,
|
||||
and paste XML into other text-editing programs
|
||||
|
||||
* Save on exit: don't ask if no changes
|
||||
|
||||
* Browse for meshes/actors/etc, in a more nice/correct/unbuggy way
|
||||
|
||||
* Window size memory
|
||||
|
||||
* Column width memory
|
||||
|
||||
* Allow reset memory
|
||||
|
||||
* Input validation?
|
||||
|
||||
* Browse for meshes/actors/etc, with mods
|
||||
|
||||
* Customised AtObj->string conversion
|
||||
|
||||
* Undo in text-editing boxes
|
||||
|
||||
* AtlasObjectXML error handling
|
||||
|
||||
* Use standard wxWidgets 2.5.4 release
|
||||
|
||||
* Fix Escape in combo boxes inside dialogs
|
||||
|
||||
* Make wxFileHistory work when not at the very end of a menu
|
||||
|
||||
===
|
||||
|
||||
* Document lots
|
||||
|
||||
* wxListItemAttr* OnGetItemAttr(long item) >>>const<<< - wx documentation wrong?
|
||||
|
||||
* Better column widths / window sizes
|
||||
|
||||
* Don't create a row when editing a blank one then removing focus without typing anything
|
||||
|
||||
======
|
||||
|
||||
Done: (newest at top)
|
||||
|
||||
* Display DDS info (compression, size)
|
||||
* Copy and paste
|
||||
* 'Create entity' button (take name, parent)
|
||||
* Correct undo menu entry when selecting 'New' (so it's not 'Import')
|
||||
* MRU file list
|
||||
* 'New' menu item
|
||||
* Import/export filter, for validation(?) and for handling attributes
|
||||
wxWidgets:
|
||||
* alt+f with notebook tab focussed
|
||||
* wxLogTrace "%s" wxGetMessage (msw/window.cpp)
|
||||
|
||||
==============================
|
||||
|
||||
Colour tester:
|
||||
|
||||
==============================
|
||||
|
||||
Actor editor:
|
||||
|
||||
* Fix new actor fields
|
||||
|
||||
|
||||
==============================
|
||||
|
||||
General and/or unsorted miscellany:
|
||||
|
||||
* Regression testing
|
||||
|
||||
* Open actors from prop-actor selection
|
||||
|
||||
* Make import undo work with multi-control windows, and update the title bar
|
||||
|
||||
===
|
||||
|
||||
* Better input controls (=> export nicely, support undo, etc)
|
||||
|
||||
* Help (tooltips, etc)
|
||||
|
||||
* More efficient Datafile::ReadList (don't read from disk every time)
|
||||
|
||||
* Version number
|
||||
|
||||
* Better colouring in test_dude.xml, where some variants have no data
|
||||
|
||||
* Tab to move between fields
|
||||
|
||||
===
|
||||
|
||||
* Test/fix when running with large fonts, or weird XP styles
|
||||
|
||||
* Better copy and paste (e.g. between multiple instances of the program,
|
||||
and paste XML into other text-editing programs
|
||||
|
||||
* Save on exit: don't ask if no changes
|
||||
|
||||
* Browse for meshes/actors/etc, in a more nice/correct/unbuggy way
|
||||
|
||||
* Window size memory
|
||||
|
||||
* Column width memory
|
||||
|
||||
* Allow reset memory
|
||||
|
||||
* Input validation?
|
||||
|
||||
* Browse for meshes/actors/etc, with mods
|
||||
|
||||
* Customised AtObj->string conversion
|
||||
|
||||
* Undo in text-editing boxes
|
||||
|
||||
* AtlasObjectXML error handling
|
||||
|
||||
* Use standard wxWidgets 2.5.4 release
|
||||
|
||||
* Fix Escape in combo boxes inside dialogs
|
||||
|
||||
* Make wxFileHistory work when not at the very end of a menu
|
||||
|
||||
===
|
||||
|
||||
* Document lots
|
||||
|
||||
* wxListItemAttr* OnGetItemAttr(long item) >>>const<<< - wx documentation wrong?
|
||||
|
||||
* Better column widths / window sizes
|
||||
|
||||
* Don't create a row when editing a blank one then removing focus without typing anything
|
||||
|
||||
======
|
||||
|
||||
Done: (newest at top)
|
||||
|
||||
* Display DDS info (compression, size)
|
||||
* Copy and paste
|
||||
* 'Create entity' button (take name, parent)
|
||||
* Correct undo menu entry when selecting 'New' (so it's not 'Import')
|
||||
* MRU file list
|
||||
* 'New' menu item
|
||||
* Import/export filter, for validation(?) and for handling attributes
|
||||
|
@ -1,88 +1,88 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Find;
|
||||
|
||||
my $dir = '../../../binaries/data/mods/official/entities';
|
||||
my @xml;
|
||||
find({wanted=>sub{
|
||||
push @xml, $_ if /\.xml$/;
|
||||
}, no_chdir=>1}, $dir);
|
||||
s~\Q$dir/~~ for @xml;
|
||||
|
||||
my %nodes;
|
||||
|
||||
for my $f (@xml) {
|
||||
|
||||
$f =~ m~(?:.*/|^)(.*)\.xml~ or die "invalid filename $f";
|
||||
my $name = $1;
|
||||
|
||||
open I, "$dir/$f" or die "error opening $dir/$f: $!";
|
||||
my $data = do { local $/; <I> };
|
||||
close I;
|
||||
|
||||
my $parent;
|
||||
$parent = $1 if $data =~ /Parent="(.*?)"/;
|
||||
|
||||
my ($upgrade, $rank);
|
||||
$upgrade = $1 if $data =~ /<Entity>\s*(.*?)\s*</s;
|
||||
$rank = $1 if $data =~ /Up.*rank="(.*?)"/s;
|
||||
|
||||
my $actor;
|
||||
$actor = $1 if $data =~ /<Actor>\s*(.*?)\s*</;
|
||||
|
||||
undef $upgrade unless defined $upgrade and length $upgrade;
|
||||
|
||||
$nodes{$parent} ||= {} if defined $parent;
|
||||
$nodes{$upgrade} ||= {} if defined $upgrade;
|
||||
$nodes{$name} = { def=>1, parent=>$parent, upgrade=>[$upgrade, $rank], actor=>$actor };
|
||||
}
|
||||
|
||||
open O, ">", "entities.dot" or die $!;
|
||||
|
||||
print O <<EOF;
|
||||
digraph g
|
||||
{
|
||||
graph [nodesep=.1];
|
||||
edge [fontname=ArialN fontsize=8];
|
||||
EOF
|
||||
|
||||
print O " /* entities without actors */
|
||||
node [fontname=ArialN fontsize=10 shape=ellipse];
|
||||
";
|
||||
for (sort keys %nodes) {
|
||||
print O qq{ "$_";\n} if keys %{$nodes{$_}} and not defined $nodes{$_}{actor};
|
||||
}
|
||||
|
||||
print O " /* entities with actors */
|
||||
node [shape=box];
|
||||
";
|
||||
for (sort keys %nodes) {
|
||||
print O qq{ "$_";\n} if keys %{$nodes{$_}} and defined $nodes{$_}{actor};
|
||||
}
|
||||
|
||||
print O " /* undefined entities */
|
||||
node [color=red];
|
||||
";
|
||||
for (sort keys %nodes) {
|
||||
print O qq{ "$_";\n} if not keys %{$nodes{$_}};
|
||||
}
|
||||
|
||||
print O "\n /* inheritance edges */\n";
|
||||
for (sort keys %nodes) {
|
||||
print O qq{ "$nodes{$_}{parent}" -> "$_";\n} if defined $nodes{$_}{parent};
|
||||
}
|
||||
|
||||
print O "\n /* upgrade edges */\n";
|
||||
print O " edge [color=red fontcolor=red]\n";
|
||||
for (sort keys %nodes) {
|
||||
if (defined $nodes{$_}{upgrade}[0]) {
|
||||
print O qq{ "$_" -> "$nodes{$_}{upgrade}[0]"};
|
||||
print O qq{ [label="from rank $nodes{$_}{upgrade}[1]"]} if defined $nodes{$_}{upgrade}[1];
|
||||
print O qq{;\n};
|
||||
}
|
||||
}
|
||||
print O "}\n";
|
||||
close O;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Find;
|
||||
|
||||
my $dir = '../../../binaries/data/mods/official/entities';
|
||||
my @xml;
|
||||
find({wanted=>sub{
|
||||
push @xml, $_ if /\.xml$/;
|
||||
}, no_chdir=>1}, $dir);
|
||||
s~\Q$dir/~~ for @xml;
|
||||
|
||||
my %nodes;
|
||||
|
||||
for my $f (@xml) {
|
||||
|
||||
$f =~ m~(?:.*/|^)(.*)\.xml~ or die "invalid filename $f";
|
||||
my $name = $1;
|
||||
|
||||
open I, "$dir/$f" or die "error opening $dir/$f: $!";
|
||||
my $data = do { local $/; <I> };
|
||||
close I;
|
||||
|
||||
my $parent;
|
||||
$parent = $1 if $data =~ /Parent="(.*?)"/;
|
||||
|
||||
my ($upgrade, $rank);
|
||||
$upgrade = $1 if $data =~ /<Entity>\s*(.*?)\s*</s;
|
||||
$rank = $1 if $data =~ /Up.*rank="(.*?)"/s;
|
||||
|
||||
my $actor;
|
||||
$actor = $1 if $data =~ /<Actor>\s*(.*?)\s*</;
|
||||
|
||||
undef $upgrade unless defined $upgrade and length $upgrade;
|
||||
|
||||
$nodes{$parent} ||= {} if defined $parent;
|
||||
$nodes{$upgrade} ||= {} if defined $upgrade;
|
||||
$nodes{$name} = { def=>1, parent=>$parent, upgrade=>[$upgrade, $rank], actor=>$actor };
|
||||
}
|
||||
|
||||
open O, ">", "entities.dot" or die $!;
|
||||
|
||||
print O <<EOF;
|
||||
digraph g
|
||||
{
|
||||
graph [nodesep=.1];
|
||||
edge [fontname=ArialN fontsize=8];
|
||||
EOF
|
||||
|
||||
print O " /* entities without actors */
|
||||
node [fontname=ArialN fontsize=10 shape=ellipse];
|
||||
";
|
||||
for (sort keys %nodes) {
|
||||
print O qq{ "$_";\n} if keys %{$nodes{$_}} and not defined $nodes{$_}{actor};
|
||||
}
|
||||
|
||||
print O " /* entities with actors */
|
||||
node [shape=box];
|
||||
";
|
||||
for (sort keys %nodes) {
|
||||
print O qq{ "$_";\n} if keys %{$nodes{$_}} and defined $nodes{$_}{actor};
|
||||
}
|
||||
|
||||
print O " /* undefined entities */
|
||||
node [color=red];
|
||||
";
|
||||
for (sort keys %nodes) {
|
||||
print O qq{ "$_";\n} if not keys %{$nodes{$_}};
|
||||
}
|
||||
|
||||
print O "\n /* inheritance edges */\n";
|
||||
for (sort keys %nodes) {
|
||||
print O qq{ "$nodes{$_}{parent}" -> "$_";\n} if defined $nodes{$_}{parent};
|
||||
}
|
||||
|
||||
print O "\n /* upgrade edges */\n";
|
||||
print O " edge [color=red fontcolor=red]\n";
|
||||
for (sort keys %nodes) {
|
||||
if (defined $nodes{$_}{upgrade}[0]) {
|
||||
print O qq{ "$_" -> "$nodes{$_}{upgrade}[0]"};
|
||||
print O qq{ [label="from rank $nodes{$_}{upgrade}[1]"]} if defined $nodes{$_}{upgrade}[1];
|
||||
print O qq{;\n};
|
||||
}
|
||||
}
|
||||
print O "}\n";
|
||||
close O;
|
||||
|
||||
system("dot.exe", "-Tpng", "entities.dot", "-o", "entities.png");
|
File diff suppressed because it is too large
Load Diff
@ -1,72 +1,72 @@
|
||||
0 A.D. Font Builder
|
||||
====================
|
||||
|
||||
The Font Builder generates pre-rendered font glyphs for use in the game engine. Its output for each font consists
|
||||
of an 8-bit greyscale PNG image and a descriptor .fnt file that describes and locates each individual glyph in the image
|
||||
(see fileformat.txt for details).
|
||||
|
||||
See the wiki page for more information:
|
||||
|
||||
http://trac.wildfiregames.com/wiki/Font_Builder2
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
The main prerequisite for the fontbuilder is the Cairo imaging library and its Python bindings, PyCairo. On most
|
||||
Linux distributions, this should be merely a matter of installing a package (e.g. 'python-cairo' for Debian/Ubuntu),
|
||||
but on Windows it's more involved.
|
||||
|
||||
We'll demonstrate the process for Windows 32-bit first. Grab a Win32 binary for PyCairo from
|
||||
|
||||
http://ftp.gnome.org/pub/GNOME/binaries/win32/pycairo/1.8/
|
||||
|
||||
and install it using the installer. There are installers available for Python versions 2.6 and 2.7. The installer
|
||||
extracts the necessary files into Lib\site-packages\cairo within your Python installation directory.
|
||||
|
||||
Next is Cairo itself, and some dependencies which are required for Cairo to work. Head to
|
||||
|
||||
http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/
|
||||
|
||||
and get the following binaries. Listed next to each are their version numbers at the time of writing; these may vary
|
||||
over time, so be adaptive!
|
||||
|
||||
- Cairo (cairo_1.8.10-3_win32.zip)
|
||||
- Fontconfig (fontconfig_2.8.0-2_win32.zip)
|
||||
- Freetype (freetype_2.4.4-1_win32.zip)
|
||||
- Expat (expat_2.0.1-1_win32.zip)
|
||||
- libpng (libpng_1.4.3-1_win32.zip)
|
||||
- zlib (zlib_1.2.5-2_win32.zip).
|
||||
|
||||
Each ZIP file will contain a bin subfolder with a DLL file in it. Put the following DLLs in Lib\site-packages\cairo
|
||||
within your Python installation:
|
||||
|
||||
libcairo-2.dll (from cairo_1.8.10-3_win32.zip)
|
||||
libfontconfig-1.dll (from fontconfig_2.8.0-2_win32.zip)
|
||||
freetype6.dll (from freetype_2.4.4-1_win32.zip)
|
||||
libexpat-1.dll (from expat_2.0.1-1_win32.zip)
|
||||
libpng14-14.dll (from libpng_1.4.3-1_win32.zip)
|
||||
zlib1.dll (from zlib_1.2.5-2_win32.zip).
|
||||
|
||||
You should be all set now. To test whether PyCairo installed successfully, try running the following command on a
|
||||
command line:
|
||||
|
||||
python -c "import cairo"
|
||||
|
||||
If it doesn't complain, then it's installed successfully.
|
||||
|
||||
On Windows 64-bit, the process is similar, but no pre-built PyCairo executable appears to be available from Gnome at
|
||||
the time of writing. Instead, you can install PyGTK+ for 64-bit Windows, which includes Cairo, PyCairo, and the
|
||||
same set of dependencies. See this page for details:
|
||||
|
||||
http://www.pygtk.org/downloads.html
|
||||
|
||||
Running
|
||||
-------
|
||||
|
||||
Running the font-builder is fairly straight-forward; there are no configuration options. One caveat is that you must
|
||||
run it from its own directory as the current directory.
|
||||
|
||||
python fontbuilder.py
|
||||
|
||||
This will generate the output .png and .fnt files straight into the binaries/data/mods/public/fonts directory, ready
|
||||
for in-game use.
|
||||
0 A.D. Font Builder
|
||||
====================
|
||||
|
||||
The Font Builder generates pre-rendered font glyphs for use in the game engine. Its output for each font consists
|
||||
of an 8-bit greyscale PNG image and a descriptor .fnt file that describes and locates each individual glyph in the image
|
||||
(see fileformat.txt for details).
|
||||
|
||||
See the wiki page for more information:
|
||||
|
||||
http://trac.wildfiregames.com/wiki/Font_Builder2
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
The main prerequisite for the fontbuilder is the Cairo imaging library and its Python bindings, PyCairo. On most
|
||||
Linux distributions, this should be merely a matter of installing a package (e.g. 'python-cairo' for Debian/Ubuntu),
|
||||
but on Windows it's more involved.
|
||||
|
||||
We'll demonstrate the process for Windows 32-bit first. Grab a Win32 binary for PyCairo from
|
||||
|
||||
http://ftp.gnome.org/pub/GNOME/binaries/win32/pycairo/1.8/
|
||||
|
||||
and install it using the installer. There are installers available for Python versions 2.6 and 2.7. The installer
|
||||
extracts the necessary files into Lib\site-packages\cairo within your Python installation directory.
|
||||
|
||||
Next is Cairo itself, and some dependencies which are required for Cairo to work. Head to
|
||||
|
||||
http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/
|
||||
|
||||
and get the following binaries. Listed next to each are their version numbers at the time of writing; these may vary
|
||||
over time, so be adaptive!
|
||||
|
||||
- Cairo (cairo_1.8.10-3_win32.zip)
|
||||
- Fontconfig (fontconfig_2.8.0-2_win32.zip)
|
||||
- Freetype (freetype_2.4.4-1_win32.zip)
|
||||
- Expat (expat_2.0.1-1_win32.zip)
|
||||
- libpng (libpng_1.4.3-1_win32.zip)
|
||||
- zlib (zlib_1.2.5-2_win32.zip).
|
||||
|
||||
Each ZIP file will contain a bin subfolder with a DLL file in it. Put the following DLLs in Lib\site-packages\cairo
|
||||
within your Python installation:
|
||||
|
||||
libcairo-2.dll (from cairo_1.8.10-3_win32.zip)
|
||||
libfontconfig-1.dll (from fontconfig_2.8.0-2_win32.zip)
|
||||
freetype6.dll (from freetype_2.4.4-1_win32.zip)
|
||||
libexpat-1.dll (from expat_2.0.1-1_win32.zip)
|
||||
libpng14-14.dll (from libpng_1.4.3-1_win32.zip)
|
||||
zlib1.dll (from zlib_1.2.5-2_win32.zip).
|
||||
|
||||
You should be all set now. To test whether PyCairo installed successfully, try running the following command on a
|
||||
command line:
|
||||
|
||||
python -c "import cairo"
|
||||
|
||||
If it doesn't complain, then it's installed successfully.
|
||||
|
||||
On Windows 64-bit, the process is similar, but no pre-built PyCairo executable appears to be available from Gnome at
|
||||
the time of writing. Instead, you can install PyGTK+ for 64-bit Windows, which includes Cairo, PyCairo, and the
|
||||
same set of dependencies. See this page for details:
|
||||
|
||||
http://www.pygtk.org/downloads.html
|
||||
|
||||
Running
|
||||
-------
|
||||
|
||||
Running the font-builder is fairly straight-forward; there are no configuration options. One caveat is that you must
|
||||
run it from its own directory as the current directory.
|
||||
|
||||
python fontbuilder.py
|
||||
|
||||
This will generate the output .png and .fnt files straight into the binaries/data/mods/public/fonts directory, ready
|
||||
for in-game use.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
' Simple VBScript to open the 0 A.D. logs folder
|
||||
' the path varies on different versions of Windows
|
||||
Set objShell = CreateObject("Shell.Application")
|
||||
' 0x1C is equivalent to the ssfLOCALAPPDATA constant in VB
|
||||
objShell.Explore objShell.Namespace(&H1C&).Self.Path & "\0ad\logs"
|
||||
' Simple VBScript to open the 0 A.D. logs folder
|
||||
' the path varies on different versions of Windows
|
||||
Set objShell = CreateObject("Shell.Application")
|
||||
' 0x1C is equivalent to the ssfLOCALAPPDATA constant in VB
|
||||
objShell.Explore objShell.Namespace(&H1C&).Self.Path & "\0ad\logs"
|
||||
|
@ -1,426 +1,426 @@
|
||||
// Copyright (c) 2016 Wildfire Games
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Profiler2Report module
|
||||
// Create one instance per profiler report you wish to open.
|
||||
// This gives you the interface to access the raw and processed data
|
||||
|
||||
var Profiler2Report = function(callback, tryLive, file)
|
||||
{
|
||||
var outInterface = {};
|
||||
|
||||
// Item types returned by the engine
|
||||
var ITEM_EVENT = 1;
|
||||
var ITEM_ENTER = 2;
|
||||
var ITEM_LEAVE = 3;
|
||||
var ITEM_ATTRIBUTE = 4;
|
||||
|
||||
var g_used_colours = {};
|
||||
|
||||
var g_raw_data;
|
||||
var g_data;
|
||||
|
||||
function refresh(callback, tryLive, file)
|
||||
{
|
||||
if (tryLive)
|
||||
refresh_live(callback, file);
|
||||
else
|
||||
refresh_jsonp(callback, file);
|
||||
}
|
||||
outInterface.refresh = refresh;
|
||||
|
||||
function refresh_jsonp(callback, source)
|
||||
{
|
||||
if (!source)
|
||||
{
|
||||
callback(false);
|
||||
return
|
||||
}
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e)
|
||||
{
|
||||
refresh_from_jsonp(callback, e.target.result);
|
||||
}
|
||||
reader.onerror = function(e) {
|
||||
alert("Failed to load report file");
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
reader.readAsText(source);
|
||||
}
|
||||
|
||||
function refresh_from_jsonp(callback, content)
|
||||
{
|
||||
var script = document.createElement('script');
|
||||
|
||||
window.profileDataCB = function(data)
|
||||
{
|
||||
script.parentNode.removeChild(script);
|
||||
|
||||
var threads = [];
|
||||
data.threads.forEach(function(thread) {
|
||||
var canvas = $('<canvas width="1600" height="160"></canvas>');
|
||||
threads.push({'name': thread.name, 'data': { 'events': concat_events(thread.data) }, 'canvas': canvas.get(0)});
|
||||
});
|
||||
g_raw_data = { 'threads': threads };
|
||||
compute_data();
|
||||
callback(true);
|
||||
};
|
||||
|
||||
script.innerHTML = content;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
|
||||
function refresh_live(callback, file)
|
||||
{
|
||||
$.ajax({
|
||||
url: 'http://127.0.0.1:8000/overview',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
var threads = [];
|
||||
data.threads.forEach(function(thread) {
|
||||
threads.push({'name': thread.name});
|
||||
});
|
||||
var callback_data = { 'threads': threads, 'completed': 0 };
|
||||
|
||||
threads.forEach(function(thread) {
|
||||
refresh_thread(callback, thread, callback_data);
|
||||
});
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown)
|
||||
{
|
||||
console.log('Failed to connect to server ("'+textStatus+'")');
|
||||
callback(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function refresh_thread(callback, thread, callback_data)
|
||||
{
|
||||
$.ajax({
|
||||
url: 'http://127.0.0.1:8000/query',
|
||||
dataType: 'json',
|
||||
data: { 'thread': thread.name },
|
||||
success: function (data) {
|
||||
data.events = concat_events(data);
|
||||
thread.data = data;
|
||||
|
||||
if (++callback_data.completed == callback_data.threads.length)
|
||||
{
|
||||
g_raw_data = { 'threads': callback_data.threads };
|
||||
compute_data();
|
||||
callback(true);
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
alert('Failed to connect to server ("'+textStatus+'")');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function compute_data(range)
|
||||
{
|
||||
g_data = { "threads" : [] };
|
||||
g_data_by_frame = { "threads" : [] };
|
||||
for (let thread = 0; thread < g_raw_data.threads.length; thread++)
|
||||
{
|
||||
let processed_data = process_raw_data(g_raw_data.threads[thread].data.events, range );
|
||||
if (!processed_data.intervals.length && !processed_data.events.length)
|
||||
continue;
|
||||
|
||||
g_data.threads[thread] = processed_data;
|
||||
|
||||
g_data.threads[thread].intervals_by_type_frame = {};
|
||||
|
||||
if (!g_data.threads[thread].frames.length)
|
||||
continue
|
||||
// compute intervals by types and frames if there are frames.
|
||||
for (let type in g_data.threads[thread].intervals_by_type)
|
||||
{
|
||||
let current_frame = 0;
|
||||
g_data.threads[thread].intervals_by_type_frame[type] = [[]];
|
||||
for (let i = 0; i < g_data.threads[thread].intervals_by_type[type].length;i++)
|
||||
{
|
||||
let event = g_data.threads[thread].intervals[g_data.threads[thread].intervals_by_type[type][i]];
|
||||
while (current_frame < g_data.threads[thread].frames.length && event.t0 > g_data.threads[thread].frames[current_frame].t1)
|
||||
{
|
||||
g_data.threads[thread].intervals_by_type_frame[type].push([]);
|
||||
current_frame++;
|
||||
}
|
||||
if (current_frame < g_data.threads[thread].frames.length)
|
||||
g_data.threads[thread].intervals_by_type_frame[type][current_frame].push(g_data.threads[thread].intervals_by_type[type][i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function process_raw_data(data, range)
|
||||
{
|
||||
if (!data.length)
|
||||
return { 'frames': [], 'events': [], 'intervals': [], 'intervals_by_type' : {}, 'tmin': 0, 'tmax': 0 };
|
||||
|
||||
var start, end;
|
||||
var tmin, tmax;
|
||||
|
||||
var frames = [];
|
||||
var last_frame_time_start = undefined;
|
||||
var last_frame_time_end = undefined;
|
||||
|
||||
var stack = [];
|
||||
for (var i = 0; i < data.length; ++i)
|
||||
{
|
||||
if (data[i][0] == ITEM_EVENT && data[i][2] == '__framestart')
|
||||
{
|
||||
if (last_frame_time_end)
|
||||
frames.push({'t0': last_frame_time_start, 't1': last_frame_time_end});
|
||||
last_frame_time_start = data[i][1];
|
||||
}
|
||||
if (data[i][0] == ITEM_ENTER)
|
||||
stack.push(data[i][2]);
|
||||
if (data[i][0] == ITEM_LEAVE)
|
||||
{
|
||||
if (stack[stack.length-1] == 'frame')
|
||||
last_frame_time_end = data[i][1];
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
if(!range)
|
||||
{
|
||||
range = { "tmin" : data[0][1], "tmax" : data[data.length-1][1] };
|
||||
}
|
||||
if (range.numframes)
|
||||
{
|
||||
for (var i = data.length - 1; i > 0; --i)
|
||||
{
|
||||
if (data[i][0] == ITEM_EVENT && data[i][2] == '__framestart')
|
||||
{
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var framesfound = 0;
|
||||
for (var i = end - 1; i > 0; --i)
|
||||
{
|
||||
if (data[i][0] == ITEM_EVENT && data[i][2] == '__framestart')
|
||||
{
|
||||
start = i;
|
||||
if (++framesfound == range.numframes)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tmin = data[start][1];
|
||||
tmax = data[end][1];
|
||||
}
|
||||
else if (range.seconds)
|
||||
{
|
||||
var end = data.length - 1;
|
||||
for (var i = end; i > 0; --i)
|
||||
{
|
||||
var type = data[i][0];
|
||||
if (type == ITEM_EVENT || type == ITEM_ENTER || type == ITEM_LEAVE)
|
||||
{
|
||||
tmax = data[i][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmin = tmax - range.seconds;
|
||||
|
||||
for (var i = end; i > 0; --i)
|
||||
{
|
||||
var type = data[i][0];
|
||||
if ((type == ITEM_EVENT || type == ITEM_ENTER || type == ITEM_LEAVE) && data[i][1] < tmin)
|
||||
break;
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
start = 0;
|
||||
end = data.length - 1;
|
||||
tmin = range.tmin;
|
||||
tmax = range.tmax;
|
||||
|
||||
for (var i = data.length-1; i > 0; --i)
|
||||
{
|
||||
var type = data[i][0];
|
||||
if ((type == ITEM_EVENT || type == ITEM_ENTER || type == ITEM_LEAVE) && data[i][1] < tmax)
|
||||
{
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = end; i > 0; --i)
|
||||
{
|
||||
var type = data[i][0];
|
||||
if ((type == ITEM_EVENT || type == ITEM_ENTER || type == ITEM_LEAVE) && data[i][1] < tmin)
|
||||
break;
|
||||
start = i;
|
||||
}
|
||||
|
||||
// Move the start/end outwards by another frame, so we don't lose data at the edges
|
||||
while (start > 0)
|
||||
{
|
||||
--start;
|
||||
if (data[start][0] == ITEM_EVENT && data[start][2] == '__framestart')
|
||||
break;
|
||||
}
|
||||
while (end < data.length-1)
|
||||
{
|
||||
++end;
|
||||
if (data[end][0] == ITEM_EVENT && data[end][2] == '__framestart')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var num_colours = 0;
|
||||
|
||||
var events = [];
|
||||
|
||||
// Read events for the entire data period (not just start..end)
|
||||
var lastWasEvent = false;
|
||||
for (var i = 0; i < data.length; ++i)
|
||||
{
|
||||
if (data[i][0] == ITEM_EVENT)
|
||||
{
|
||||
events.push({'t': data[i][1], 'id': data[i][2]});
|
||||
lastWasEvent = true;
|
||||
}
|
||||
else if (data[i][0] == ITEM_ATTRIBUTE)
|
||||
{
|
||||
if (lastWasEvent)
|
||||
{
|
||||
if (!events[events.length-1].attrs)
|
||||
events[events.length-1].attrs = [];
|
||||
events[events.length-1].attrs.push(data[i][1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lastWasEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var intervals = [];
|
||||
var intervals_by_type = {};
|
||||
|
||||
// Read intervals from the focused data period (start..end)
|
||||
stack = [];
|
||||
var lastT = 0;
|
||||
var lastWasEvent = false;
|
||||
|
||||
for (var i = start; i <= end; ++i)
|
||||
{
|
||||
if (data[i][0] == ITEM_EVENT)
|
||||
{
|
||||
// if (data[i][1] < lastT)
|
||||
// console.log('Time went backwards: ' + (data[i][1] - lastT));
|
||||
|
||||
lastT = data[i][1];
|
||||
lastWasEvent = true;
|
||||
}
|
||||
else if (data[i][0] == ITEM_ENTER)
|
||||
{
|
||||
// if (data[i][1] < lastT)
|
||||
// console.log('Time - ENTER went backwards: ' + (data[i][1] - lastT) + " - " + JSON.stringify(data[i]));
|
||||
|
||||
stack.push({'t0': data[i][1], 'id': data[i][2]});
|
||||
|
||||
lastT = data[i][1];
|
||||
lastWasEvent = false;
|
||||
}
|
||||
else if (data[i][0] == ITEM_LEAVE)
|
||||
{
|
||||
// if (data[i][1] < lastT)
|
||||
// console.log('Time - LEAVE went backwards: ' + (data[i][1] - lastT) + " - " + JSON.stringify(data[i]));
|
||||
|
||||
lastT = data[i][1];
|
||||
lastWasEvent = false;
|
||||
|
||||
if (!stack.length)
|
||||
continue;
|
||||
|
||||
var interval = stack.pop();
|
||||
|
||||
if (!g_used_colours[interval.id])
|
||||
g_used_colours[interval.id] = new_colour(num_colours++);
|
||||
|
||||
interval.colour = g_used_colours[interval.id];
|
||||
|
||||
interval.t1 = data[i][1];
|
||||
interval.duration = interval.t1 - interval.t0;
|
||||
interval.depth = stack.length;
|
||||
//console.log(JSON.stringify(interval));
|
||||
intervals.push(interval);
|
||||
if (interval.id in intervals_by_type)
|
||||
intervals_by_type[interval.id].push(intervals.length-1);
|
||||
else
|
||||
intervals_by_type[interval.id] = [intervals.length-1];
|
||||
|
||||
if (interval.id == "Script" && interval.attrs && interval.attrs.length)
|
||||
{
|
||||
let curT = interval.t0;
|
||||
for (let subItem in interval.attrs)
|
||||
{
|
||||
let sub = interval.attrs[subItem];
|
||||
if (sub.search("buffer") != -1)
|
||||
continue;
|
||||
let newInterv = {};
|
||||
newInterv.t0 = curT;
|
||||
newInterv.duration = +sub.replace(/.+? ([.0-9]+)us/, "$1")/1000000;
|
||||
if (!newInterv.duration)
|
||||
continue;
|
||||
newInterv.t1 = curT + newInterv.duration;
|
||||
curT += newInterv.duration;
|
||||
newInterv.id = "Script:" + sub.replace(/(.+?) ([.0-9]+)us/, "$1");
|
||||
newInterv.colour = g_used_colours[interval.id];
|
||||
newInterv.depth = interval.depth+1;
|
||||
intervals.push(newInterv);
|
||||
if (newInterv.id in intervals_by_type)
|
||||
intervals_by_type[newInterv.id].push(intervals.length-1);
|
||||
else
|
||||
intervals_by_type[newInterv.id] = [intervals.length-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data[i][0] == ITEM_ATTRIBUTE)
|
||||
{
|
||||
if (!lastWasEvent && stack.length)
|
||||
{
|
||||
if (!stack[stack.length-1].attrs)
|
||||
stack[stack.length-1].attrs = [];
|
||||
stack[stack.length-1].attrs.push(data[i][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return { 'frames': frames, 'events': events, 'intervals': intervals, 'intervals_by_type' : intervals_by_type, 'tmin': tmin, 'tmax': tmax };
|
||||
}
|
||||
|
||||
outInterface.data = function() { return g_data; };
|
||||
outInterface.raw_data = function() { return g_raw_data; };
|
||||
outInterface.data_by_frame = function() { return g_data_by_frame; };
|
||||
|
||||
refresh(callback, tryLive, file);
|
||||
|
||||
return outInterface;
|
||||
};
|
||||
// Copyright (c) 2016 Wildfire Games
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Profiler2Report module
|
||||
// Create one instance per profiler report you wish to open.
|
||||
// This gives you the interface to access the raw and processed data
|
||||
|
||||
var Profiler2Report = function(callback, tryLive, file)
|
||||
{
|
||||
var outInterface = {};
|
||||
|
||||
// Item types returned by the engine
|
||||
var ITEM_EVENT = 1;
|
||||
var ITEM_ENTER = 2;
|
||||
var ITEM_LEAVE = 3;
|
||||
var ITEM_ATTRIBUTE = 4;
|
||||
|
||||
var g_used_colours = {};
|
||||
|
||||
var g_raw_data;
|
||||
var g_data;
|
||||
|
||||
function refresh(callback, tryLive, file)
|
||||
{
|
||||
if (tryLive)
|
||||
refresh_live(callback, file);
|
||||
else
|
||||
refresh_jsonp(callback, file);
|
||||
}
|
||||
outInterface.refresh = refresh;
|
||||
|
||||
function refresh_jsonp(callback, source)
|
||||
{
|
||||
if (!source)
|
||||
{
|
||||
callback(false);
|
||||
return
|
||||
}
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e)
|
||||
{
|
||||
refresh_from_jsonp(callback, e.target.result);
|
||||
}
|
||||
reader.onerror = function(e) {
|
||||
alert("Failed to load report file");
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
reader.readAsText(source);
|
||||
}
|
||||
|
||||
function refresh_from_jsonp(callback, content)
|
||||
{
|
||||
var script = document.createElement('script');
|
||||
|
||||
window.profileDataCB = function(data)
|
||||
{
|
||||
script.parentNode.removeChild(script);
|
||||
|
||||
var threads = [];
|
||||
data.threads.forEach(function(thread) {
|
||||
var canvas = $('<canvas width="1600" height="160"></canvas>');
|
||||
threads.push({'name': thread.name, 'data': { 'events': concat_events(thread.data) }, 'canvas': canvas.get(0)});
|
||||
});
|
||||
g_raw_data = { 'threads': threads };
|
||||
compute_data();
|
||||
callback(true);
|
||||
};
|
||||
|
||||
script.innerHTML = content;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
|
||||
function refresh_live(callback, file)
|
||||
{
|
||||
$.ajax({
|
||||
url: 'http://127.0.0.1:8000/overview',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
var threads = [];
|
||||
data.threads.forEach(function(thread) {
|
||||
threads.push({'name': thread.name});
|
||||
});
|
||||
var callback_data = { 'threads': threads, 'completed': 0 };
|
||||
|
||||
threads.forEach(function(thread) {
|
||||
refresh_thread(callback, thread, callback_data);
|
||||
});
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown)
|
||||
{
|
||||
console.log('Failed to connect to server ("'+textStatus+'")');
|
||||
callback(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function refresh_thread(callback, thread, callback_data)
|
||||
{
|
||||
$.ajax({
|
||||
url: 'http://127.0.0.1:8000/query',
|
||||
dataType: 'json',
|
||||
data: { 'thread': thread.name },
|
||||
success: function (data) {
|
||||
data.events = concat_events(data);
|
||||
thread.data = data;
|
||||
|
||||
if (++callback_data.completed == callback_data.threads.length)
|
||||
{
|
||||
g_raw_data = { 'threads': callback_data.threads };
|
||||
compute_data();
|
||||
callback(true);
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
alert('Failed to connect to server ("'+textStatus+'")');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function compute_data(range)
|
||||
{
|
||||
g_data = { "threads" : [] };
|
||||
g_data_by_frame = { "threads" : [] };
|
||||
for (let thread = 0; thread < g_raw_data.threads.length; thread++)
|
||||
{
|
||||
let processed_data = process_raw_data(g_raw_data.threads[thread].data.events, range );
|
||||
if (!processed_data.intervals.length && !processed_data.events.length)
|
||||
continue;
|
||||
|
||||
g_data.threads[thread] = processed_data;
|
||||
|
||||
g_data.threads[thread].intervals_by_type_frame = {};
|
||||
|
||||
if (!g_data.threads[thread].frames.length)
|
||||
continue
|
||||
// compute intervals by types and frames if there are frames.
|
||||
for (let type in g_data.threads[thread].intervals_by_type)
|
||||
{
|
||||
let current_frame = 0;
|
||||
g_data.threads[thread].intervals_by_type_frame[type] = [[]];
|
||||
for (let i = 0; i < g_data.threads[thread].intervals_by_type[type].length;i++)
|
||||
{
|
||||
let event = g_data.threads[thread].intervals[g_data.threads[thread].intervals_by_type[type][i]];
|
||||
while (current_frame < g_data.threads[thread].frames.length && event.t0 > g_data.threads[thread].frames[current_frame].t1)
|
||||
{
|
||||
g_data.threads[thread].intervals_by_type_frame[type].push([]);
|
||||
current_frame++;
|
||||
}
|
||||
if (current_frame < g_data.threads[thread].frames.length)
|
||||
g_data.threads[thread].intervals_by_type_frame[type][current_frame].push(g_data.threads[thread].intervals_by_type[type][i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function process_raw_data(data, range)
|
||||
{
|
||||
if (!data.length)
|
||||
return { 'frames': [], 'events': [], 'intervals': [], 'intervals_by_type' : {}, 'tmin': 0, 'tmax': 0 };
|
||||
|
||||
var start, end;
|
||||
var tmin, tmax;
|
||||
|
||||
var frames = [];
|
||||
var last_frame_time_start = undefined;
|
||||
var last_frame_time_end = undefined;
|
||||
|
||||
var stack = [];
|
||||
for (var i = 0; i < data.length; ++i)
|
||||
{
|
||||
if (data[i][0] == ITEM_EVENT && data[i][2] == '__framestart')
|
||||
{
|
||||
if (last_frame_time_end)
|
||||
frames.push({'t0': last_frame_time_start, 't1': last_frame_time_end});
|
||||
last_frame_time_start = data[i][1];
|
||||
}
|
||||
if (data[i][0] == ITEM_ENTER)
|
||||
stack.push(data[i][2]);
|
||||
if (data[i][0] == ITEM_LEAVE)
|
||||
{
|
||||
if (stack[stack.length-1] == 'frame')
|
||||
last_frame_time_end = data[i][1];
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
if(!range)
|
||||
{
|
||||
range = { "tmin" : data[0][1], "tmax" : data[data.length-1][1] };
|
||||
}
|
||||
if (range.numframes)
|
||||
{
|
||||
for (var i = data.length - 1; i > 0; --i)
|
||||
{
|
||||
if (data[i][0] == ITEM_EVENT && data[i][2] == '__framestart')
|
||||
{
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var framesfound = 0;
|
||||
for (var i = end - 1; i > 0; --i)
|
||||
{
|
||||
if (data[i][0] == ITEM_EVENT && data[i][2] == '__framestart')
|
||||
{
|
||||
start = i;
|
||||
if (++framesfound == range.numframes)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tmin = data[start][1];
|
||||
tmax = data[end][1];
|
||||
}
|
||||
else if (range.seconds)
|
||||
{
|
||||
var end = data.length - 1;
|
||||
for (var i = end; i > 0; --i)
|
||||
{
|
||||
var type = data[i][0];
|
||||
if (type == ITEM_EVENT || type == ITEM_ENTER || type == ITEM_LEAVE)
|
||||
{
|
||||
tmax = data[i][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmin = tmax - range.seconds;
|
||||
|
||||
for (var i = end; i > 0; --i)
|
||||
{
|
||||
var type = data[i][0];
|
||||
if ((type == ITEM_EVENT || type == ITEM_ENTER || type == ITEM_LEAVE) && data[i][1] < tmin)
|
||||
break;
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
start = 0;
|
||||
end = data.length - 1;
|
||||
tmin = range.tmin;
|
||||
tmax = range.tmax;
|
||||
|
||||
for (var i = data.length-1; i > 0; --i)
|
||||
{
|
||||
var type = data[i][0];
|
||||
if ((type == ITEM_EVENT || type == ITEM_ENTER || type == ITEM_LEAVE) && data[i][1] < tmax)
|
||||
{
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = end; i > 0; --i)
|
||||
{
|
||||
var type = data[i][0];
|
||||
if ((type == ITEM_EVENT || type == ITEM_ENTER || type == ITEM_LEAVE) && data[i][1] < tmin)
|
||||
break;
|
||||
start = i;
|
||||
}
|
||||
|
||||
// Move the start/end outwards by another frame, so we don't lose data at the edges
|
||||
while (start > 0)
|
||||
{
|
||||
--start;
|
||||
if (data[start][0] == ITEM_EVENT && data[start][2] == '__framestart')
|
||||
break;
|
||||
}
|
||||
while (end < data.length-1)
|
||||
{
|
||||
++end;
|
||||
if (data[end][0] == ITEM_EVENT && data[end][2] == '__framestart')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var num_colours = 0;
|
||||
|
||||
var events = [];
|
||||
|
||||
// Read events for the entire data period (not just start..end)
|
||||
var lastWasEvent = false;
|
||||
for (var i = 0; i < data.length; ++i)
|
||||
{
|
||||
if (data[i][0] == ITEM_EVENT)
|
||||
{
|
||||
events.push({'t': data[i][1], 'id': data[i][2]});
|
||||
lastWasEvent = true;
|
||||
}
|
||||
else if (data[i][0] == ITEM_ATTRIBUTE)
|
||||
{
|
||||
if (lastWasEvent)
|
||||
{
|
||||
if (!events[events.length-1].attrs)
|
||||
events[events.length-1].attrs = [];
|
||||
events[events.length-1].attrs.push(data[i][1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lastWasEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var intervals = [];
|
||||
var intervals_by_type = {};
|
||||
|
||||
// Read intervals from the focused data period (start..end)
|
||||
stack = [];
|
||||
var lastT = 0;
|
||||
var lastWasEvent = false;
|
||||
|
||||
for (var i = start; i <= end; ++i)
|
||||
{
|
||||
if (data[i][0] == ITEM_EVENT)
|
||||
{
|
||||
// if (data[i][1] < lastT)
|
||||
// console.log('Time went backwards: ' + (data[i][1] - lastT));
|
||||
|
||||
lastT = data[i][1];
|
||||
lastWasEvent = true;
|
||||
}
|
||||
else if (data[i][0] == ITEM_ENTER)
|
||||
{
|
||||
// if (data[i][1] < lastT)
|
||||
// console.log('Time - ENTER went backwards: ' + (data[i][1] - lastT) + " - " + JSON.stringify(data[i]));
|
||||
|
||||
stack.push({'t0': data[i][1], 'id': data[i][2]});
|
||||
|
||||
lastT = data[i][1];
|
||||
lastWasEvent = false;
|
||||
}
|
||||
else if (data[i][0] == ITEM_LEAVE)
|
||||
{
|
||||
// if (data[i][1] < lastT)
|
||||
// console.log('Time - LEAVE went backwards: ' + (data[i][1] - lastT) + " - " + JSON.stringify(data[i]));
|
||||
|
||||
lastT = data[i][1];
|
||||
lastWasEvent = false;
|
||||
|
||||
if (!stack.length)
|
||||
continue;
|
||||
|
||||
var interval = stack.pop();
|
||||
|
||||
if (!g_used_colours[interval.id])
|
||||
g_used_colours[interval.id] = new_colour(num_colours++);
|
||||
|
||||
interval.colour = g_used_colours[interval.id];
|
||||
|
||||
interval.t1 = data[i][1];
|
||||
interval.duration = interval.t1 - interval.t0;
|
||||
interval.depth = stack.length;
|
||||
//console.log(JSON.stringify(interval));
|
||||
intervals.push(interval);
|
||||
if (interval.id in intervals_by_type)
|
||||
intervals_by_type[interval.id].push(intervals.length-1);
|
||||
else
|
||||
intervals_by_type[interval.id] = [intervals.length-1];
|
||||
|
||||
if (interval.id == "Script" && interval.attrs && interval.attrs.length)
|
||||
{
|
||||
let curT = interval.t0;
|
||||
for (let subItem in interval.attrs)
|
||||
{
|
||||
let sub = interval.attrs[subItem];
|
||||
if (sub.search("buffer") != -1)
|
||||
continue;
|
||||
let newInterv = {};
|
||||
newInterv.t0 = curT;
|
||||
newInterv.duration = +sub.replace(/.+? ([.0-9]+)us/, "$1")/1000000;
|
||||
if (!newInterv.duration)
|
||||
continue;
|
||||
newInterv.t1 = curT + newInterv.duration;
|
||||
curT += newInterv.duration;
|
||||
newInterv.id = "Script:" + sub.replace(/(.+?) ([.0-9]+)us/, "$1");
|
||||
newInterv.colour = g_used_colours[interval.id];
|
||||
newInterv.depth = interval.depth+1;
|
||||
intervals.push(newInterv);
|
||||
if (newInterv.id in intervals_by_type)
|
||||
intervals_by_type[newInterv.id].push(intervals.length-1);
|
||||
else
|
||||
intervals_by_type[newInterv.id] = [intervals.length-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data[i][0] == ITEM_ATTRIBUTE)
|
||||
{
|
||||
if (!lastWasEvent && stack.length)
|
||||
{
|
||||
if (!stack[stack.length-1].attrs)
|
||||
stack[stack.length-1].attrs = [];
|
||||
stack[stack.length-1].attrs.push(data[i][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return { 'frames': frames, 'events': events, 'intervals': intervals, 'intervals_by_type' : intervals_by_type, 'tmin': tmin, 'tmax': tmax };
|
||||
}
|
||||
|
||||
outInterface.data = function() { return g_data; };
|
||||
outInterface.raw_data = function() { return g_raw_data; };
|
||||
outInterface.data_by_frame = function() { return g_data_by_frame; };
|
||||
|
||||
refresh(callback, tryLive, file);
|
||||
|
||||
return outInterface;
|
||||
};
|
||||
|
@ -1,479 +1,479 @@
|
||||
// Copyright (c) 2016 Wildfire Games
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Handles the drawing of a report
|
||||
|
||||
var g_report_draw = (function()
|
||||
{
|
||||
var outInterface = {};
|
||||
|
||||
var mouse_is_down = null;
|
||||
|
||||
function rebuild_canvases(raw_data)
|
||||
{
|
||||
g_canvas = {};
|
||||
|
||||
g_canvas.canvas_frames = $('<canvas width="1600" height="128"></canvas>').get(0);
|
||||
g_canvas.threads = {};
|
||||
|
||||
for (var thread = 0; thread < raw_data.threads.length; thread++)
|
||||
g_canvas.threads[thread] = $('<canvas width="1600" height="128"></canvas>').get(0);
|
||||
|
||||
g_canvas.canvas_zoom = $('<canvas width="1600" height="192"></canvas>').get(0);
|
||||
g_canvas.text_output = $('<pre></pre>').get(0);
|
||||
|
||||
$('#timelines').empty();
|
||||
$('#timelines').append("<h3>Main thread frames</h3>");
|
||||
$('#timelines').append(g_canvas.canvas_frames);
|
||||
for (var thread = 0; thread < raw_data.threads.length; thread++)
|
||||
{
|
||||
$('#timelines').append("<h3>" + raw_data.threads[thread].name + "</h3>");
|
||||
$('#timelines').append($(g_canvas.threads[thread]));
|
||||
}
|
||||
|
||||
$('#timelines').append("<h3>Zoomed frames</h3>");
|
||||
$('#timelines').append(g_canvas.canvas_zoom);
|
||||
$('#timelines').append(g_canvas.text_output);
|
||||
}
|
||||
|
||||
function update_display(report, range)
|
||||
{
|
||||
let data = report.data();
|
||||
let raw_data = report.raw_data();
|
||||
let main_data = data.threads[g_main_thread];
|
||||
|
||||
rebuild_canvases(raw_data);
|
||||
|
||||
if (range.seconds)
|
||||
{
|
||||
range.tmax = main_data.frames[main_data.frames.length-1].t1;
|
||||
range.tmin = main_data.frames[main_data.frames.length-1].t1-range.seconds;
|
||||
}
|
||||
else if (range.frames)
|
||||
{
|
||||
range.tmax = main_data.frames[main_data.frames.length-1].t1;
|
||||
range.tmin = main_data.frames[main_data.frames.length-1-range.frames].t0;
|
||||
}
|
||||
|
||||
$(g_canvas.text_output).empty();
|
||||
|
||||
display_frames(data.threads[g_main_thread], g_canvas.canvas_frames, range);
|
||||
display_events(data.threads[g_main_thread], g_canvas.canvas_frames, range);
|
||||
|
||||
set_frames_zoom_handlers(report, g_canvas.canvas_frames);
|
||||
set_tooltip_handlers(g_canvas.canvas_frames);
|
||||
|
||||
$(g_canvas.canvas_zoom).unbind();
|
||||
|
||||
set_zoom_handlers(data.threads[g_main_thread], data.threads[g_main_thread], g_canvas.threads[g_main_thread], g_canvas.canvas_zoom);
|
||||
set_tooltip_handlers(data.canvas_zoom);
|
||||
|
||||
for (var i = 0; i < data.threads.length; i++)
|
||||
{
|
||||
$(g_canvas.threads[i]).unbind();
|
||||
|
||||
let events = slice_intervals(data.threads[i], range);
|
||||
|
||||
display_hierarchy(data.threads[i], events, g_canvas.threads[i], {});
|
||||
set_zoom_handlers(data.threads[i], events, g_canvas.threads[i], g_canvas.canvas_zoom);
|
||||
set_tooltip_handlers(g_canvas.threads[i]);
|
||||
};
|
||||
}
|
||||
outInterface.update_display = update_display;
|
||||
|
||||
function display_frames(data, canvas, range)
|
||||
{
|
||||
canvas._tooltips = [];
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.save();
|
||||
|
||||
var xpadding = 8;
|
||||
var padding_top = 40;
|
||||
var width = canvas.width - xpadding*2;
|
||||
var height = canvas.height - padding_top - 4;
|
||||
|
||||
var tmin = data.tmin;
|
||||
var tmax = data.tmax;
|
||||
var dx = width / (tmax-tmin);
|
||||
|
||||
canvas._zoomData = {
|
||||
'x_to_t': x => tmin + (x - xpadding) / dx,
|
||||
't_to_x': t => (t - tmin) * dx + xpadding
|
||||
};
|
||||
|
||||
// log 100 scale, skip < 15 ms (60fps)
|
||||
var scale = x => 1 - Math.max(0, Math.log(1 + (x-15)/10) / Math.log(100));
|
||||
|
||||
ctx.strokeStyle = 'rgb(0, 0, 0)';
|
||||
ctx.fillStyle = 'rgb(255, 255, 255)';
|
||||
for (var i = 0; i < data.frames.length; ++i)
|
||||
{
|
||||
var frame = data.frames[i];
|
||||
|
||||
var duration = frame.t1 - frame.t0;
|
||||
var x0 = xpadding + dx*(frame.t0 - tmin);
|
||||
var x1 = x0 + dx*duration;
|
||||
var y1 = canvas.height;
|
||||
var y0 = y1 * scale(duration*1000);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.rect(x0, y0, x1-x0, y1-y0);
|
||||
ctx.stroke();
|
||||
|
||||
canvas._tooltips.push({
|
||||
'x0': x0, 'x1': x1,
|
||||
'y0': y0, 'y1': y1,
|
||||
'text': function(frame, duration) { return function() {
|
||||
var t = '<b>Frame</b><br>';
|
||||
t += 'Length: ' + time_label(duration) + '<br>';
|
||||
if (frame.attrs)
|
||||
{
|
||||
frame.attrs.forEach(function(attr)
|
||||
{
|
||||
t += attr + '<br>';
|
||||
});
|
||||
}
|
||||
return t;
|
||||
}} (frame, duration)
|
||||
});
|
||||
}
|
||||
|
||||
[16, 33, 200, 500].forEach(function(t)
|
||||
{
|
||||
var y1 = canvas.height;
|
||||
var y0 = y1 * scale(t);
|
||||
var y = Math.floor(y0) + 0.5;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(xpadding, y);
|
||||
ctx.lineTo(canvas.width - xpadding, y);
|
||||
ctx.strokeStyle = 'rgb(255, 0, 0)';
|
||||
ctx.stroke();
|
||||
ctx.fillStyle = 'rgb(255, 0, 0)';
|
||||
ctx.fillText(t+'ms', 0, y-2);
|
||||
});
|
||||
|
||||
ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)';
|
||||
ctx.fillStyle = 'rgba(128, 128, 255, 0.2)';
|
||||
ctx.beginPath();
|
||||
ctx.rect(xpadding + dx*(range.tmin - tmin), 0, dx*(range.tmax - range.tmin), canvas.height);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
outInterface.display_frames = display_frames;
|
||||
|
||||
function display_events(data, canvas)
|
||||
{
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
|
||||
var x_to_time = canvas._zoomData.x_to_t;
|
||||
var time_to_x = canvas._zoomData.t_to_x;
|
||||
|
||||
for (var i = 0; i < data.events.length; ++i)
|
||||
{
|
||||
var event = data.events[i];
|
||||
|
||||
if (event.id == '__framestart')
|
||||
continue;
|
||||
|
||||
if (event.id == 'gui event' && event.attrs && event.attrs[0] == 'type: mousemove')
|
||||
continue;
|
||||
|
||||
var x = time_to_x(event.t);
|
||||
var y = 32;
|
||||
|
||||
if (x < 2)
|
||||
continue;
|
||||
|
||||
var x0 = x;
|
||||
var x1 = x;
|
||||
var y0 = y-4;
|
||||
var y1 = y+4;
|
||||
|
||||
ctx.strokeStyle = 'rgb(255, 0, 0)';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x0, y0);
|
||||
ctx.lineTo(x1, y1);
|
||||
ctx.stroke();
|
||||
canvas._tooltips.push({
|
||||
'x0': x0, 'x1': x1,
|
||||
'y0': y0, 'y1': y1,
|
||||
'text': function(event) { return function() {
|
||||
var t = '<b>' + event.id + '</b><br>';
|
||||
if (event.attrs)
|
||||
{
|
||||
event.attrs.forEach(function(attr) {
|
||||
t += attr + '<br>';
|
||||
});
|
||||
}
|
||||
return t;
|
||||
}} (event)
|
||||
});
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
outInterface.display_events = display_events;
|
||||
|
||||
function display_hierarchy(main_data, data, canvas, range, zoom)
|
||||
{
|
||||
canvas._tooltips = [];
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.save();
|
||||
|
||||
ctx.font = '12px sans-serif';
|
||||
|
||||
var xpadding = 8;
|
||||
var padding_top = 40;
|
||||
var width = canvas.width - xpadding*2;
|
||||
var height = canvas.height - padding_top - 4;
|
||||
|
||||
var tmin, tmax, start, end;
|
||||
|
||||
if (range.tmin)
|
||||
{
|
||||
tmin = range.tmin;
|
||||
tmax = range.tmax;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmin = data.tmin;
|
||||
tmax = data.tmax;
|
||||
}
|
||||
|
||||
canvas._hierarchyData = { 'range': range, 'tmin': tmin, 'tmax': tmax };
|
||||
|
||||
function time_to_x(t)
|
||||
{
|
||||
return xpadding + (t - tmin) / (tmax - tmin) * width;
|
||||
}
|
||||
|
||||
function x_to_time(x)
|
||||
{
|
||||
return tmin + (x - xpadding) * (tmax - tmin) / width;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.textAlign = 'center';
|
||||
ctx.strokeStyle = 'rgb(192, 192, 192)';
|
||||
ctx.beginPath();
|
||||
var precision = -3;
|
||||
while ((tmax-tmin)*Math.pow(10, 3+precision) < 25)
|
||||
++precision;
|
||||
if (precision > 10)
|
||||
precision = 10;
|
||||
if (precision < 0)
|
||||
precision = 0;
|
||||
var ticks_per_sec = Math.pow(10, 3+precision);
|
||||
var major_tick_interval = 5;
|
||||
|
||||
for (var i = 0; i < (tmax-tmin)*ticks_per_sec; ++i)
|
||||
{
|
||||
var major = (i % major_tick_interval == 0);
|
||||
var x = Math.floor(time_to_x(tmin + i/ticks_per_sec));
|
||||
ctx.moveTo(x-0.5, padding_top - (major ? 4 : 2));
|
||||
ctx.lineTo(x-0.5, padding_top + height);
|
||||
if (major)
|
||||
ctx.fillText((i*1000/ticks_per_sec).toFixed(precision), x, padding_top - 8);
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
var BAR_SPACING = 16;
|
||||
|
||||
for (var i = 0; i < data.intervals.length; ++i)
|
||||
{
|
||||
var interval = data.intervals[i];
|
||||
|
||||
if (interval.tmax <= tmin || interval.tmin > tmax)
|
||||
continue;
|
||||
|
||||
var x0 = Math.floor(time_to_x(interval.t0));
|
||||
var x1 = Math.floor(time_to_x(interval.t1));
|
||||
|
||||
if (x1-x0 < 1)
|
||||
continue;
|
||||
|
||||
var y0 = padding_top + interval.depth * BAR_SPACING;
|
||||
var y1 = y0 + BAR_SPACING;
|
||||
|
||||
var label = interval.id;
|
||||
if (interval.attrs)
|
||||
{
|
||||
if (/^\d+$/.exec(interval.attrs[0]))
|
||||
label += ' ' + interval.attrs[0];
|
||||
else
|
||||
label += ' [...]';
|
||||
}
|
||||
|
||||
ctx.fillStyle = interval.colour;
|
||||
ctx.strokeStyle = 'black';
|
||||
ctx.beginPath();
|
||||
ctx.rect(x0-0.5, y0-0.5, x1-x0, y1-y0);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.fillText(label, x0+2, y0+BAR_SPACING-4, Math.max(1, x1-x0-4));
|
||||
|
||||
canvas._tooltips.push({
|
||||
'x0': x0, 'x1': x1,
|
||||
'y0': y0, 'y1': y1,
|
||||
'text': function(interval) { return function() {
|
||||
var t = '<b>' + interval.id + '</b><br>';
|
||||
t += 'Length: ' + time_label(interval.duration) + '<br>';
|
||||
if (interval.attrs)
|
||||
{
|
||||
interval.attrs.forEach(function(attr) {
|
||||
t += attr + '<br>';
|
||||
});
|
||||
}
|
||||
return t;
|
||||
}} (interval)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
for (var i = 0; i < main_data.frames.length; ++i)
|
||||
{
|
||||
var frame = main_data.frames[i];
|
||||
|
||||
if (frame.t0 < tmin || frame.t0 > tmax)
|
||||
continue;
|
||||
|
||||
var x = Math.floor(time_to_x(frame.t0));
|
||||
|
||||
ctx.save();
|
||||
ctx.lineWidth = 3;
|
||||
ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x+0.5, 0);
|
||||
ctx.lineTo(x+0.5, canvas.height);
|
||||
ctx.stroke();
|
||||
ctx.fillText(((frame.t1 - frame.t0) * 1000).toFixed(0)+'ms', x+2, padding_top - 24);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
if (zoom)
|
||||
{
|
||||
var x0 = time_to_x(zoom.tmin);
|
||||
var x1 = time_to_x(zoom.tmax);
|
||||
ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)';
|
||||
ctx.fillStyle = 'rgba(128, 128, 255, 0.2)';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x0+0.5, 0.5);
|
||||
ctx.lineTo(x1+0.5, 0.5);
|
||||
ctx.lineTo(x1+0.5 + 4, canvas.height-0.5);
|
||||
ctx.lineTo(x0+0.5 - 4, canvas.height-0.5);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
outInterface.display_hierarchy = display_hierarchy;
|
||||
|
||||
function set_frames_zoom_handlers(report, canvas0)
|
||||
{
|
||||
function do_zoom(report, event)
|
||||
{
|
||||
var zdata = canvas0._zoomData;
|
||||
|
||||
var relativeX = event.pageX - this.offsetLeft;
|
||||
var relativeY = event.pageY - this.offsetTop;
|
||||
|
||||
var width = relativeY / canvas0.height;
|
||||
width = width*width;
|
||||
width *= zdata.x_to_t(canvas0.width)/10;
|
||||
|
||||
var tavg = zdata.x_to_t(relativeX);
|
||||
var tmax = tavg + width/2;
|
||||
var tmin = tavg - width/2;
|
||||
var range = {'tmin': tmin, 'tmax': tmax};
|
||||
update_display(report, range);
|
||||
}
|
||||
|
||||
$(canvas0).unbind();
|
||||
$(canvas0).mousedown(function(event)
|
||||
{
|
||||
mouse_is_down = canvas0;
|
||||
do_zoom.call(this, report, event);
|
||||
});
|
||||
$(canvas0).mouseup(function(event)
|
||||
{
|
||||
mouse_is_down = null;
|
||||
});
|
||||
$(canvas0).mousemove(function(event)
|
||||
{
|
||||
if (mouse_is_down)
|
||||
do_zoom.call(this, report, event);
|
||||
});
|
||||
}
|
||||
|
||||
function set_zoom_handlers(main_data, data, canvas0, canvas1)
|
||||
{
|
||||
function do_zoom(event)
|
||||
{
|
||||
var hdata = canvas0._hierarchyData;
|
||||
|
||||
function x_to_time(x)
|
||||
{
|
||||
return hdata.tmin + x * (hdata.tmax - hdata.tmin) / canvas0.width;
|
||||
}
|
||||
|
||||
var relativeX = event.pageX - this.offsetLeft;
|
||||
var relativeY = (event.pageY + this.offsetTop) / canvas0.height;
|
||||
relativeY = relativeY - 0.5;
|
||||
relativeY *= 5;
|
||||
relativeY *= relativeY;
|
||||
var width = relativeY / canvas0.height;
|
||||
width = width*width;
|
||||
width = 3 + width * x_to_time(canvas0.width)/10;
|
||||
var zoom = { tmin: x_to_time(relativeX-width/2), tmax: x_to_time(relativeX+width/2) };
|
||||
display_hierarchy(main_data, data, canvas0, hdata.range, zoom);
|
||||
display_hierarchy(main_data, data, canvas1, zoom, undefined);
|
||||
set_tooltip_handlers(canvas1);
|
||||
}
|
||||
|
||||
$(canvas0).mousedown(function(event)
|
||||
{
|
||||
mouse_is_down = canvas0;
|
||||
do_zoom.call(this, event);
|
||||
});
|
||||
$(canvas0).mouseup(function(event)
|
||||
{
|
||||
mouse_is_down = null;
|
||||
});
|
||||
$(canvas0).mousemove(function(event)
|
||||
{
|
||||
if (mouse_is_down)
|
||||
do_zoom.call(this, event);
|
||||
});
|
||||
}
|
||||
|
||||
return outInterface;
|
||||
// Copyright (c) 2016 Wildfire Games
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Handles the drawing of a report
|
||||
|
||||
var g_report_draw = (function()
|
||||
{
|
||||
var outInterface = {};
|
||||
|
||||
var mouse_is_down = null;
|
||||
|
||||
function rebuild_canvases(raw_data)
|
||||
{
|
||||
g_canvas = {};
|
||||
|
||||
g_canvas.canvas_frames = $('<canvas width="1600" height="128"></canvas>').get(0);
|
||||
g_canvas.threads = {};
|
||||
|
||||
for (var thread = 0; thread < raw_data.threads.length; thread++)
|
||||
g_canvas.threads[thread] = $('<canvas width="1600" height="128"></canvas>').get(0);
|
||||
|
||||
g_canvas.canvas_zoom = $('<canvas width="1600" height="192"></canvas>').get(0);
|
||||
g_canvas.text_output = $('<pre></pre>').get(0);
|
||||
|
||||
$('#timelines').empty();
|
||||
$('#timelines').append("<h3>Main thread frames</h3>");
|
||||
$('#timelines').append(g_canvas.canvas_frames);
|
||||
for (var thread = 0; thread < raw_data.threads.length; thread++)
|
||||
{
|
||||
$('#timelines').append("<h3>" + raw_data.threads[thread].name + "</h3>");
|
||||
$('#timelines').append($(g_canvas.threads[thread]));
|
||||
}
|
||||
|
||||
$('#timelines').append("<h3>Zoomed frames</h3>");
|
||||
$('#timelines').append(g_canvas.canvas_zoom);
|
||||
$('#timelines').append(g_canvas.text_output);
|
||||
}
|
||||
|
||||
function update_display(report, range)
|
||||
{
|
||||
let data = report.data();
|
||||
let raw_data = report.raw_data();
|
||||
let main_data = data.threads[g_main_thread];
|
||||
|
||||
rebuild_canvases(raw_data);
|
||||
|
||||
if (range.seconds)
|
||||
{
|
||||
range.tmax = main_data.frames[main_data.frames.length-1].t1;
|
||||
range.tmin = main_data.frames[main_data.frames.length-1].t1-range.seconds;
|
||||
}
|
||||
else if (range.frames)
|
||||
{
|
||||
range.tmax = main_data.frames[main_data.frames.length-1].t1;
|
||||
range.tmin = main_data.frames[main_data.frames.length-1-range.frames].t0;
|
||||
}
|
||||
|
||||
$(g_canvas.text_output).empty();
|
||||
|
||||
display_frames(data.threads[g_main_thread], g_canvas.canvas_frames, range);
|
||||
display_events(data.threads[g_main_thread], g_canvas.canvas_frames, range);
|
||||
|
||||
set_frames_zoom_handlers(report, g_canvas.canvas_frames);
|
||||
set_tooltip_handlers(g_canvas.canvas_frames);
|
||||
|
||||
$(g_canvas.canvas_zoom).unbind();
|
||||
|
||||
set_zoom_handlers(data.threads[g_main_thread], data.threads[g_main_thread], g_canvas.threads[g_main_thread], g_canvas.canvas_zoom);
|
||||
set_tooltip_handlers(data.canvas_zoom);
|
||||
|
||||
for (var i = 0; i < data.threads.length; i++)
|
||||
{
|
||||
$(g_canvas.threads[i]).unbind();
|
||||
|
||||
let events = slice_intervals(data.threads[i], range);
|
||||
|
||||
display_hierarchy(data.threads[i], events, g_canvas.threads[i], {});
|
||||
set_zoom_handlers(data.threads[i], events, g_canvas.threads[i], g_canvas.canvas_zoom);
|
||||
set_tooltip_handlers(g_canvas.threads[i]);
|
||||
};
|
||||
}
|
||||
outInterface.update_display = update_display;
|
||||
|
||||
function display_frames(data, canvas, range)
|
||||
{
|
||||
canvas._tooltips = [];
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.save();
|
||||
|
||||
var xpadding = 8;
|
||||
var padding_top = 40;
|
||||
var width = canvas.width - xpadding*2;
|
||||
var height = canvas.height - padding_top - 4;
|
||||
|
||||
var tmin = data.tmin;
|
||||
var tmax = data.tmax;
|
||||
var dx = width / (tmax-tmin);
|
||||
|
||||
canvas._zoomData = {
|
||||
'x_to_t': x => tmin + (x - xpadding) / dx,
|
||||
't_to_x': t => (t - tmin) * dx + xpadding
|
||||
};
|
||||
|
||||
// log 100 scale, skip < 15 ms (60fps)
|
||||
var scale = x => 1 - Math.max(0, Math.log(1 + (x-15)/10) / Math.log(100));
|
||||
|
||||
ctx.strokeStyle = 'rgb(0, 0, 0)';
|
||||
ctx.fillStyle = 'rgb(255, 255, 255)';
|
||||
for (var i = 0; i < data.frames.length; ++i)
|
||||
{
|
||||
var frame = data.frames[i];
|
||||
|
||||
var duration = frame.t1 - frame.t0;
|
||||
var x0 = xpadding + dx*(frame.t0 - tmin);
|
||||
var x1 = x0 + dx*duration;
|
||||
var y1 = canvas.height;
|
||||
var y0 = y1 * scale(duration*1000);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.rect(x0, y0, x1-x0, y1-y0);
|
||||
ctx.stroke();
|
||||
|
||||
canvas._tooltips.push({
|
||||
'x0': x0, 'x1': x1,
|
||||
'y0': y0, 'y1': y1,
|
||||
'text': function(frame, duration) { return function() {
|
||||
var t = '<b>Frame</b><br>';
|
||||
t += 'Length: ' + time_label(duration) + '<br>';
|
||||
if (frame.attrs)
|
||||
{
|
||||
frame.attrs.forEach(function(attr)
|
||||
{
|
||||
t += attr + '<br>';
|
||||
});
|
||||
}
|
||||
return t;
|
||||
}} (frame, duration)
|
||||
});
|
||||
}
|
||||
|
||||
[16, 33, 200, 500].forEach(function(t)
|
||||
{
|
||||
var y1 = canvas.height;
|
||||
var y0 = y1 * scale(t);
|
||||
var y = Math.floor(y0) + 0.5;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(xpadding, y);
|
||||
ctx.lineTo(canvas.width - xpadding, y);
|
||||
ctx.strokeStyle = 'rgb(255, 0, 0)';
|
||||
ctx.stroke();
|
||||
ctx.fillStyle = 'rgb(255, 0, 0)';
|
||||
ctx.fillText(t+'ms', 0, y-2);
|
||||
});
|
||||
|
||||
ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)';
|
||||
ctx.fillStyle = 'rgba(128, 128, 255, 0.2)';
|
||||
ctx.beginPath();
|
||||
ctx.rect(xpadding + dx*(range.tmin - tmin), 0, dx*(range.tmax - range.tmin), canvas.height);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
outInterface.display_frames = display_frames;
|
||||
|
||||
function display_events(data, canvas)
|
||||
{
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
|
||||
var x_to_time = canvas._zoomData.x_to_t;
|
||||
var time_to_x = canvas._zoomData.t_to_x;
|
||||
|
||||
for (var i = 0; i < data.events.length; ++i)
|
||||
{
|
||||
var event = data.events[i];
|
||||
|
||||
if (event.id == '__framestart')
|
||||
continue;
|
||||
|
||||
if (event.id == 'gui event' && event.attrs && event.attrs[0] == 'type: mousemove')
|
||||
continue;
|
||||
|
||||
var x = time_to_x(event.t);
|
||||
var y = 32;
|
||||
|
||||
if (x < 2)
|
||||
continue;
|
||||
|
||||
var x0 = x;
|
||||
var x1 = x;
|
||||
var y0 = y-4;
|
||||
var y1 = y+4;
|
||||
|
||||
ctx.strokeStyle = 'rgb(255, 0, 0)';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x0, y0);
|
||||
ctx.lineTo(x1, y1);
|
||||
ctx.stroke();
|
||||
canvas._tooltips.push({
|
||||
'x0': x0, 'x1': x1,
|
||||
'y0': y0, 'y1': y1,
|
||||
'text': function(event) { return function() {
|
||||
var t = '<b>' + event.id + '</b><br>';
|
||||
if (event.attrs)
|
||||
{
|
||||
event.attrs.forEach(function(attr) {
|
||||
t += attr + '<br>';
|
||||
});
|
||||
}
|
||||
return t;
|
||||
}} (event)
|
||||
});
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
outInterface.display_events = display_events;
|
||||
|
||||
function display_hierarchy(main_data, data, canvas, range, zoom)
|
||||
{
|
||||
canvas._tooltips = [];
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.save();
|
||||
|
||||
ctx.font = '12px sans-serif';
|
||||
|
||||
var xpadding = 8;
|
||||
var padding_top = 40;
|
||||
var width = canvas.width - xpadding*2;
|
||||
var height = canvas.height - padding_top - 4;
|
||||
|
||||
var tmin, tmax, start, end;
|
||||
|
||||
if (range.tmin)
|
||||
{
|
||||
tmin = range.tmin;
|
||||
tmax = range.tmax;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmin = data.tmin;
|
||||
tmax = data.tmax;
|
||||
}
|
||||
|
||||
canvas._hierarchyData = { 'range': range, 'tmin': tmin, 'tmax': tmax };
|
||||
|
||||
function time_to_x(t)
|
||||
{
|
||||
return xpadding + (t - tmin) / (tmax - tmin) * width;
|
||||
}
|
||||
|
||||
function x_to_time(x)
|
||||
{
|
||||
return tmin + (x - xpadding) * (tmax - tmin) / width;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.textAlign = 'center';
|
||||
ctx.strokeStyle = 'rgb(192, 192, 192)';
|
||||
ctx.beginPath();
|
||||
var precision = -3;
|
||||
while ((tmax-tmin)*Math.pow(10, 3+precision) < 25)
|
||||
++precision;
|
||||
if (precision > 10)
|
||||
precision = 10;
|
||||
if (precision < 0)
|
||||
precision = 0;
|
||||
var ticks_per_sec = Math.pow(10, 3+precision);
|
||||
var major_tick_interval = 5;
|
||||
|
||||
for (var i = 0; i < (tmax-tmin)*ticks_per_sec; ++i)
|
||||
{
|
||||
var major = (i % major_tick_interval == 0);
|
||||
var x = Math.floor(time_to_x(tmin + i/ticks_per_sec));
|
||||
ctx.moveTo(x-0.5, padding_top - (major ? 4 : 2));
|
||||
ctx.lineTo(x-0.5, padding_top + height);
|
||||
if (major)
|
||||
ctx.fillText((i*1000/ticks_per_sec).toFixed(precision), x, padding_top - 8);
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
var BAR_SPACING = 16;
|
||||
|
||||
for (var i = 0; i < data.intervals.length; ++i)
|
||||
{
|
||||
var interval = data.intervals[i];
|
||||
|
||||
if (interval.tmax <= tmin || interval.tmin > tmax)
|
||||
continue;
|
||||
|
||||
var x0 = Math.floor(time_to_x(interval.t0));
|
||||
var x1 = Math.floor(time_to_x(interval.t1));
|
||||
|
||||
if (x1-x0 < 1)
|
||||
continue;
|
||||
|
||||
var y0 = padding_top + interval.depth * BAR_SPACING;
|
||||
var y1 = y0 + BAR_SPACING;
|
||||
|
||||
var label = interval.id;
|
||||
if (interval.attrs)
|
||||
{
|
||||
if (/^\d+$/.exec(interval.attrs[0]))
|
||||
label += ' ' + interval.attrs[0];
|
||||
else
|
||||
label += ' [...]';
|
||||
}
|
||||
|
||||
ctx.fillStyle = interval.colour;
|
||||
ctx.strokeStyle = 'black';
|
||||
ctx.beginPath();
|
||||
ctx.rect(x0-0.5, y0-0.5, x1-x0, y1-y0);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.fillText(label, x0+2, y0+BAR_SPACING-4, Math.max(1, x1-x0-4));
|
||||
|
||||
canvas._tooltips.push({
|
||||
'x0': x0, 'x1': x1,
|
||||
'y0': y0, 'y1': y1,
|
||||
'text': function(interval) { return function() {
|
||||
var t = '<b>' + interval.id + '</b><br>';
|
||||
t += 'Length: ' + time_label(interval.duration) + '<br>';
|
||||
if (interval.attrs)
|
||||
{
|
||||
interval.attrs.forEach(function(attr) {
|
||||
t += attr + '<br>';
|
||||
});
|
||||
}
|
||||
return t;
|
||||
}} (interval)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
for (var i = 0; i < main_data.frames.length; ++i)
|
||||
{
|
||||
var frame = main_data.frames[i];
|
||||
|
||||
if (frame.t0 < tmin || frame.t0 > tmax)
|
||||
continue;
|
||||
|
||||
var x = Math.floor(time_to_x(frame.t0));
|
||||
|
||||
ctx.save();
|
||||
ctx.lineWidth = 3;
|
||||
ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x+0.5, 0);
|
||||
ctx.lineTo(x+0.5, canvas.height);
|
||||
ctx.stroke();
|
||||
ctx.fillText(((frame.t1 - frame.t0) * 1000).toFixed(0)+'ms', x+2, padding_top - 24);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
if (zoom)
|
||||
{
|
||||
var x0 = time_to_x(zoom.tmin);
|
||||
var x1 = time_to_x(zoom.tmax);
|
||||
ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)';
|
||||
ctx.fillStyle = 'rgba(128, 128, 255, 0.2)';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x0+0.5, 0.5);
|
||||
ctx.lineTo(x1+0.5, 0.5);
|
||||
ctx.lineTo(x1+0.5 + 4, canvas.height-0.5);
|
||||
ctx.lineTo(x0+0.5 - 4, canvas.height-0.5);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
outInterface.display_hierarchy = display_hierarchy;
|
||||
|
||||
function set_frames_zoom_handlers(report, canvas0)
|
||||
{
|
||||
function do_zoom(report, event)
|
||||
{
|
||||
var zdata = canvas0._zoomData;
|
||||
|
||||
var relativeX = event.pageX - this.offsetLeft;
|
||||
var relativeY = event.pageY - this.offsetTop;
|
||||
|
||||
var width = relativeY / canvas0.height;
|
||||
width = width*width;
|
||||
width *= zdata.x_to_t(canvas0.width)/10;
|
||||
|
||||
var tavg = zdata.x_to_t(relativeX);
|
||||
var tmax = tavg + width/2;
|
||||
var tmin = tavg - width/2;
|
||||
var range = {'tmin': tmin, 'tmax': tmax};
|
||||
update_display(report, range);
|
||||
}
|
||||
|
||||
$(canvas0).unbind();
|
||||
$(canvas0).mousedown(function(event)
|
||||
{
|
||||
mouse_is_down = canvas0;
|
||||
do_zoom.call(this, report, event);
|
||||
});
|
||||
$(canvas0).mouseup(function(event)
|
||||
{
|
||||
mouse_is_down = null;
|
||||
});
|
||||
$(canvas0).mousemove(function(event)
|
||||
{
|
||||
if (mouse_is_down)
|
||||
do_zoom.call(this, report, event);
|
||||
});
|
||||
}
|
||||
|
||||
function set_zoom_handlers(main_data, data, canvas0, canvas1)
|
||||
{
|
||||
function do_zoom(event)
|
||||
{
|
||||
var hdata = canvas0._hierarchyData;
|
||||
|
||||
function x_to_time(x)
|
||||
{
|
||||
return hdata.tmin + x * (hdata.tmax - hdata.tmin) / canvas0.width;
|
||||
}
|
||||
|
||||
var relativeX = event.pageX - this.offsetLeft;
|
||||
var relativeY = (event.pageY + this.offsetTop) / canvas0.height;
|
||||
relativeY = relativeY - 0.5;
|
||||
relativeY *= 5;
|
||||
relativeY *= relativeY;
|
||||
var width = relativeY / canvas0.height;
|
||||
width = width*width;
|
||||
width = 3 + width * x_to_time(canvas0.width)/10;
|
||||
var zoom = { tmin: x_to_time(relativeX-width/2), tmax: x_to_time(relativeX+width/2) };
|
||||
display_hierarchy(main_data, data, canvas0, hdata.range, zoom);
|
||||
display_hierarchy(main_data, data, canvas1, zoom, undefined);
|
||||
set_tooltip_handlers(canvas1);
|
||||
}
|
||||
|
||||
$(canvas0).mousedown(function(event)
|
||||
{
|
||||
mouse_is_down = canvas0;
|
||||
do_zoom.call(this, event);
|
||||
});
|
||||
$(canvas0).mouseup(function(event)
|
||||
{
|
||||
mouse_is_down = null;
|
||||
});
|
||||
$(canvas0).mousemove(function(event)
|
||||
{
|
||||
if (mouse_is_down)
|
||||
do_zoom.call(this, event);
|
||||
});
|
||||
}
|
||||
|
||||
return outInterface;
|
||||
})();
|
@ -1,91 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>0 A.D. profiler UI</title>
|
||||
<script src="jquery-1.6.4.js"></script>
|
||||
<script src="utilities.js"></script>
|
||||
<script src="ReportDraw.js"></script>
|
||||
<script src="Profiler2Report.js"></script>
|
||||
<script src="profiler2.js"></script>
|
||||
<style>
|
||||
@keyframes rotate
|
||||
{
|
||||
0% {transform:translateY(-50%) rotate(0deg);}
|
||||
100% {transform:translateY(-50%) rotate(360deg);}
|
||||
}
|
||||
html { font-size: 14px; font-family: "Source Code Pro", monospace; padding:10px;}
|
||||
* { box-sizing:border-box; margin:0; padding: 0; }
|
||||
canvas { border: 1px #ddd solid; display:block;}
|
||||
header h1 { font-size:2em; }
|
||||
header nav { height:50px; margin:5px; border:1px solid gray; }
|
||||
header nav p { display:inline-block; height:100%; padding: 15px 10px; background:#aaa; cursor:pointer; border-right:1px solid gray; position:relative;}
|
||||
header nav p.loading { background:#ccf; cursor:progress; padding-right:15px; }
|
||||
header nav p.loading:after { content:""; position:absolute; right:5px; top:50%; transform:translateY(-50%); height:5px;width:5px;background:#ccc;border:1px solid gray; animation:rotate 2s infinite; }
|
||||
header nav p.fail { background:#faa;cursor:not-allowed;}
|
||||
header nav p.active { cursor:pointer; background:#eee; box-shadow: 0px 0px 2px 0px rgba(0,0,0,0.5);font-weight:bold;}
|
||||
#tooltip { background: #ffd; padding: 4px; font: 12px sans-serif; border: 1px #880 solid; }
|
||||
#tooltip.long { -moz-column-count: 2; }
|
||||
#choices { display: flex; flex-wrap:wrap;}
|
||||
#choices section { position:relative;}
|
||||
#choices section h2 { height:25px; }
|
||||
#choices section aside { width:200px; position:absolute; top: 0px; right : 1px; border-left:1px solid gray;border-bottom:1px solid gray; background:rgba(255,255,255,0.5);}
|
||||
#choices section aside:hover { opacity:0.2; }
|
||||
#choices section aside p { margin:4px 0px 4px 2px; border-left:15px solid; padding-left: 5px; font-size:0.8rem; }
|
||||
#choices section input { height:25px; vertical-align:top; }
|
||||
#choices section label { line-height:25px; padding-left:5px; }
|
||||
#choices nav { flex-shrink:0; width:300px; height:600px; overflow-y: scroll;}
|
||||
#choices nav p { margin:2px; cursor:pointer;}
|
||||
#choices nav p:hover { background:#eee;}
|
||||
#choices nav p.active { background:#fee;}
|
||||
#comparison { min-width:400px; }
|
||||
#comparison table { border-collapse:collapse; margin: 20px 10px;}
|
||||
#comparison td,#comparison th { min-width:80px;height:25px;text-align: center;}
|
||||
#comparison th { border: 1px solid #888; background:#eee; }
|
||||
#comparison td { border: 1px solid #bbb; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button onclick="save_as_file()">Save Live Report to file</button>
|
||||
|
||||
<header>
|
||||
<h1>Open reports</h1>
|
||||
<p>Use the input field below to load a new report (from JSON)</p>
|
||||
<input type="file" id="report_load_input" name="files[]" />
|
||||
<nav></nav>
|
||||
</header>
|
||||
|
||||
<p>Click on the following timelines to zoom.</p>
|
||||
</a><div id="timelines"></div>
|
||||
|
||||
<div id="choices">
|
||||
<div style="width:100%">
|
||||
<h1>Analysis</h1>
|
||||
<p>Click on any of the event names in "choices" to see more details about them. Load more reports to compare.</p>
|
||||
</div>
|
||||
<section id="frequency_graph">
|
||||
<h2>Frequency Graph</h2>
|
||||
<input type="checkbox" id="fulln" name="fulln" value="fulln" onchange="update_analysis()"><label for="fulln">Show for all frames</label>
|
||||
<div style="position:relative">
|
||||
<aside></aside>
|
||||
<canvas id="canvas_frequency" width="600" height="600"></canvas
|
||||
html5 > </div>
|
||||
</section>
|
||||
<section id="history_graph">
|
||||
<h2>Frame-by-Frame Graph</h2>
|
||||
<input type="range" id="smooth" name="smooth" onchange="update_analysis()" min="0" max="10" step="1" value="3"/><label for="smooth">Degree of smoothing</label>
|
||||
<div style="position:relative">
|
||||
<aside></aside>
|
||||
<div style="width:602px;overflow:auto;"><canvas id="canvas_history" width="600" height="600"></canvas></div>
|
||||
</div>
|
||||
</section>
|
||||
<nav>
|
||||
<h3>Choices</h3>
|
||||
</nav>
|
||||
<div id="comparison">
|
||||
<h3>Report Comparison</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tooltip" style="position: absolute; visibility: hidden"></div>
|
||||
|
||||
<pre id="debug"></pre>
|
||||
</body>
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>0 A.D. profiler UI</title>
|
||||
<script src="jquery-1.6.4.js"></script>
|
||||
<script src="utilities.js"></script>
|
||||
<script src="ReportDraw.js"></script>
|
||||
<script src="Profiler2Report.js"></script>
|
||||
<script src="profiler2.js"></script>
|
||||
<style>
|
||||
@keyframes rotate
|
||||
{
|
||||
0% {transform:translateY(-50%) rotate(0deg);}
|
||||
100% {transform:translateY(-50%) rotate(360deg);}
|
||||
}
|
||||
html { font-size: 14px; font-family: "Source Code Pro", monospace; padding:10px;}
|
||||
* { box-sizing:border-box; margin:0; padding: 0; }
|
||||
canvas { border: 1px #ddd solid; display:block;}
|
||||
header h1 { font-size:2em; }
|
||||
header nav { height:50px; margin:5px; border:1px solid gray; }
|
||||
header nav p { display:inline-block; height:100%; padding: 15px 10px; background:#aaa; cursor:pointer; border-right:1px solid gray; position:relative;}
|
||||
header nav p.loading { background:#ccf; cursor:progress; padding-right:15px; }
|
||||
header nav p.loading:after { content:""; position:absolute; right:5px; top:50%; transform:translateY(-50%); height:5px;width:5px;background:#ccc;border:1px solid gray; animation:rotate 2s infinite; }
|
||||
header nav p.fail { background:#faa;cursor:not-allowed;}
|
||||
header nav p.active { cursor:pointer; background:#eee; box-shadow: 0px 0px 2px 0px rgba(0,0,0,0.5);font-weight:bold;}
|
||||
#tooltip { background: #ffd; padding: 4px; font: 12px sans-serif; border: 1px #880 solid; }
|
||||
#tooltip.long { -moz-column-count: 2; }
|
||||
#choices { display: flex; flex-wrap:wrap;}
|
||||
#choices section { position:relative;}
|
||||
#choices section h2 { height:25px; }
|
||||
#choices section aside { width:200px; position:absolute; top: 0px; right : 1px; border-left:1px solid gray;border-bottom:1px solid gray; background:rgba(255,255,255,0.5);}
|
||||
#choices section aside:hover { opacity:0.2; }
|
||||
#choices section aside p { margin:4px 0px 4px 2px; border-left:15px solid; padding-left: 5px; font-size:0.8rem; }
|
||||
#choices section input { height:25px; vertical-align:top; }
|
||||
#choices section label { line-height:25px; padding-left:5px; }
|
||||
#choices nav { flex-shrink:0; width:300px; height:600px; overflow-y: scroll;}
|
||||
#choices nav p { margin:2px; cursor:pointer;}
|
||||
#choices nav p:hover { background:#eee;}
|
||||
#choices nav p.active { background:#fee;}
|
||||
#comparison { min-width:400px; }
|
||||
#comparison table { border-collapse:collapse; margin: 20px 10px;}
|
||||
#comparison td,#comparison th { min-width:80px;height:25px;text-align: center;}
|
||||
#comparison th { border: 1px solid #888; background:#eee; }
|
||||
#comparison td { border: 1px solid #bbb; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button onclick="save_as_file()">Save Live Report to file</button>
|
||||
|
||||
<header>
|
||||
<h1>Open reports</h1>
|
||||
<p>Use the input field below to load a new report (from JSON)</p>
|
||||
<input type="file" id="report_load_input" name="files[]" />
|
||||
<nav></nav>
|
||||
</header>
|
||||
|
||||
<p>Click on the following timelines to zoom.</p>
|
||||
</a><div id="timelines"></div>
|
||||
|
||||
<div id="choices">
|
||||
<div style="width:100%">
|
||||
<h1>Analysis</h1>
|
||||
<p>Click on any of the event names in "choices" to see more details about them. Load more reports to compare.</p>
|
||||
</div>
|
||||
<section id="frequency_graph">
|
||||
<h2>Frequency Graph</h2>
|
||||
<input type="checkbox" id="fulln" name="fulln" value="fulln" onchange="update_analysis()"><label for="fulln">Show for all frames</label>
|
||||
<div style="position:relative">
|
||||
<aside></aside>
|
||||
<canvas id="canvas_frequency" width="600" height="600"></canvas
|
||||
html5 > </div>
|
||||
</section>
|
||||
<section id="history_graph">
|
||||
<h2>Frame-by-Frame Graph</h2>
|
||||
<input type="range" id="smooth" name="smooth" onchange="update_analysis()" min="0" max="10" step="1" value="3"/><label for="smooth">Degree of smoothing</label>
|
||||
<div style="position:relative">
|
||||
<aside></aside>
|
||||
<div style="width:602px;overflow:auto;"><canvas id="canvas_history" width="600" height="600"></canvas></div>
|
||||
</div>
|
||||
</section>
|
||||
<nav>
|
||||
<h3>Choices</h3>
|
||||
</nav>
|
||||
<div id="comparison">
|
||||
<h3>Report Comparison</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tooltip" style="position: absolute; visibility: hidden"></div>
|
||||
|
||||
<pre id="debug"></pre>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
@ -1,192 +1,192 @@
|
||||
// Copyright (c) 2016 Wildfire Games
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Various functions used by several of the tiles.
|
||||
|
||||
function hslToRgb(h, s, l, a)
|
||||
{
|
||||
var r, g, b;
|
||||
|
||||
if (s == 0)
|
||||
{
|
||||
r = g = b = l;
|
||||
}
|
||||
else
|
||||
{
|
||||
function hue2rgb(p, q, t)
|
||||
{
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1/6) return p + (q - p) * 6 * t;
|
||||
if (t < 1/2) return q;
|
||||
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1/3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1/3);
|
||||
}
|
||||
|
||||
return 'rgba(' + Math.floor(r * 255) + ',' + Math.floor(g * 255) + ',' + Math.floor(b * 255) + ',' + a + ')';
|
||||
}
|
||||
|
||||
function new_colour(id)
|
||||
{
|
||||
var hs = [0, 1/3, 2/3, 1/4, 2/4, 3/4, 1/5, 3/5, 2/5, 4/5];
|
||||
var ss = [1, 0.5];
|
||||
var ls = [0.8, 0.6, 0.9, 0.7];
|
||||
return hslToRgb(hs[id % hs.length], ss[Math.floor(id / hs.length) % ss.length], ls[Math.floor(id / (hs.length*ss.length)) % ls.length], 1);
|
||||
}
|
||||
|
||||
function graph_colour(id)
|
||||
{
|
||||
var hs = [0, 1/3, 2/3, 2/4, 3/4, 1/5, 3/5, 2/5, 4/5];
|
||||
return hslToRgb(hs[id % hs.length], 0.7, 0.5, 1);
|
||||
}
|
||||
|
||||
function concat_events(data)
|
||||
{
|
||||
var events = [];
|
||||
data.events.forEach(function(ev) {
|
||||
ev.pop(); // remove the dummy null markers
|
||||
Array.prototype.push.apply(events, ev);
|
||||
});
|
||||
return events;
|
||||
}
|
||||
|
||||
function time_label(t, precision = 2)
|
||||
{
|
||||
if (t < 0)
|
||||
return "-" + time_label(-t, precision);
|
||||
if (t > 1e-3)
|
||||
return (t * 1e3).toFixed(precision) + 'ms';
|
||||
else
|
||||
return (t * 1e6).toFixed(precision) + 'us';
|
||||
}
|
||||
|
||||
function slice_intervals(data, range)
|
||||
{
|
||||
if (!data.intervals.length)
|
||||
return {"tmin":0,"tmax":0,"intervals":[]};
|
||||
|
||||
var tmin = 0;
|
||||
var tmax = 0;
|
||||
if (range.seconds && data.frames.length)
|
||||
{
|
||||
tmax = data.frames[data.frames.length-1].t1;
|
||||
tmin = data.frames[data.frames.length-1].t1-range.seconds;
|
||||
}
|
||||
else if (range.frames && data.frames.length)
|
||||
{
|
||||
tmax = data.frames[data.frames.length-1].t1;
|
||||
tmin = data.frames[data.frames.length-1-range.frames].t0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmax = range.tmax;
|
||||
tmin = range.tmin;
|
||||
}
|
||||
var events = { "tmin" : tmin, "tmax" : tmax, "intervals" : [] };
|
||||
for (let itv in data.intervals)
|
||||
{
|
||||
let interval = data.intervals[itv];
|
||||
if (interval.t1 > tmin && interval.t0 < tmax)
|
||||
events.intervals.push(interval);
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
function smooth_1D(array, i, distance)
|
||||
{
|
||||
let value = 0;
|
||||
let total = 0;
|
||||
for (let j = i - distance; j <= i + distance; j++)
|
||||
{
|
||||
value += array[j]*(1+distance*distance - (j-i)*(j-i) );
|
||||
total += (1+distance*distance - (j-i)*(j-i) );
|
||||
}
|
||||
return value/total;
|
||||
}
|
||||
|
||||
function smooth_1D_array(array, distance)
|
||||
{
|
||||
let copied = array.slice(0);
|
||||
for (let i =0; i < array.length; ++i)
|
||||
{
|
||||
let value = 0;
|
||||
let total = 0;
|
||||
for (let j = i - distance; j <= i + distance; j++)
|
||||
{
|
||||
value += array[j]*(1+distance*distance - (j-i)*(j-i) );
|
||||
total += (1+distance*distance - (j-i)*(j-i) );
|
||||
}
|
||||
copied[i] = value/total;
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
function set_tooltip_handlers(canvas)
|
||||
{
|
||||
function do_tooltip(event)
|
||||
{
|
||||
var tooltips = canvas._tooltips;
|
||||
if (!tooltips)
|
||||
return;
|
||||
|
||||
var relativeX = event.pageX - this.getBoundingClientRect().left - window.scrollX;
|
||||
var relativeY = event.pageY - this.getBoundingClientRect().top - window.scrollY;
|
||||
|
||||
var text = undefined;
|
||||
for (var i = 0; i < tooltips.length; ++i)
|
||||
{
|
||||
var t = tooltips[i];
|
||||
if (t.x0-1 <= relativeX && relativeX <= t.x1+1 && t.y0 <= relativeY && relativeY <= t.y1)
|
||||
{
|
||||
text = t.text();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (text)
|
||||
{
|
||||
if (text.length > 512)
|
||||
$('#tooltip').addClass('long');
|
||||
else
|
||||
$('#tooltip').removeClass('long');
|
||||
$('#tooltip').css('left', (event.pageX+16)+'px');
|
||||
$('#tooltip').css('top', (event.pageY+8)+'px');
|
||||
$('#tooltip').html(text);
|
||||
$('#tooltip').css('visibility', 'visible');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#tooltip').css('visibility', 'hidden');
|
||||
}
|
||||
}
|
||||
|
||||
$(canvas).mousemove(function(event) {
|
||||
do_tooltip.call(this, event);
|
||||
});
|
||||
$(canvas).mouseleave(function(event) {
|
||||
$('#tooltip').css('visibility', 'hidden');
|
||||
});
|
||||
// Copyright (c) 2016 Wildfire Games
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Various functions used by several of the tiles.
|
||||
|
||||
function hslToRgb(h, s, l, a)
|
||||
{
|
||||
var r, g, b;
|
||||
|
||||
if (s == 0)
|
||||
{
|
||||
r = g = b = l;
|
||||
}
|
||||
else
|
||||
{
|
||||
function hue2rgb(p, q, t)
|
||||
{
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1/6) return p + (q - p) * 6 * t;
|
||||
if (t < 1/2) return q;
|
||||
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1/3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1/3);
|
||||
}
|
||||
|
||||
return 'rgba(' + Math.floor(r * 255) + ',' + Math.floor(g * 255) + ',' + Math.floor(b * 255) + ',' + a + ')';
|
||||
}
|
||||
|
||||
function new_colour(id)
|
||||
{
|
||||
var hs = [0, 1/3, 2/3, 1/4, 2/4, 3/4, 1/5, 3/5, 2/5, 4/5];
|
||||
var ss = [1, 0.5];
|
||||
var ls = [0.8, 0.6, 0.9, 0.7];
|
||||
return hslToRgb(hs[id % hs.length], ss[Math.floor(id / hs.length) % ss.length], ls[Math.floor(id / (hs.length*ss.length)) % ls.length], 1);
|
||||
}
|
||||
|
||||
function graph_colour(id)
|
||||
{
|
||||
var hs = [0, 1/3, 2/3, 2/4, 3/4, 1/5, 3/5, 2/5, 4/5];
|
||||
return hslToRgb(hs[id % hs.length], 0.7, 0.5, 1);
|
||||
}
|
||||
|
||||
function concat_events(data)
|
||||
{
|
||||
var events = [];
|
||||
data.events.forEach(function(ev) {
|
||||
ev.pop(); // remove the dummy null markers
|
||||
Array.prototype.push.apply(events, ev);
|
||||
});
|
||||
return events;
|
||||
}
|
||||
|
||||
function time_label(t, precision = 2)
|
||||
{
|
||||
if (t < 0)
|
||||
return "-" + time_label(-t, precision);
|
||||
if (t > 1e-3)
|
||||
return (t * 1e3).toFixed(precision) + 'ms';
|
||||
else
|
||||
return (t * 1e6).toFixed(precision) + 'us';
|
||||
}
|
||||
|
||||
function slice_intervals(data, range)
|
||||
{
|
||||
if (!data.intervals.length)
|
||||
return {"tmin":0,"tmax":0,"intervals":[]};
|
||||
|
||||
var tmin = 0;
|
||||
var tmax = 0;
|
||||
if (range.seconds && data.frames.length)
|
||||
{
|
||||
tmax = data.frames[data.frames.length-1].t1;
|
||||
tmin = data.frames[data.frames.length-1].t1-range.seconds;
|
||||
}
|
||||
else if (range.frames && data.frames.length)
|
||||
{
|
||||
tmax = data.frames[data.frames.length-1].t1;
|
||||
tmin = data.frames[data.frames.length-1-range.frames].t0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmax = range.tmax;
|
||||
tmin = range.tmin;
|
||||
}
|
||||
var events = { "tmin" : tmin, "tmax" : tmax, "intervals" : [] };
|
||||
for (let itv in data.intervals)
|
||||
{
|
||||
let interval = data.intervals[itv];
|
||||
if (interval.t1 > tmin && interval.t0 < tmax)
|
||||
events.intervals.push(interval);
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
function smooth_1D(array, i, distance)
|
||||
{
|
||||
let value = 0;
|
||||
let total = 0;
|
||||
for (let j = i - distance; j <= i + distance; j++)
|
||||
{
|
||||
value += array[j]*(1+distance*distance - (j-i)*(j-i) );
|
||||
total += (1+distance*distance - (j-i)*(j-i) );
|
||||
}
|
||||
return value/total;
|
||||
}
|
||||
|
||||
function smooth_1D_array(array, distance)
|
||||
{
|
||||
let copied = array.slice(0);
|
||||
for (let i =0; i < array.length; ++i)
|
||||
{
|
||||
let value = 0;
|
||||
let total = 0;
|
||||
for (let j = i - distance; j <= i + distance; j++)
|
||||
{
|
||||
value += array[j]*(1+distance*distance - (j-i)*(j-i) );
|
||||
total += (1+distance*distance - (j-i)*(j-i) );
|
||||
}
|
||||
copied[i] = value/total;
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
function set_tooltip_handlers(canvas)
|
||||
{
|
||||
function do_tooltip(event)
|
||||
{
|
||||
var tooltips = canvas._tooltips;
|
||||
if (!tooltips)
|
||||
return;
|
||||
|
||||
var relativeX = event.pageX - this.getBoundingClientRect().left - window.scrollX;
|
||||
var relativeY = event.pageY - this.getBoundingClientRect().top - window.scrollY;
|
||||
|
||||
var text = undefined;
|
||||
for (var i = 0; i < tooltips.length; ++i)
|
||||
{
|
||||
var t = tooltips[i];
|
||||
if (t.x0-1 <= relativeX && relativeX <= t.x1+1 && t.y0 <= relativeY && relativeY <= t.y1)
|
||||
{
|
||||
text = t.text();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (text)
|
||||
{
|
||||
if (text.length > 512)
|
||||
$('#tooltip').addClass('long');
|
||||
else
|
||||
$('#tooltip').removeClass('long');
|
||||
$('#tooltip').css('left', (event.pageX+16)+'px');
|
||||
$('#tooltip').css('top', (event.pageY+8)+'px');
|
||||
$('#tooltip').html(text);
|
||||
$('#tooltip').css('visibility', 'visible');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#tooltip').css('visibility', 'hidden');
|
||||
}
|
||||
}
|
||||
|
||||
$(canvas).mousemove(function(event) {
|
||||
do_tooltip.call(this, event);
|
||||
});
|
||||
$(canvas).mouseleave(function(event) {
|
||||
$('#tooltip').css('visibility', 'hidden');
|
||||
});
|
||||
}
|
@ -1,99 +1,99 @@
|
||||
# http://code.djangoproject.com/attachment/ticket/5908/cycle.py
|
||||
|
||||
from django.utils.translation import ungettext, ugettext as _
|
||||
from django.utils.encoding import force_unicode
|
||||
from django import template
|
||||
from django.template import defaultfilters
|
||||
from django.template import Node, Variable
|
||||
from django.conf import settings
|
||||
from itertools import cycle as itertools_cycle
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
|
||||
class SafeCycleNode(Node):
|
||||
def __init__(self, cyclevars, variable_name=None):
|
||||
self.cyclevars = cyclevars
|
||||
self.cycle_iter = itertools_cycle(cyclevars)
|
||||
self.variable_name = variable_name
|
||||
|
||||
def render(self, context):
|
||||
if context.has_key('forloop'):
|
||||
if not context.get(self):
|
||||
context[self] = True
|
||||
self.cycle_iter = itertools_cycle(self.cyclevars)
|
||||
value = self.cycle_iter.next()
|
||||
value = Variable(value).resolve(context)
|
||||
if self.variable_name:
|
||||
context[self.variable_name] = value
|
||||
return value
|
||||
|
||||
|
||||
|
||||
#@register.tag
|
||||
def safe_cycle(parser, token):
|
||||
"""
|
||||
Cycles among the given strings each time this tag is encountered.
|
||||
|
||||
Within a loop, cycles among the given strings each time through
|
||||
the loop::
|
||||
|
||||
{% for o in some_list %}
|
||||
<tr class="{% cycle 'row1' 'row2' %}">
|
||||
...
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
Outside of a loop, give the values a unique name the first time you call
|
||||
it, then use that name each sucessive time through::
|
||||
|
||||
<tr class="{% cycle 'row1' 'row2' 'row3' as rowcolors %}">...</tr>
|
||||
<tr class="{% cycle rowcolors %}">...</tr>
|
||||
<tr class="{% cycle rowcolors %}">...</tr>
|
||||
|
||||
You can use any number of values, seperated by spaces. Commas can also
|
||||
be used to separate values; if a comma is used, the cycle values are
|
||||
interpreted as literal strings.
|
||||
"""
|
||||
|
||||
# Note: This returns the exact same node on each {% cycle name %} call;
|
||||
# that is, the node object returned from {% cycle a b c as name %} and the
|
||||
# one returned from {% cycle name %} are the exact same object. This
|
||||
# shouldn't cause problems (heh), but if it does, now you know.
|
||||
#
|
||||
# Ugly hack warning: this stuffs the named template dict into parser so
|
||||
# that names are only unique within each template (as opposed to using
|
||||
# a global variable, which would make cycle names have to be unique across
|
||||
# *all* templates.
|
||||
|
||||
args = token.split_contents()
|
||||
|
||||
if len(args) < 2:
|
||||
raise TemplateSyntaxError("'cycle' tag requires at least two arguments")
|
||||
|
||||
if ',' in args[1]:
|
||||
# Backwards compatibility: {% cycle a,b %} or {% cycle a,b as foo %}
|
||||
# case.
|
||||
args[1:2] = ['"%s"' % arg for arg in args[1].split(",")]
|
||||
|
||||
if len(args) == 2:
|
||||
# {% cycle foo %} case.
|
||||
name = args[1]
|
||||
if not hasattr(parser, '_namedCycleNodes'):
|
||||
raise TemplateSyntaxError("No named cycles in template."
|
||||
" '%s' is not defined" % name)
|
||||
if not name in parser._namedCycleNodes:
|
||||
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
|
||||
return parser._namedCycleNodes[name]
|
||||
|
||||
if len(args) > 4 and args[-2] == 'as':
|
||||
name = args[-1]
|
||||
node = SafeCycleNode(args[1:-2], name)
|
||||
if not hasattr(parser, '_namedCycleNodes'):
|
||||
parser._namedCycleNodes = {}
|
||||
parser._namedCycleNodes[name] = node
|
||||
else:
|
||||
node = SafeCycleNode(args[1:])
|
||||
return node
|
||||
safe_cycle = register.tag(safe_cycle)
|
||||
# http://code.djangoproject.com/attachment/ticket/5908/cycle.py
|
||||
|
||||
from django.utils.translation import ungettext, ugettext as _
|
||||
from django.utils.encoding import force_unicode
|
||||
from django import template
|
||||
from django.template import defaultfilters
|
||||
from django.template import Node, Variable
|
||||
from django.conf import settings
|
||||
from itertools import cycle as itertools_cycle
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
|
||||
class SafeCycleNode(Node):
|
||||
def __init__(self, cyclevars, variable_name=None):
|
||||
self.cyclevars = cyclevars
|
||||
self.cycle_iter = itertools_cycle(cyclevars)
|
||||
self.variable_name = variable_name
|
||||
|
||||
def render(self, context):
|
||||
if context.has_key('forloop'):
|
||||
if not context.get(self):
|
||||
context[self] = True
|
||||
self.cycle_iter = itertools_cycle(self.cyclevars)
|
||||
value = self.cycle_iter.next()
|
||||
value = Variable(value).resolve(context)
|
||||
if self.variable_name:
|
||||
context[self.variable_name] = value
|
||||
return value
|
||||
|
||||
|
||||
|
||||
#@register.tag
|
||||
def safe_cycle(parser, token):
|
||||
"""
|
||||
Cycles among the given strings each time this tag is encountered.
|
||||
|
||||
Within a loop, cycles among the given strings each time through
|
||||
the loop::
|
||||
|
||||
{% for o in some_list %}
|
||||
<tr class="{% cycle 'row1' 'row2' %}">
|
||||
...
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
Outside of a loop, give the values a unique name the first time you call
|
||||
it, then use that name each sucessive time through::
|
||||
|
||||
<tr class="{% cycle 'row1' 'row2' 'row3' as rowcolors %}">...</tr>
|
||||
<tr class="{% cycle rowcolors %}">...</tr>
|
||||
<tr class="{% cycle rowcolors %}">...</tr>
|
||||
|
||||
You can use any number of values, seperated by spaces. Commas can also
|
||||
be used to separate values; if a comma is used, the cycle values are
|
||||
interpreted as literal strings.
|
||||
"""
|
||||
|
||||
# Note: This returns the exact same node on each {% cycle name %} call;
|
||||
# that is, the node object returned from {% cycle a b c as name %} and the
|
||||
# one returned from {% cycle name %} are the exact same object. This
|
||||
# shouldn't cause problems (heh), but if it does, now you know.
|
||||
#
|
||||
# Ugly hack warning: this stuffs the named template dict into parser so
|
||||
# that names are only unique within each template (as opposed to using
|
||||
# a global variable, which would make cycle names have to be unique across
|
||||
# *all* templates.
|
||||
|
||||
args = token.split_contents()
|
||||
|
||||
if len(args) < 2:
|
||||
raise TemplateSyntaxError("'cycle' tag requires at least two arguments")
|
||||
|
||||
if ',' in args[1]:
|
||||
# Backwards compatibility: {% cycle a,b %} or {% cycle a,b as foo %}
|
||||
# case.
|
||||
args[1:2] = ['"%s"' % arg for arg in args[1].split(",")]
|
||||
|
||||
if len(args) == 2:
|
||||
# {% cycle foo %} case.
|
||||
name = args[1]
|
||||
if not hasattr(parser, '_namedCycleNodes'):
|
||||
raise TemplateSyntaxError("No named cycles in template."
|
||||
" '%s' is not defined" % name)
|
||||
if not name in parser._namedCycleNodes:
|
||||
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
|
||||
return parser._namedCycleNodes[name]
|
||||
|
||||
if len(args) > 4 and args[-2] == 'as':
|
||||
name = args[-1]
|
||||
node = SafeCycleNode(args[1:-2], name)
|
||||
if not hasattr(parser, '_namedCycleNodes'):
|
||||
parser._namedCycleNodes = {}
|
||||
parser._namedCycleNodes[name] = node
|
||||
else:
|
||||
node = SafeCycleNode(args[1:])
|
||||
return node
|
||||
safe_cycle = register.tag(safe_cycle)
|
||||
|
Loading…
Reference in New Issue
Block a user