"Thinking Clearly About Performance" by Cary Millsap:
or
var numbers = [1,2,3,4,5]
var doubled = []
for(var i = 0; i < numbers.length; i++) {
var newNumber = numbers[i] * 2
doubled.push(newNumber)
}
console.log(doubled) //=> [2,4,6,8,10]
doubled array at each step until we are done.Array.map function and look like:var numbers = [1,2,3,4,5] var doubled = numbers.map(function(n) { return n * 2 }) console.log(doubled) //=> [2,4,6,8,10]
map creates a new array from an existing array, where
each element in the new array is created by passing the elements of the
original array into the function passed to map (function(n) { return n*2 } in this case).map function does is abstract away the process of explicitly iterating over the array, and lets us focus on what
we want to happen. Note that the function we pass to map is pure; it
doesn't have any side effects (change any external state), it just takes
in a number and returns the number doubled.Or we could do it declaratively, using thevar numbers = [1,2,3,4,5] var total = 0 for(var i = 0; i < numbers.length; i++) { total += numbers[i] } console.log(total) //=> 15
reduce function:var numbers = [1,2,3,4,5] var total = numbers.reduce(function(sum, n) { return sum + n }); console.log(total) //=> 15
reduce boils a list down into a single value using the
given function. It takes the function and applies it to all the items in
the array. On each invocation, the first argument (sum in this case) is the result of calling the function on the previous element, and the second (n) is the current element. So in this case, for each element we add n to sum and return that on each step, leaving us with the sum of the entire array at the end.reduce abstracts over the how and deals
with the iteration and state management side of things for us, giving us
a generic way of collapsing a list to a single value. All we have to do
is specify what we are looking for.map or reduce before, this will feel and look strange at first, I guarantee it. As programmers we are very used to specifying how
things should happen. "Iterate over this list", "if this then that",
"update this variable with this new value". Why should you have to learn
this slightly bizarre looking abstraction when you already know how to
tell the machine how to do things?how it should happen.SELECT * from dogs
INNER JOIN owners
WHERE dogs.owner_id = owners.id
Yuck! Now, I'm not saying that SQL is always easy to understand, or necessarily obvious when you first see it, but it's a lot clearer than that mess.//dogs = [{name: 'Fido', owner_id: 1}, {...}, ... ] //owners = [{id: 1, name: 'Bob'}, {...}, ...] var dogsWithOwners = [] var dog, owner for(var di=0; di < dogs.length; di++) { dog = dogs[di] for(var oi=0; oi < owners.length; oi++) { owner = owners[oi] if (owner && dog.owner_id == owner.id) { dogsWithOwners.push({ dog: dog, owner: owner }) } }} }
data array. To demonstrate what's going on we add a circle every second.It's not essential to understand exactly what's going on here (it will take a while to get your head around regardless), but the gist of it is this://var data = [{x: 5, y: 10}, {x: 20, y: 5}] var circles = svg.selectAll('circle') .data(data) circles.enter().append('circle') .attr('cx', function(d) { return d.x }) .attr('cy', function(d) { return d.y }) .attr('r', 0) .transition().duration(500) .attr('r', 5)
circles in the visualisation (initially there will be none). Then we bind some data to the selection (our data array)..enter() method to get the datapoints which
have "entered". For those points, we say we would like a circle added to
the diagram, centered on the x and y values of the datapoint, with an initial radius of 0 but transitioned over half a second to a radius of 5.I want this data drawn as circles, centered on the point specified in the data, and if there are any new circles you should add them and animate their radius.This is awesome, we haven't written a single loop, there is no state management here. Coding graphics is often hard, confusing and ugly, but here d3 has abstracted away most of the crap and left us to just specify what we want.
xkbcomp $DISPLAY xkb.dumpThis dumps the layout to the file xkb.dump, which I can then inspect. Doing so reveals that I want to edit the keys CAPS, LCTL, PRSC and RCTL. How to do this though, according to the x.org documentation, is that I need a rules file and a symbol file. The rules file references the symbol file in the 'options' field in order to enable the customizations I specified in the symbol file. The two examples I will use for these files are the evdev rule set located in
/usr/share/X11/xkb/rules/evdev and the ctrl symbol file located at /usr/share/X11/xkb/symbols/ctrl.ctrl:nocaps = +ctrl(nocaps)which points to the 'nocaps' entry in the 'symbols/ctrl' file.
/usr/share/X11/xkb/rules/ and symbol files must exist in /usr/share/X11/symbols/. For ease of use, I created my files in ~/.xkb/ and created symlinks with in symbols/ and rules/ to those files. Once those custom files are set up, the rule file can be specified with setxkbmap. Changes in symbol files wont take affect until the cached versions are removed with rm /var/lib/xkb/*.xkm. Then if our symbol file is /usr/share/X11/symbols/test, with symbols defined as
partial modifier_keys
xkb_symbols "nocaps_nolrctrl" {
replace key <caps>; { [ Control_L, Control_L ] };
replace key <lctl> { [ NoSymbol ] };
replace key <rctl> { [ NoSymbol ] };
modifier_map Control { <caps> }
};
our option string to use would be 'test:nocaps_nolrctrl'. Test it with setxkbmap -option 'test:nocaps_nolrctrl'. This is also what is needed in the rule file.
// Eliminate CapsLock, making it another Ctrl.
partial modifier_keys
xkb_symbols "nocaps_nolrctrl" {
replace key <caps> { [ Control_L, Control_L ] };
replace key <lctl> { [ NoSymbol ] };
replace key <rctl> { [ NoSymbol ] };
modifier_map Control { <caps> };
};
// Replace PtrSc
partial modifier_keys
xkb_symbols "prtsc_super" {
replace key <prsc> { [ Super_R, Super_R ] };
modifier_map Mod4 { <prsc>, <lwin> };
};
// Have [L|R]CTL generate an fkey
partial modifier_keys
xkb_symbols "ctl_fkey" {
replace key <lctl> { [ F12 ] };
replace key <rctl> { [ F12 ] };
};
~/.xkb/evdev.mouseless and ~/.xkb/evdev.mouseless.lst then added to the end of the ! option = symbols section of evdev.mouseless:
window_ctrl:ctl_fkey = +window_ctrl(ctl_fkey)
window_ctrl:nocaps_nolrctrl = +window_ctrl(nocaps_nolrctrl)
window_ctrl:prtsc_super = +window_ctrl(prtsc_super)
setxkbmap -rules evdev.mouseless -option "window_ctrl:nocaps_nolrctrl,window_ctrl:prtsc_super,window_ctrl:ctl_fkey".myModMask with mod4Mask (mod4 being the equivalent to the Super/Windows key).
;; Setup move to previous window to mimic tmux bindings
(global-unset-key "\M-o")
(global-set-key "\M-o" 'other-window)
;; Move to next window
(global-set-key "\M-O" (lambda () (interactive) (other-window -1)))
set-option -g prefix F12 .config/autostart/synclient.desktop
[Desktop Entry]
Name=synclient
GenericName=synclient
Comment=Change trackpad to scrollpad
Exec=synclient RightEdge=1751
Terminal=true
Type=Application
StartupNotify=false
The original release from TTimo compiles well with Visual Studio 2010 Professional. Unfortunately Visual Studio 2010 "Express" lacks MFC and hence cannot be used. This was disappointing upon release but some people have since removed the dependencies.
Windows 7 :
===========
git clone https://github.com/TTimo/doom3.gpl.git

MacOS X :
=========
git clone https://github.com/badsector/Doom3-for-MacOSX-
base folder containing the Doom 3 assets. Since I did not want to waste time extracting them from the Doom 3 CDs and updating them: I downloaded the Steam version. It seems id Software team did the same since the Visual Studio project released still contains "+set fs_basepath C:\Program Files (x86)\Steam\steamapps\common\doom 3" in the debug settings! neo subfolder.| Projects | Builds | Observations | |
| Windows | MacO SX | ||
| Game | gamex86.dll | gamex86.so | Doom3 gameplay |
| Game-d3xp | gamex86.dll | gamex86.so | Doom3 eXPension (Ressurection) gameplay |
| MayaImport | MayaImport.dll | - | Part of the assets creation toolchain: Loaded at runtime in order to open Maya files and import monsters, camera path and maps. |
| Doom3 | Doom3.exe | Doom3.app | Doom 3 Engine |
| TypeInfo | TypeInfo.exe | - | In-house RTTI helper: Generates GameTypeInfo.h: A map of all the Doom3 class types with each member size. This allow memory debugging via TypeInfo class. |
| CurlLib | CurlLib.lib | - | HTTP client used to download files (Staticaly linked against gamex86.dll and doom3.exe). |
| idLib | idLib.lib | idLib.a | id Software library. Includes parser,lexer,dictionary ... (Staticaly linked against gamex86.dll and doom3.exe). |

idlib.a and gamex86.dll but the core of the engine was still closed source.libc is extensively used. Filesystem) are in the Doom3.exe project. This is a problem since gamex86.dll needs to load assets as well. Those subsystems are dynamically loaded by gamex86.dll from doom3.exe (this is what the arrow materializes in the drawing). If we use a PE explorer on the DLL we can see that gamex86.dll export one method: GetGameAPI:
LoadLibrary.GetGameAPI in the dll using win32's GetProcAddress.GetGameAPI.
gameExport_t * GetGameAPI_t( gameImport_t *import );
idGame object and Game.dll has a pointer to a gameImport_t object containing additional references to all missing subsystems such as idFileSystem.
typedef struct {
int version; // API version
idSys * sys; // non-portable system services
idCommon * common; // common
idCmdSystem * cmdSystem // console command system
idCVarSystem * cvarSystem; // console variable system
idFileSystem * fileSystem; // file system
idNetworkSystem * networkSystem; // network system
idRenderSystem * renderSystem; // render system
idSoundSystem * soundSystem; // sound system
idRenderModelManager * renderModelManager; // render model manager
idUserInterfaceManager * uiManager; // user interface manager
idDeclManager * declManager; // declaration manager
idAASFileManager * AASFileManager; // AAS file manager
idCollisionModelManager * collisionModelManager; // collision model manager
} gameImport_t;
typedef struct
{
int version; // API version
idGame * game; // interface to run the game
idGameEdit * gameEdit; // interface for in-game editing
} gameExport_t;
cloc:
./cloc-1.56.pl neo
2180 text files.
2002 unique files.
626 files ignored.
http://cloc.sourceforge.net v 1.56 T=19.0 s (77.9 files/s, 47576.6 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
C++ 517 87078 113107 366433
C/C++ Header 617 29833 27176 111105
C 171 11408 15566 53540
Bourne Shell 29 5399 6516 39966
make 43 1196 874 9121
m4 10 1079 232 9025
HTML 55 391 76 4142
Objective C++ 6 709 656 2606
Perl 10 523 411 2380
yacc 1 95 97 912
Python 10 108 182 895
Objective C 1 145 20 768
DOS Batch 5 0 0 61
Teamcenter def 4 3 0 51
Lisp 1 5 20 25
awk 1 2 1 17
-------------------------------------------------------------------------------
SUM: 1481 137974 164934 601047
-------------------------------------------------------------------------------
| #Lines of code | Doom | idTech1 | idTech2 | idTech3 | idTech4 |
| Engine | 39079 | 143855 | 135788 | 239398 | 601032 |
| Tools | 341 | 11155 | 28140 | 128417 | - |
| Total | 39420 | 155010 | 163928 | 367815 | 601032 |

lcc codebase (the C compiler used to generate QVM bytecode) .idMath::InvSqrt and spacial localization optimizations are here but most of the code just tries to use the tools when they are available (GPU Shaders, OpenGL VBO, SIMD, Altivec, SMP, L2 Optimizations (R_AddModelSurfaces per model processing)...).const placement).
idCommonLocal commonLocal; // OS Specialized object
idCommon * common = &commonLocal; // Interface pointer (since Init is OS dependent it is an abstract method
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
Sys_SetPhysicalWorkMemory( 192 << 20, 1024 << 20 ); //Min = 201,326,592 Max = 1,073,741,824
Sys_CreateConsole();
// Since the engine is multi-threaded mutexes are initialized here: One mutex per "critical" (concurrent execution) section of code.
for (int i = 0; i < MAX_CRITICAL_SECTIONS; i++ ) {
InitializeCriticalSection( &win32.criticalSections[i] );
}
common->Init( 0, NULL, lpCmdLine ); // Assess how much VRAM is available (not done via OpenGL but OS call)
Sys_StartAsyncThread(){ // The next look runs is a separate thread.
while ( 1 ){
usleep( 16666 ); // Run at 60Hz
common->Async(); // Do the job
Sys_TriggerEvent( TRIGGER_EVENT_ONE ); // Unlock other thread waiting for inputs
pthread_testcancel(); // Check if we have been cancelled by the main thread (on shutdown).
}
}
Sys_ShowConsole
while( 1 ){
Win_Frame(); // Show or hide the console
common->Frame(){
session->Frame() // Game logic
{
for (int i = 0 ; i < gameTicsToRun ; i++ )
RunGameTic(){
game->RunFrame( &cmd ); // From this point execution jumps in the GameX86.dll address space.
for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() )
ent->GetPhysics()->UpdateTime( time ); // let entities think
}
}
session->UpdateScreen( false ); // normal, in-sequence screen update
{
renderSystem->BeginFrame
idGame::Draw // Renderer front-end. Doesn't actually communicate with the GPU !!
renderSystem->EndFrame
R_IssueRenderCommands // Renderer back-end. Issue GPU optimized commands to the GPU.
}
}
}
}
Sys_StartAsyncThread which indicate that Doom3 is multi-threaded. The goal of this thread is to handle the time-critical functions that the engine don't want limited to the frame rate:
idCommonLocal commonLocal; // Implementation
idCommon * common = &commonLocal; // Pointer for gamex86.dll
commonLocalmethods are called. The interface pointer is used during the handshake so doom3.exe can exchange objects reference with gamex86.dll but in this case the vtable cost is not optimized away. IN_frame().dmap is a complete departure from the traditional bsp builder. I reviewed it to the deep down on a dedicated page. 
