SlideShare a Scribd company logo
The Challenge of 
Bringing FEZ to 
PlayStation Platforms 
Miguel Angel Horna 
Lead Programmer at BlitWorks
FEZ 
• Released in 2012 
• Developed by Polytron Corporation 
• In development for over 5 years 
• Just 2 people 
• Game design/Art: Phil Fish 
• Game programmer: Renaud Bédard
FEZ 
• C# Code 
• Xbox 360 version uses XNA 
• PC Version uses MonoGame (OpenGL) 
• No C# runtime for PlayStation platforms
The main decision 
• Two options: 
• Port C# to PlayStation platforms 
• Straightforward (almost) game code port 
• No JIT support. Doubts on performance 
• OpenGL to native libraries 
• Rewrite C# code to C++ 
• “Native” performance. Better optimizations 
• Lots of work. Over 500 classes
The main decision 
• We chose game code rewrite 
• We knew it was going to be hard 
• And long… It took almost 1 year to 
complete 
• Manual rewrite was out of question 
• Tried some automatic conversion tools
The main decision 
• C# to C++ Converter by Tangible 
Software 
• It made the first (rough) conversion 
• Every file had to be completed, edited 
and reviewed 
• Blind conversion. Much time passed with 
no visible progress (not even compiling)
The main decision 
C# 
public IEnumerableTrile> ActorTriles(ActorType type) 
{ 
return TrileSet == null ? Enumerable.Repeat<Trile>(null, 1) : TrileSet.Triles.Values.Where(x => 
x.ActorSettings.Type == type); 
} 
Auto converted 
std::shared_ptr<IEnumerable<Trile*>> LevelManager::ActorTriles(ActorType type) 
{ 
//C# TO C++ CONVERTER TODO TASK: Lambda expressions and anonymous methods are not converted to native 
C++: 
return get_TrileSet() == nullptr ? Enumerable::Repeat<Trile*>(nullptr, 1) : get_TrileSet()- 
>get_Triles().Values->Where(x => x.ActorSettings->Type == type); 
}
The main decision 
Final code 
std::shared_ptr<List<std::shared_ptr<Trile>>> LevelManager::ActorTriles(ActorType type) 
{ 
if(get_TrileSet()==nullptr) 
{ 
std::shared_ptr<List<std::shared_ptr<Trile>>> result = std::make_shared<List<std::shared_ptr<Trile>>>(); 
result->push_back(nullptr); 
return result; 
} 
else 
{ 
return Where(get_TrileSet()->get_Triles(),[=] (const std::shared_ptr<Trile> &t) { return t->get_ActorSettings()- 
>get_Type() == type; } ); 
} 
}
Conversion 
• Properties 
• Generate get_, set_ accessors in classes 
• Converter generated proper methods 
• .. But sometimes didn’t use them 
• Needed long rewrites 
• Beware of returning temporary references, 
some compilers don’t detect that!
Conversion 
• Be careful with operation order with -= and 
too “automated” rewrite 
C# 
PlayerManager.Velocity -= destination - instance.Center; 
C++ wrong 
get_PlayerManager()->set_Velocity(get_PlayerManager()->get_Velocity() - destination - instance- 
>get_Center()); 
C++ correct 
get_PlayerManager()->set_Velocity(get_PlayerManager()->get_Velocity() - (destination - instance- 
>get_Center()));
Conversion 
• Extension methods 
• Extension methods were widely used ... 
• … on Enums 
• No way to convert it to C++ 
• Just create normal functions passing the 
enum as parameter 
C# 
var bitangent = orientation.GetBitangent().AsAxis().GetMask(); 
C++ 
auto bitangent = FezMath::GetMask(FezMath::AsAxis(FezMath::GetBitangent(orientation)));
Conversion 
• Lambda expressions & delegates 
• Game code heavily used lambda expressions 
for events, list queries ... 
• Delegates were used a lot too (threads, 
scheduled operations, scripting…) 
• They don’t have direct conversion to C++ … 
• … but they have for C++11 
• Lambdas and std::function<>
Conversion 
C# 
GameState.LoadSaveFile(() => GameState.LoadLevelAsync(Util.NullAction)); 
C++ 
get_GameState()->LoadSaveFile([=] () 
{ 
get_GameState()->LoadLevelAsync([=] () { }); 
}); 
C# 
return new LongRunningAction((elapsed, since) => component.IsDisposed); 
C++ 
return LongRunningAction::Create([=] (float elapsed, float since) -> bool 
{ 
return component->get_IsDisposed(); 
});
Conversion 
• Nested lambdas caused problems with the 
converter 
• Corrupted, half-converted files 
• Unbalanced brackets generation 
• Unconverted c# code 
• Missing pieces of functions 
• Find the offending code, comment, re-convert 
the file, and manually convert that piece of 
code
Conversion 
C# 
DotService.Say("DOT_ANTI_A", true, false).Ended = () => 
{ DotService.Say("DOT_ANTI_B", true, false).Ended = () => 
{ DotService.Say("DOT_ANTI_C", true, false).Ended = () => 
{ DotService.Say("DOT_ANTI_D", true, true).Ended = CheckCubes; };};}; 
C++ 
get_DotService()->Say("DOT_ANTI_A", true, false)->Ended = [=] () 
{ 
get_DotService()->Say("DOT_ANTI_B", true, false)->Ended = [=] () 
{ 
get_DotService()->Say("DOT_ANTI_C", true, false)->Ended = [=] () 
{ 
get_DotService()->Say("DOT_ANTI_D", true, true)->Ended = [=] { CheckCubes(); }; 
}; 
}; 
};
Garbage Collector 
• FEZ had random stuttering due to the GC 
kicking in 
• Deterministic object destruction preferred 
• Reference counting 
• C++11’s std::shared_ptr<> 
• Caused its own kind of bugs ☹
Garbage Collector 
• Circular references 
• Try to access shared_from_this() in 
constructors 
• Capturing this on lambdas caused 
problems (no reference increment)
Garbage Collector 
void SoundEmitter::FadeOutAndDie(float forSeconds) 
{ 
void MovingGroupsHost::MovingGroupState::StopSound() 
{ 
eAssociatedSound->FadeOutAndDie(0.25f); 
eAssociatedSound.reset(); 
} 
Waiters::Interpolate(forSeconds, [=] (float s) 
{ 
set_VolumeFactor(volumeFactor * (1 - s)); 
} 
, [=] () 
{ 
if (get_Cue() != nullptr && !get_Cue()->get_IsDisposed() && get_Cue()->get_State() != SoundState::Stopped) 
get_Cue()->Stop(true); 
}); 
}
Garbage Collector 
void SoundEmitter::FadeOutAndDie(float forSeconds) 
{ 
auto _this=shared_from_this(); 
Waiters::Interpolate(forSeconds, [=] (float s) 
{ 
_this->set_VolumeFactor(volumeFactor * (1 - s)); 
} 
, [=] () 
{ 
if (_this->get_Cue() != nullptr && !_this->get_Cue()->get_IsDisposed() && _this->get_Cue()->get_State() != SoundState::Stopped) 
_this->get_Cue()->Stop(true); 
}); 
}
Reflection 
• Game scripting used reflection to: 
• Trap scripting objects events by name 
• Invoke methods by name 
• We implemented method, event, triggers… 
descriptors for scripting objects 
• Generated dynamic methods by using IL Emit 
• No dynamic code generation
Reflection 
script key=9 { name "Untitled" 
triggers { trigger { event "Enter" 
object { type "Volume" identifier 4 
} } } 
actions { action { 
operation "ChangeLevelToVolume" 
arguments "LIGHTHOUSE_HOUSE_A" "1" "True" "True" 
object { 
type "Level" 
} 
} } }
Reflection 
std::shared_ptr<EntityDescriptor> IVolumeService::GetEntityDescriptor() 
{ 
//Operations 
std::unordered_map<String,MethodDesc> operations; 
operations["FocusCamera"] = MethodDesc([=] (std::vector<MultiTypeParameter> &params) -> std::shared_ptr<LongRunningAction> 
{return FocusCamera(params[0].I, params[1].I, params[2].B); },3 ) ; 
operations["SetEnabled"] = MethodDesc([=] (std::vector<MultiTypeParameter> &params) -> std::shared_ptr<LongRunningAction> 
{SetEnabled(params[0].I, params[1].B, params[2].B); return nullptr;},3 ) ; 
//Properties 
std::unordered_map<String,PropertyDesc> properties; 
properties["GomezInside"] = PropertyDesc([=] (int id) -> MultiTypeParameter { MultiTypeParameter mt; mt.B=get_GomezInside(id); 
return mt; },MultiType::BOOL); 
//Events 
std::unordered_map<String,EventHandlerDesc> events; 
events["Enter"] = EventInstance(&Enter,&Exit); 
events["Exit"] = EventInstance(&Exit); 
return std::make_shared<EntityDescriptor>("Volume","Volume",false,operations,properties,events); 
}
Reflection 
• Service dependencies were resolved using 
reflection 
[ServiceDependency] 
public ISoundManager SoundManager { protected get; set; } 
[ServiceDependency] 
public IContentManagerProvider CMProvider { protected get; set; } 
• In C++ there are no attributes, and also we can’t 
get the property names 
• This was not possible to resolve the same way
Reflection 
• We created a base class with all the service set_ 
methods virtual, and doing nothing 
• The dependency resolver iterated all registered 
services 
• A macro called for each combination of property 
name and type, tried to dynamic_cast the service 
to the type, and if so, called the set_ method 
• All components derived from this class, so the 
overridden set_ functions actually set the value
Reflection 
#define MY_SERVICE_SET(__propertyname,__serviceclass)  
if(std::dynamic_pointer_cast<__serviceclass>(service)!=nullptr)  
{ 
std::shared_ptr<__serviceclass> 
private_##__propertyname##_##__serviceclass=std::dynamic_pointer_cast<__serviceclass>(service); 
injector->set_##__propertyname(private_##__propertyname##_##__serviceclass); 
} 
MY_SERVICE_SET(CameraManager,IGameCameraManager); 
MY_SERVICE_SET(SoundManager,ISoundManager) 
MY_SERVICE_SET(CMProvider,IContentManagerProvider) 
MY_SERVICE_SET(TargetRenderer,ITargetRenderingManager) 
MY_SERVICE_SET(TargetRenderingManager,ITargetRenderingManager) 
...
.NET Framework 
• Replacement for some .NET Framework 
libraries: 
• Threads & Synchronization 
• Almost direct map to native APIs 
• lock() blocks converted to mutex.Lock() and 
Unlock() 
• Files 
• Also easy to map, and BinaryReader/Writer gave us 
the endian safe file access.
.NET Framework 
• String (Unicode) 
• String class derived from std::wstring, but with C# 
like methods (SubString(),Replace(),Split()..) 
• Collections (Dictionary, List, Array) 
• Converter automatically changed them to STL 
containers (unordered_map,list,vector) 
• Nullable types 
• Implemented our own Nullable<T> class
.NET Framework 
• Events 
• Internally containing a std::list<std::function> 
• Adding a method to an event requires a lambda 
• C# CameraManager.ViewpointChanged += UpdateRotation; 
• C++ get_CameraManager()->ViewpointChanged += [=] () {UpdateRotation();}; 
• Initially same interface than C# (+=, -=) 
• No way to compare lambdas to remove, so we had 
to change interface and return ID 
• UpdateRotationDelegateId=get_CameraManager()->ViewpointChanged.Add([=] () 
{UpdateRotation();}); 
• get_CameraManager()->ViewpointChanged.Remove(UpdateRotationDelegateId);
.NET Framework 
• LINQ was widely used to search 
• We implemented LINQ-like operations for 
STL list,vector, map: 
• Where, Any, All, Union, Exists... 
• Usage was a bit awkward sometimes 
C# if(!tracks.Any(y => y.Name == x.Track.Name)) 
C++ if(!Any<std::shared_ptr<AmbienceTrack>>(tracks,[=] (const std::shared_ptr<AmbienceTrack> 
&y) -> bool { return y->get_Name()==(*x)->Track->get_Name(); }))
Bugfixing 
• Original game already had bugs 
• C# to C++ introduced new ones 
• Memory leaks (circular references) 
• Mixing normal and reference counted 
pointers to same object. Use after delete. 
• Returning reference to temporary object in 
get_ properties access: 
const Vector3 &TrixelEmplacement::get_Position() const 
{ 
return Vector3(X, Y, Z); 
}
Bugfixing 
• Mistakes during manual conversion 
• Missing parenthesis on -= operations 
• Errors converting lambda expressions in 
LINQ operations 
• Uninitialized member variables 
• C++11 compiler bugs !!
Optimization 
• OK, now it worked… but slowly 
• CPU intensive code 
• Lots of geometry with inefficient 
instancing 
• Complex shaders
Optimization (CPU) 
• std::shared_ptr is thread safe. We 
created a lightweight (unsafe) fast_ptr 
• Move some CPU intensive operations to 
another thread 
• Erasing std::vector elements is slow: 
• convert to std::list 
• replace removed element with last one and 
resize()
MonoGame graphics 
• For PC, OpenGL based. 
• Two options: 
• Minimal OpenGL library for each platform 
• Custom MonoGame target for each platform 
• We anticipated GPU performance 
problems 
• Chose custom MonoGame targets
MonoGame graphics 
• Allows platform-specific features 
• Fine tuning for platform 
• Assets optimized per platform (swizzled, 
tiled…) 
• Shaders rewritten and optimized for each 
platform
Optimization (GPU) 
• FEZ doesn’t look like a GPU intensive game. 
• That’s wrong 
• “Trile” (tri-dimensional tile) made of 
16x16x16 “trixels” (tri-dimensional pixel) 
• Built sculpting a solid trile, removing trixels. 
Generates a lot of geometry 
• Two pass rendering
Optimization (GPU)
Optimization (GPU)
Optimization (GPU) 
• Excessive geometry was choking vertex 
shaders 
• Only one (while moving) or two (while 
rotating) trile faces visible most of the time 
• Quick rejection of non-visible faces in CPU 
(~⅚ of the total geometry) 
• Proper instancing 
• Huge speedup
Optimization (GPU) 
• Complex effects were choking the pixel 
shaders 
• Simplified code paths 
• Wrote specific “fast path” shaders to avoid 
branching 
• Moved calculations to vertex shader when 
possible 
• Most shaders unnecessarily used “discard”
Optimization (GPU)
New features 
• Cross-save (additional slot) 
• Transparent for the user if online 
• No progress merge, just latest data 
• Allows play offline, syncs when 
online 
• Stereoscopic 3D 
• Based on existing red/blue mode 
• Required extra tweaks
Questions?

More Related Content

What's hot

Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)
intelliyole
 
JVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinJVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in Kotlin
Andrey Breslav
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
intelliyole
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)
Dhaval Dalal
 
Being functional in PHP (PHPDay Italy 2016)
Being functional in PHP (PHPDay Italy 2016)Being functional in PHP (PHPDay Italy 2016)
Being functional in PHP (PHPDay Italy 2016)
David de Boer
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friend
The Software House
 
​"Delegates, Delegates everywhere" Владимир Миронов
​"Delegates, Delegates everywhere" Владимир Миронов​"Delegates, Delegates everywhere" Владимир Миронов
​"Delegates, Delegates everywhere" Владимир Миронов
AvitoTech
 
Voce Tem Orgulho Do Seu Codigo
Voce Tem Orgulho Do Seu CodigoVoce Tem Orgulho Do Seu Codigo
Voce Tem Orgulho Do Seu Codigo
Victor Hugo Germano
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
HamletDRC
 
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Doris Chen
 
Developer Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoDeveloper Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duo
The Software House
 
Promise: async programming hero
Promise: async programming heroPromise: async programming hero
Promise: async programming hero
The Software House
 
AST Transformations
AST TransformationsAST Transformations
AST TransformationsHamletDRC
 
Kotlin, why?
Kotlin, why?Kotlin, why?
Kotlin, why?
Paweł Byszewski
 
Introduction to Kotlin
Introduction to KotlinIntroduction to Kotlin
Introduction to Kotlin
Oswald Campesato
 
Polyglot Programming in the JVM
Polyglot Programming in the JVMPolyglot Programming in the JVM
Polyglot Programming in the JVMAndres Almiray
 
ES6 in Real Life
ES6 in Real LifeES6 in Real Life
ES6 in Real Life
Domenic Denicola
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis Atencio
Luis Atencio
 
Building native Android applications with Mirah and Pindah
Building native Android applications with Mirah and PindahBuilding native Android applications with Mirah and Pindah
Building native Android applications with Mirah and Pindah
Nick Plante
 
Polyglot Grails
Polyglot GrailsPolyglot Grails
Polyglot Grails
Marcin Gryszko
 

What's hot (20)

Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)
 
JVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinJVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in Kotlin
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)
 
Being functional in PHP (PHPDay Italy 2016)
Being functional in PHP (PHPDay Italy 2016)Being functional in PHP (PHPDay Italy 2016)
Being functional in PHP (PHPDay Italy 2016)
 
Let the type system be your friend
Let the type system be your friendLet the type system be your friend
Let the type system be your friend
 
​"Delegates, Delegates everywhere" Владимир Миронов
​"Delegates, Delegates everywhere" Владимир Миронов​"Delegates, Delegates everywhere" Владимир Миронов
​"Delegates, Delegates everywhere" Владимир Миронов
 
