The ancient Blob
10 listopada 2009
FreeSpace is a 10-year-old game and despite the fact SCP developers have been doing great work since 2002 there are still many parts of code that were left unchanged. That means there is a great variety of antipatterns. Some of them are being solved while the others are so complex that their refactorization will require large amount of work. One of these antipatterns, easily found in FSO, is The Blob.
The Blob Class is a class that has a huge number of members and is given many, loosely related responsibilities. It is a procedural design, therefore, it is considered as antipattern and an existence of such thing in any object-oritented code is a problem. More elaborated description of The Blob is available here.
FreeSpace used to support both DirectX and OpenGL, after 2002 the majority of new features was implemented only in OpenGL thus DirectX code became outdated soon and eventually was removed from the code. Unfortunately, the original mechanism that allowed the engine to support two APIs is still present in the code.
In OOP the best way to design the code that implements the one interface in two different ways is to take advantage from virtual member functions. The original FreeSpace developers did the same, but without the "object-oriented" part. They created structure screen that consist of over 100 function pointers (the whole structure has 277 lines of code). Actually, they implemented some kind of virtual functions table that was filled at start-up with the addresses of appropriate functions.
What's more, this structure also stores data required by rendering functions, such as screen resolution, fog settings, alpha blending configuration, etc. In addition to that, it still grows, new graphics functions are being added to the list. The situation, probably won't improve until somebody rewrites a large amount of graphics code in OOP manner.
typedef struct screen { uint signature; int max_w, max_h; /* lots of things here */ bool recording_state_block; int current_state_block; void (*gf_start_state_block)(); int (*gf_end_state_block)(); void (*gf_set_state_block)(int); //switch onscreen, offscreen void (*gf_flip)(); /* lots of things here */ void (*gf_gradient)(int x1, int y1, int x2, int y2, bool resize); void (*gf_circle)(int x, int y, int r, bool resize); void (*gf_curve)(int x, int y, int r, int direction); /* lots of things here */ void (*gf_render_buffer)(int, int, ushort*, uint*, int); int (*gf_make_flat_buffer)(poly_list*); int (*gf_make_line_buffer)(line_list*); /* lots of things here */ } screen;
It is not surprising that ten years ago programmers didn't thought about OOP and used C to create a computer game. In procedural design such structure is not a "pure evil" as much as in object-oriented design. Unfortunately, nobody bothered to improve that part of FSO code and structure screen still scares unsuspecting people.
Nevertheless, such nasty parts of code may be very interesting (especially for the coders that don't remember the "good old days"). They show how much changed the techniques programmers use and give an general idea how much it will change. Procedural programming ten years ago, object-oriented now and something completely new in the next 10 years (maybe something that will evolve from data-driven component design that is more and more popular among game developers).
Komentarze do wpisu "The ancient Blob":
1.
SebaS86 napisał(a):
10 listopada 2009, 20:38:24
Ten sposób jest jednak ciut wydajniejszy, pomijamy jeden wskaźnik po drodze, który wykorzystywany jest do wskazania vtable - akurat w takim miejscu ten wybór mógł być uzasadniony, w końcu Freespace rusza na bardzo leciwym już sprzęcie bez najmniejszych zgrzytów.
2.
Paweł Dziepak napisał(a):
10 listopada 2009, 20:45:24
Zwróć uwagę na to, że obecnie FreeSpace wspiera tylko OpenGL więc cała ta zabawa ze wskaźnikami jest kompletnie niepotrzebna.
Ten kod w momencie gdy powstawał prawdopodobnie był w porządku, złe jest tylko to, że pozostał w praktycznie niezmienionym stanie do dzisiaj. Jeden wskaźnik więcej to jednak za mało, żeby uzasadnić istnienie czegoś takiego w obiektowo zorientowanym kodzie.
3.
SebaS86 napisał(a):
10 listopada 2009, 22:40:35
Drugie "za" to powód ekonomiczny. Nie dotyka się czegoś co już jest i działa. To, że pozostało tylko wsparcie OGL nie oznacza, że producent musiałbym ponieść dodatkowy nakład na czyszczenie kodu, testowanie, poprawianie błędów i dopieszczanie takich dupereli. ;)
4.
Paweł Dziepak napisał(a):
10 listopada 2009, 22:44:42
To jest projekt open source więc producenta który ponosi koszty nie ma. Kod wsparcia OGL jest cały czas rozbudowywany, a takie kwiatki jak to tylko komplikują architekturę systemu. Na dłuższą metę nie opłaca się czegoś takiego trzymać. Powód ekonomiczny tu nie działa.
Dobra architektura znaczy naprawdę wiele, bo ułatwia wiele innych działań. Dodatkowe nakłady pracy czy ewentualny minimalny spadek wydajności (jeżeli jednak powrócimy do DirectX) nie są wystarczającymi argumentami.
Dodaj komentarz: