Fix line endings of all files in source/ except source/third_party/.

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