Voce Tem Orgulho Do Seu Codigo
Voce Tem Orgulho Do Seu CodigoVoce Tem Orgulho Do Seu Codigo
Voce Tem Orgulho Do Seu Codigo
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
 
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5Developing High Performance Websites and Modern Apps with JavaScript and HTML5
Developing High Performance Websites and Modern Apps with JavaScript and HTML5
 
Developer Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoDeveloper Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duo
 
Promise: async programming hero
Promise: async programming heroPromise: async programming hero
Promise: async programming hero
 
AST Transformations
AST TransformationsAST Transformations
AST Transformations
 
Kotlin, why?
Kotlin, why?Kotlin, why?
Kotlin, why?
 
Introduction to Kotlin
Introduction to KotlinIntroduction to Kotlin
Introduction to Kotlin
 
Polyglot Programming in the JVM
Polyglot Programming in the JVMPolyglot Programming in the JVM
Polyglot Programming in the JVM
 
ES6 in Real Life
ES6 in Real LifeES6 in Real Life
ES6 in Real Life
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis Atencio
 
Building native Android applications with Mirah and Pindah
Building native Android applications with Mirah and PindahBuilding native Android applications with Mirah and Pindah
Building native Android applications with Mirah and Pindah
 
Polyglot Grails
Polyglot GrailsPolyglot Grails
Polyglot Grails
 

Similar to The Challenge of Bringing FEZ to PlayStation Platforms

Add an interactive command line to your C++ application
Add an interactive command line to your C++ applicationAdd an interactive command line to your C++ application
Add an interactive command line to your C++ application
Daniele Pallastrelli
 
C++11: Feel the New Language
C++11: Feel the New LanguageC++11: Feel the New Language
C++11: Feel the New Languagemspline
 
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
GeeksLab Odessa
 
C# 6.0 Preview
C# 6.0 PreviewC# 6.0 Preview
C# 6.0 Preview
Fujio Kojima
 
Introduction to typescript
Introduction to typescriptIntroduction to typescript
Introduction to typescript
Mario Alexandro Santini
 
JSLounge - TypeScript 소개
JSLounge - TypeScript 소개JSLounge - TypeScript 소개
JSLounge - TypeScript 소개Reagan Hwang
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
Juan Pablo
 
Annotation processor and compiler plugin
Annotation processor and compiler pluginAnnotation processor and compiler plugin
Annotation processor and compiler plugin
Oleksandr Radchykov
 
20.1 Java working with abstraction
20.1 Java working with abstraction20.1 Java working with abstraction
20.1 Java working with abstraction
Intro C# Book
 
Angular2 for Beginners
Angular2 for BeginnersAngular2 for Beginners
Angular2 for Beginners
Oswald Campesato
 
What’s new in .NET
What’s new in .NETWhat’s new in .NET
What’s new in .NET
Doommaker
 
Systematic Generation Data and Types in C++
Systematic Generation Data and Types in C++Systematic Generation Data and Types in C++
Systematic Generation Data and Types in C++
Sumant Tambe
 
JavaScript 2016 for C# Developers
JavaScript 2016 for C# DevelopersJavaScript 2016 for C# Developers
JavaScript 2016 for C# Developers
Rick Beerendonk
 
Connecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with EmbindConnecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with Embind
Chad Austin
 
Beware: Sharp Tools
Beware: Sharp ToolsBeware: Sharp Tools
Beware: Sharp Toolschrismdp
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) Things
Michael Pirnat
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
Adam L Barrett
 

Similar to The Challenge of Bringing FEZ to PlayStation Platforms (20)

Add an interactive command line to your C++ application
Add an interactive command line to your C++ applicationAdd an interactive command line to your C++ application
Add an interactive command line to your C++ application
 
lecture56.ppt
lecture56.pptlecture56.ppt
lecture56.ppt
 
Dlr
DlrDlr
Dlr
 
C++11: Feel the New Language
C++11: Feel the New LanguageC++11: Feel the New Language
C++11: Feel the New Language
 
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
 
C# 6.0 Preview
C# 6.0 PreviewC# 6.0 Preview
C# 6.0 Preview
 
Introduction to typescript
Introduction to typescriptIntroduction to typescript
Introduction to typescript
 
JSLounge - TypeScript 소개
JSLounge - TypeScript 소개JSLounge - TypeScript 소개
JSLounge - TypeScript 소개
 
Day 1
Day 1Day 1
Day 1
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
 
Annotation processor and compiler plugin
Annotation processor and compiler pluginAnnotation processor and compiler plugin
Annotation processor and compiler plugin
 
20.1 Java working with abstraction
20.1 Java working with abstraction20.1 Java working with abstraction
20.1 Java working with abstraction
 
Angular2 for Beginners
Angular2 for BeginnersAngular2 for Beginners
Angular2 for Beginners
 
What’s new in .NET
What’s new in .NETWhat’s new in .NET
What’s new in .NET
 
Systematic Generation Data and Types in C++
Systematic Generation Data and Types in C++Systematic Generation Data and Types in C++
Systematic Generation Data and Types in C++
 
JavaScript 2016 for C# Developers
JavaScript 2016 for C# DevelopersJavaScript 2016 for C# Developers
JavaScript 2016 for C# Developers
 
Connecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with EmbindConnecting C++ and JavaScript on the Web with Embind
Connecting C++ and JavaScript on the Web with Embind
 
Beware: Sharp Tools
Beware: Sharp ToolsBeware: Sharp Tools
Beware: Sharp Tools
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) Things
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 

Recently uploaded

Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Sebastiano Panichella
 
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdfSupercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Access Innovations, Inc.
 
Bitcoin Lightning wallet and tic-tac-toe game XOXO
Bitcoin Lightning wallet and tic-tac-toe game XOXOBitcoin Lightning wallet and tic-tac-toe game XOXO
Bitcoin Lightning wallet and tic-tac-toe game XOXO
Matjaž Lipuš
 
Obesity causes and management and associated medical conditions
Obesity causes and management and associated medical conditionsObesity causes and management and associated medical conditions
Obesity causes and management and associated medical conditions
Faculty of Medicine And Health Sciences
 
Getting started with Amazon Bedrock Studio and Control Tower
Getting started with Amazon Bedrock Studio and Control TowerGetting started with Amazon Bedrock Studio and Control Tower
Getting started with Amazon Bedrock Studio and Control Tower
Vladimir Samoylov
 
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Dutch Power
 
somanykidsbutsofewfathers-140705000023-phpapp02.pptx
somanykidsbutsofewfathers-140705000023-phpapp02.pptxsomanykidsbutsofewfathers-140705000023-phpapp02.pptx
somanykidsbutsofewfathers-140705000023-phpapp02.pptx
Howard Spence
 
Tom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issueTom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issue
amekonnen
 
Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...
Sebastiano Panichella
 
Burning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdfBurning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdf
kkirkland2
 
International Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software TestingInternational Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software Testing
Sebastiano Panichella
 
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdfBonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
khadija278284
 
Acorn Recovery: Restore IT infra within minutes
Acorn Recovery: Restore IT infra within minutesAcorn Recovery: Restore IT infra within minutes
Acorn Recovery: Restore IT infra within minutes
IP ServerOne
 
Gregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptxGregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptx
gharris9
 
Media as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern EraMedia as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern Era
faizulhassanfaiz1670
 
0x01 - Newton's Third Law: Static vs. Dynamic Abusers
0x01 - Newton's Third Law:  Static vs. Dynamic Abusers0x01 - Newton's Third Law:  Static vs. Dynamic Abusers
0x01 - Newton's Third Law: Static vs. Dynamic Abusers
OWASP Beja
 
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AwangAniqkmals
 
María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024
eCommerce Institute
 
Competition and Regulation in Professional Services – KLEINER – June 2024 OEC...
Competition and Regulation in Professional Services – KLEINER – June 2024 OEC...Competition and Regulation in Professional Services – KLEINER – June 2024 OEC...
Competition and Regulation in Professional Services – KLEINER – June 2024 OEC...
OECD Directorate for Financial and Enterprise Affairs
 
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Dutch Power
 

Recently uploaded (20)

Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...Doctoral Symposium at the 17th IEEE International Conference on Software Test...
Doctoral Symposium at the 17th IEEE International Conference on Software Test...
 
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdfSupercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
Supercharge your AI - SSP Industry Breakout Session 2024-v2_1.pdf
 
Bitcoin Lightning wallet and tic-tac-toe game XOXO
Bitcoin Lightning wallet and tic-tac-toe game XOXOBitcoin Lightning wallet and tic-tac-toe game XOXO
Bitcoin Lightning wallet and tic-tac-toe game XOXO
 
Obesity causes and management and associated medical conditions
Obesity causes and management and associated medical conditionsObesity causes and management and associated medical conditions
Obesity causes and management and associated medical conditions
 
Getting started with Amazon Bedrock Studio and Control Tower
Getting started with Amazon Bedrock Studio and Control TowerGetting started with Amazon Bedrock Studio and Control Tower
Getting started with Amazon Bedrock Studio and Control Tower
 
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
Presentatie 4. Jochen Cremer - TU Delft 28 mei 2024
 
somanykidsbutsofewfathers-140705000023-phpapp02.pptx
somanykidsbutsofewfathers-140705000023-phpapp02.pptxsomanykidsbutsofewfathers-140705000023-phpapp02.pptx
somanykidsbutsofewfathers-140705000023-phpapp02.pptx
 
Tom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issueTom tresser burning issue.pptx My Burning issue
Tom tresser burning issue.pptx My Burning issue
 
Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...Announcement of 18th IEEE International Conference on Software Testing, Verif...
Announcement of 18th IEEE International Conference on Software Testing, Verif...
 
Burning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdfBurning Issue Presentation By Kenmaryon.pdf
Burning Issue Presentation By Kenmaryon.pdf
 
International Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software TestingInternational Workshop on Artificial Intelligence in Software Testing
International Workshop on Artificial Intelligence in Software Testing
 
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdfBonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
Bonzo subscription_hjjjjjjjj5hhhhhhh_2024.pdf
 
Acorn Recovery: Restore IT infra within minutes
Acorn Recovery: Restore IT infra within minutesAcorn Recovery: Restore IT infra within minutes
Acorn Recovery: Restore IT infra within minutes
 
Gregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptxGregory Harris' Civics Presentation.pptx
Gregory Harris' Civics Presentation.pptx
 
Media as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern EraMedia as a Mind Controlling Strategy In Old and Modern Era
Media as a Mind Controlling Strategy In Old and Modern Era
 
0x01 - Newton's Third Law: Static vs. Dynamic Abusers
0x01 - Newton's Third Law:  Static vs. Dynamic Abusers0x01 - Newton's Third Law:  Static vs. Dynamic Abusers
0x01 - Newton's Third Law: Static vs. Dynamic Abusers
 
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
AWANG ANIQKMALBIN AWANG TAJUDIN B22080004 ASSIGNMENT 2 MPU3193 PHILOSOPHY AND...
 
María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024María Carolina Martínez - eCommerce Day Colombia 2024
María Carolina Martínez - eCommerce Day Colombia 2024
 
Competition and Regulation in Professional Services – KLEINER – June 2024 OEC...
Competition and Regulation in Professional Services – KLEINER – June 2024 OEC...Competition and Regulation in Professional Services – KLEINER – June 2024 OEC...
Competition and Regulation in Professional Services – KLEINER – June 2024 OEC...
 
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
Presentatie 8. Joost van der Linde & Daniel Anderton - Eliq 28 mei 2024
 

The Challenge of Bringing FEZ to PlayStation Platforms

  • 1. The Challenge of Bringing FEZ to PlayStation Platforms Miguel Angel Horna Lead Programmer at BlitWorks
  • 2.
  • 3.
  • 4. FEZ • Released in 2012 • Developed by Polytron Corporation • In development for over 5 years • Just 2 people • Game design/Art: Phil Fish • Game programmer: Renaud Bédard
  • 5. FEZ • C# Code • Xbox 360 version uses XNA • PC Version uses MonoGame (OpenGL) • No C# runtime for PlayStation platforms
  • 6. The main decision • Two options: • Port C# to PlayStation platforms • Straightforward (almost) game code port • No JIT support. Doubts on performance • OpenGL to native libraries • Rewrite C# code to C++ • “Native” performance. Better optimizations • Lots of work. Over 500 classes
  • 7. The main decision • We chose game code rewrite • We knew it was going to be hard • And long… It took almost 1 year to complete • Manual rewrite was out of question • Tried some automatic conversion tools
  • 8. The main decision • C# to C++ Converter by Tangible Software • It made the first (rough) conversion • Every file had to be completed, edited and reviewed • Blind conversion. Much time passed with no visible progress (not even compiling)
  • 9. The main decision C# public IEnumerableTrile> ActorTriles(ActorType type) { return TrileSet == null ? Enumerable.Repeat<Trile>(null, 1) : TrileSet.Triles.Values.Where(x => x.ActorSettings.Type == type); } Auto converted std::shared_ptr<IEnumerable<Trile*>> LevelManager::ActorTriles(ActorType type) { //C# TO C++ CONVERTER TODO TASK: Lambda expressions and anonymous methods are not converted to native C++: return get_TrileSet() == nullptr ? Enumerable::Repeat<Trile*>(nullptr, 1) : get_TrileSet()- >get_Triles().Values->Where(x => x.ActorSettings->Type == type); }
  • 10. The main decision Final code std::shared_ptr<List<std::shared_ptr<Trile>>> LevelManager::ActorTriles(ActorType type) { if(get_TrileSet()==nullptr) { std::shared_ptr<List<std::shared_ptr<Trile>>> result = std::make_shared<List<std::shared_ptr<Trile>>>(); result->push_back(nullptr); return result; } else { return Where(get_TrileSet()->get_Triles(),[=] (const std::shared_ptr<Trile> &t) { return t->get_ActorSettings()- >get_Type() == type; } ); } }
  • 11. Conversion • Properties • Generate get_, set_ accessors in classes • Converter generated proper methods • .. But sometimes didn’t use them • Needed long rewrites • Beware of returning temporary references, some compilers don’t detect that!
  • 12. Conversion • Be careful with operation order with -= and too “automated” rewrite C# PlayerManager.Velocity -= destination - instance.Center; C++ wrong get_PlayerManager()->set_Velocity(get_PlayerManager()->get_Velocity() - destination - instance- >get_Center()); C++ correct get_PlayerManager()->set_Velocity(get_PlayerManager()->get_Velocity() - (destination - instance- >get_Center()));
  • 13. Conversion • Extension methods • Extension methods were widely used ... • … on Enums • No way to convert it to C++ • Just create normal functions passing the enum as parameter C# var bitangent = orientation.GetBitangent().AsAxis().GetMask(); C++ auto bitangent = FezMath::GetMask(FezMath::AsAxis(FezMath::GetBitangent(orientation)));
  • 14. Conversion • Lambda expressions & delegates • Game code heavily used lambda expressions for events, list queries ... • Delegates were used a lot too (threads, scheduled operations, scripting…) • They don’t have direct conversion to C++ … • … but they have for C++11 • Lambdas and std::function<>
  • 15. Conversion C# GameState.LoadSaveFile(() => GameState.LoadLevelAsync(Util.NullAction)); C++ get_GameState()->LoadSaveFile([=] () { get_GameState()->LoadLevelAsync([=] () { }); }); C# return new LongRunningAction((elapsed, since) => component.IsDisposed); C++ return LongRunningAction::Create([=] (float elapsed, float since) -> bool { return component->get_IsDisposed(); });
  • 16. Conversion • Nested lambdas caused problems with the converter • Corrupted, half-converted files • Unbalanced brackets generation • Unconverted c# code • Missing pieces of functions • Find the offending code, comment, re-convert the file, and manually convert that piece of code
  • 17. Conversion C# DotService.Say("DOT_ANTI_A", true, false).Ended = () => { DotService.Say("DOT_ANTI_B", true, false).Ended = () => { DotService.Say("DOT_ANTI_C", true, false).Ended = () => { DotService.Say("DOT_ANTI_D", true, true).Ended = CheckCubes; };};}; C++ get_DotService()->Say("DOT_ANTI_A", true, false)->Ended = [=] () { get_DotService()->Say("DOT_ANTI_B", true, false)->Ended = [=] () { get_DotService()->Say("DOT_ANTI_C", true, false)->Ended = [=] () { get_DotService()->Say("DOT_ANTI_D", true, true)->Ended = [=] { CheckCubes(); }; }; }; };
  • 18. Garbage Collector • FEZ had random stuttering due to the GC kicking in • Deterministic object destruction preferred • Reference counting • C++11’s std::shared_ptr<> • Caused its own kind of bugs ☹
  • 19. Garbage Collector • Circular references • Try to access shared_from_this() in constructors • Capturing this on lambdas caused problems (no reference increment)
  • 20. Garbage Collector void SoundEmitter::FadeOutAndDie(float forSeconds) { void MovingGroupsHost::MovingGroupState::StopSound() { eAssociatedSound->FadeOutAndDie(0.25f); eAssociatedSound.reset(); } Waiters::Interpolate(forSeconds, [=] (float s) { set_VolumeFactor(volumeFactor * (1 - s)); } , [=] () { if (get_Cue() != nullptr && !get_Cue()->get_IsDisposed() && get_Cue()->get_State() != SoundState::Stopped) get_Cue()->Stop(true); }); }
  • 21. Garbage Collector void SoundEmitter::FadeOutAndDie(float forSeconds) { auto _this=shared_from_this(); Waiters::Interpolate(forSeconds, [=] (float s) { _this->set_VolumeFactor(volumeFactor * (1 - s)); } , [=] () { if (_this->get_Cue() != nullptr && !_this->get_Cue()->get_IsDisposed() && _this->get_Cue()->get_State() != SoundState::Stopped) _this->get_Cue()->Stop(true); }); }
  • 22. Reflection • Game scripting used reflection to: • Trap scripting objects events by name • Invoke methods by name • We implemented method, event, triggers… descriptors for scripting objects • Generated dynamic methods by using IL Emit • No dynamic code generation
  • 23. Reflection script key=9 { name "Untitled" triggers { trigger { event "Enter" object { type "Volume" identifier 4 } } } actions { action { operation "ChangeLevelToVolume" arguments "LIGHTHOUSE_HOUSE_A" "1" "True" "True" object { type "Level" } } } }
  • 24. Reflection std::shared_ptr<EntityDescriptor> IVolumeService::GetEntityDescriptor() { //Operations std::unordered_map<String,MethodDesc> operations; operations["FocusCamera"] = MethodDesc([=] (std::vector<MultiTypeParameter> &params) -> std::shared_ptr<LongRunningAction> {return FocusCamera(params[0].I, params[1].I, params[2].B); },3 ) ; operations["SetEnabled"] = MethodDesc([=] (std::vector<MultiTypeParameter> &params) -> std::shared_ptr<LongRunningAction> {SetEnabled(params[0].I, params[1].B, params[2].B); return nullptr;},3 ) ; //Properties std::unordered_map<String,PropertyDesc> properties; properties["GomezInside"] = PropertyDesc([=] (int id) -> MultiTypeParameter { MultiTypeParameter mt; mt.B=get_GomezInside(id); return mt; },MultiType::BOOL); //Events std::unordered_map<String,EventHandlerDesc> events; events["Enter"] = EventInstance(&Enter,&Exit); events["Exit"] = EventInstance(&Exit); return std::make_shared<EntityDescriptor>("Volume","Volume",false,operations,properties,events); }
  • 25. Reflection • Service dependencies were resolved using reflection [ServiceDependency] public ISoundManager SoundManager { protected get; set; } [ServiceDependency] public IContentManagerProvider CMProvider { protected get; set; } • In C++ there are no attributes, and also we can’t get the property names • This was not possible to resolve the same way
  • 26. Reflection • We created a base class with all the service set_ methods virtual, and doing nothing • The dependency resolver iterated all registered services • A macro called for each combination of property name and type, tried to dynamic_cast the service to the type, and if so, called the set_ method • All components derived from this class, so the overridden set_ functions actually set the value
  • 27. Reflection #define MY_SERVICE_SET(__propertyname,__serviceclass) if(std::dynamic_pointer_cast<__serviceclass>(service)!=nullptr) { std::shared_ptr<__serviceclass> private_##__propertyname##_##__serviceclass=std::dynamic_pointer_cast<__serviceclass>(service); injector->set_##__propertyname(private_##__propertyname##_##__serviceclass); } MY_SERVICE_SET(CameraManager,IGameCameraManager); MY_SERVICE_SET(SoundManager,ISoundManager) MY_SERVICE_SET(CMProvider,IContentManagerProvider) MY_SERVICE_SET(TargetRenderer,ITargetRenderingManager) MY_SERVICE_SET(TargetRenderingManager,ITargetRenderingManager) ...
  • 28. .NET Framework • Replacement for some .NET Framework libraries: • Threads & Synchronization • Almost direct map to native APIs • lock() blocks converted to mutex.Lock() and Unlock() • Files • Also easy to map, and BinaryReader/Writer gave us the endian safe file access.
  • 29. .NET Framework • String (Unicode) • String class derived from std::wstring, but with C# like methods (SubString(),Replace(),Split()..) • Collections (Dictionary, List, Array) • Converter automatically changed them to STL containers (unordered_map,list,vector) • Nullable types • Implemented our own Nullable<T> class
  • 30. .NET Framework • Events • Internally containing a std::list<std::function> • Adding a method to an event requires a lambda • C# CameraManager.ViewpointChanged += UpdateRotation; • C++ get_CameraManager()->ViewpointChanged += [=] () {UpdateRotation();}; • Initially same interface than C# (+=, -=) • No way to compare lambdas to remove, so we had to change interface and return ID • UpdateRotationDelegateId=get_CameraManager()->ViewpointChanged.Add([=] () {UpdateRotation();}); • get_CameraManager()->ViewpointChanged.Remove(UpdateRotationDelegateId);
  • 31. .NET Framework • LINQ was widely used to search • We implemented LINQ-like operations for STL list,vector, map: • Where, Any, All, Union, Exists... • Usage was a bit awkward sometimes C# if(!tracks.Any(y => y.Name == x.Track.Name)) C++ if(!Any<std::shared_ptr<AmbienceTrack>>(tracks,[=] (const std::shared_ptr<AmbienceTrack> &y) -> bool { return y->get_Name()==(*x)->Track->get_Name(); }))
  • 32. Bugfixing • Original game already had bugs • C# to C++ introduced new ones • Memory leaks (circular references) • Mixing normal and reference counted pointers to same object. Use after delete. • Returning reference to temporary object in get_ properties access: const Vector3 &TrixelEmplacement::get_Position() const { return Vector3(X, Y, Z); }
  • 33. Bugfixing • Mistakes during manual conversion • Missing parenthesis on -= operations • Errors converting lambda expressions in LINQ operations • Uninitialized member variables • C++11 compiler bugs !!
  • 34. Optimization • OK, now it worked… but slowly • CPU intensive code • Lots of geometry with inefficient instancing • Complex shaders
  • 35. Optimization (CPU) • std::shared_ptr is thread safe. We created a lightweight (unsafe) fast_ptr • Move some CPU intensive operations to another thread • Erasing std::vector elements is slow: • convert to std::list • replace removed element with last one and resize()
  • 36. MonoGame graphics • For PC, OpenGL based. • Two options: • Minimal OpenGL library for each platform • Custom MonoGame target for each platform • We anticipated GPU performance problems • Chose custom MonoGame targets
  • 37. MonoGame graphics • Allows platform-specific features • Fine tuning for platform • Assets optimized per platform (swizzled, tiled…) • Shaders rewritten and optimized for each platform
  • 38. Optimization (GPU) • FEZ doesn’t look like a GPU intensive game. • That’s wrong • “Trile” (tri-dimensional tile) made of 16x16x16 “trixels” (tri-dimensional pixel) • Built sculpting a solid trile, removing trixels. Generates a lot of geometry • Two pass rendering
  • 41. Optimization (GPU) • Excessive geometry was choking vertex shaders • Only one (while moving) or two (while rotating) trile faces visible most of the time • Quick rejection of non-visible faces in CPU (~⅚ of the total geometry) • Proper instancing • Huge speedup
  • 42. Optimization (GPU) • Complex effects were choking the pixel shaders • Simplified code paths • Wrote specific “fast path” shaders to avoid branching • Moved calculations to vertex shader when possible • Most shaders unnecessarily used “discard”
  • 44. New features • Cross-save (additional slot) • Transparent for the user if online • No progress merge, just latest data • Allows play offline, syncs when online • Stereoscopic 3D • Based on existing red/blue mode • Required extra tweaks