cisc 326 – video game architecture: doom 3 – concrete ... · this report is an analysis of the...

16
CISC 326 – Video Game Architecture: Doom 3 – Concrete Architecture and Reflexion Analysis Gabriel Bufardeci 10100032 12gb27 Seema Hejazi 10050728 11sh68 David Anbinder 10111367 13daa Kilby Baron 10100345 12kjb4 Abhishek Patel 10119736 13ap53 1

Upload: others

Post on 17-Oct-2020

9 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

CISC 326 – Video Game Architecture:

Doom 3 – Concrete Architecture and Reflexion Analysis

Gabriel Bufardeci 10100032 12gb27

Seema Hejazi 10050728 11sh68

David Anbinder 10111367 13daa

Kilby Baron 10100345 12kjb4

Abhishek Patel 10119736 13ap53

1

Page 2: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

Table of Contents

Abstract

Introduction

Concrete Analysis

High­Level Architecture

Sequence Diagrams:

a. Create New World

b. Move Forward in Game World

Design Patterns

Lessons Learned

Conclusion

2

Page 3: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

Abstract

This report outlines the concrete architecture of the game Doom3. The key points touched upon in this paper includes our derivation of the concrete architecture, a reflexion analysis on new connections, walkthrough of two sequence diagrams, observed design patterns, in­depth architecture of a subsystem and lessons learned. The Doom3 engine was divided into sub­components according to observed file names and expected function. Any components in question were moved to "Other" sub­component to be sorted in the future. At first glance, the concrete code was nearly a complete graph. Sub­components were logically moved into appropriate groupings as we analysed its code base. We noticed an observer pattern during input monitoring and an adapter design pattern for render/update calls. We decided to analyse the Animation subsystem as it had fewer files and was expected to be easier to understand. It was then split into Test Model, Animation Blend, Animation Import and Animate. Upon code review it was determined that the animation unit makes for smooth transitions between completely different animation frames and that each animation affects a unique set of bones. We modeled the idTech4 engine to have 7 subsystems; Renderer, Libraries, Gameplay Foundations, Sound and Collision & Physics all communicating through a Platform Abstraction Layer. Our initial design choice of an Object Oriented & Layered Architecture remains although there are many layer bypasses for expected efficiency reasons.

Introduction

This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released in 2004, the source code of which is available online. In the first assignment, our team analyzed the high level architecture of Doom 3, and with the help of online research and reference architectures, we produced a conceptual architecture for the game. In this assignment, our team dug deeper into the source code. We revised our conceptual architecture, and with the help of code analysis tools, we mapped the components of Doom 3 into sub­systems to create a concrete architecture for the game.

To analyze the source code, our team was given access to a tool called Understand. Understand helped us visualize the structure of the game files, and analyze different dependencies. Using the conceptual architecture as a guideline, the components of the game were divided between the conceptual sub­systems. Arrows between the sub­systems mark how many files from one system depend on files from another.

The initial mapping of components to sub­systems left far more connections than anticipated in the conceptual. Some of these dependencies were rational, while others did not appear to be

3

Page 4: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

necessary. By analyzing the calls between components, certain files were moved between components to sub­systems which appeared to be a better fit. After rearranging the system files to minimize dependencies as much as possible, our team was able to produce a concrete architecture for the system. With our new information, the original conceptual architecture was revised.

While we were expecting a relatively strict layered architecture, our analysis demonstrated that in fact the sub­system form an almost complete graph. Each dependency that was unexpected was analyzed carefully. In the Understand tool, the dependencies provided links to the source code which allowed us to carefully examine function calls and rationalize their existence. Each dependency was examined this way, and rationalized.

For the skeletal animation sub­system, we analyzed the source code in even more detail. The mini architecture within the subsystem is explored thoroughly, and its inner workings are mapped out. The inner subsystems dependencies are all analyzed and rationalized, as well as the skeletal animation’s dependencies with the rest of the system.

In a similar fashion we were able to revise our sequence diagrams. Diving into the source code, specific function calls for each action were listed. The sequence diagrams clearly demonstrate exactly which functions call one another when a command is entered by the user. The function calls are all rationalized.

The game’s overall design pattern follows a clear observer pattern. The player is treated as the subject and the various game logic and behaviour acts as the observer, reacting accordingly to the changes. This relationship is explored in detail. However, the design patterns of the sub­systems vary. For example, the rendering engine subsystem can be identified as an adapter pattern.

The process of completing the Doom 3 concrete architecture didn’t come without it’s challenges, but our team was able to learn from these challenges along the way. In the end, the concrete architecture was more loosely layered than we had anticipated, and it had a high level of coupling. In the end, we still concluded that the system follows an object oriented and layered architecture, with an observer design pattern.

4

Page 5: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

Concrete Analysis

In our original conceptual architecture, we believed that this game contained some relatively strict layers separating the sections of the system into modular sets of components. However, this was not the case. After we transferred this logic into the Understand program, what we found was not optimal in any way.

The concrete interpretation of our conceptual architecture ended up being a complete graph, with two­way dependencies strictly. This was a problem because, right from the start, we saw endless dependencies that we just could not understand, so we knew that we had to make some changes.

One of the first things we noticed is that the Game­Specific Subsystems component only contained one item and it was “gamesys”. For our purposes, we believed that the function of this component was in direct coordination with what Gameplay Foundations did, and that it was very cohesive with the items in that subsystem, so we moved it. This reduced the size of our architecture, but it still did not make a whole lot sense. Next, we moved “script” from Other into Platform Independence since it is a low­level component that acts as a liaison for the game systems with the platform. We also decided to move “ui” from Gameplay Foundations to the renderer. This made sense to us since the user interface does need to be drawn by the hardware anyway, so it seemed to fit well with the Rendering Engine. After that, we made yet another discovery. We noticed that the dependencies on the Libraries subsystem were unusually similar to that of another subsystem, but more importantly, the “typeInfo” component. Once we realized that typeInfo is a component that is looked at for data and then left alone, we learned that it actually belongs in the Libraries subsystem. Finally, we took the “sound” component out of

5

Page 6: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

Libraries and made it its own subsystem. We did this because we had the realization that Libraries was depending on the Rendering Engine with components that did not make sense. We then noticed it was because Sound depended on the Rendering Engine. We believe this is because of performance reasons. It is often discovered in video game development, that removing the coupling of graphics with certain subsystems (possibly sound), that the quality of the game suffers. Glitches involving sound and graphic discrepancies appear and the general performance of the game suffers as the division gets greater.

The next thing we needed to do is use this new information to make the required changes to our original conceptual architecture. How we did this, is by outlining all of the dependencies that we did not expect and outlining their rationale. We then determined whether this dependency made sense or not and if it did, we had to decide if it belonged on the revised conceptual architecture.

First, we focused on Gameplay Foundations; we noticed that Collision & Physics, Skeletal Animation, Rendering Engine and Platform Independence all depended on Gameplay Foundations. Conceptually we thought that Gameplay Foundations would be depending on the lower subsystems to do their jobs, so that it could get all that information and turn it into the game that people play. We found that this made sense in the conceptual point of view, but in the concrete point of view, those subsystems need some information from the game world itself. This results in every subsystem depending on Gameplay Foundations in the concrete architecture, but this is for good reason.

Collision & Physics depends on Gameplay Foundations because it needs information about the game world. It needs to know the positions of objects and actors in the game world as well as certain, game­specific physics constants and the like. All of this is because the Collision & Physics engine in Doom 3 is completely separate from the

6

Page 7: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

game. It is a purely modular system which happens to be pretty massive. Because it is separate from the game, all the information that it needs about the game world must be transferred to it somehow and this is what the Gameplay Foundations subsystem does. Skeletal Animation depends on Gameplay Foundations because it needs to know which animation(s) are playing, as well as the ones that will be played. See, Skeletal Animation does not really play animations, it simply handles lerping between frames, frame commands and blending bone weight as well as animations. Therefore, with only the knowledge of which animations are being played as well as the proceeding one, it will be able to do its job. The Rendering Engine depends on Gameplay Foundations because the Rendering Engine is broken into three parts. One of which is RenderWorld, which contains all of the render models and textures in the scene in a way that has strong synergy with Doom 3’s culling options. RenderWorld loads all of the relevant models and textures needed by talking to Gameplay Foundations, and sends them to the rest of the Rendering Engine to process.

Next, we looked at the outward dependencies coming out of Libraries. We believed this to be a subsystem that is accessed and left alone, but it does go beyond that, albeit, not by much. Libraries depends on Rendering Engine possibly for some constant sharing or maybe to share a commonly used rendering function with itself or other subsystems. The evidence we have is only an include of a Rendering Engine file in the “math” component of Libraries. Previously we also had a dependency of Libraries to the Rendering Engine for Sound reasons, but that was removed with one of our conceptual changes.

Finally we focused on the unexpected dependencies related to this system’s Platform Independence layer. We found a very odd outward relationship to Skeletal Animation, and it seems that only a single call to GetJoint() is made. We could not exactly reason with this, so we continued. Next we saw that it depends on Sound and it seem that it is because it needs to talk to the Sound subsystem so that it can interface that with the according platform’s sound device; this relationship is similar in the opposite direction as well. Platform Independence depends on the Rendering Engine and vice­versa, but this is quite logical. The Rendering Engine needs to interface with the platform’s video hardware in some way, and that is this subsystem’s job. Likewise in the other direction, the Platform Independence layer needs the information from the Rendering Engine for optimization reasons as well as compatibility reasons. It talks to Collision & Physics because it is separate from the rest of the system, and needs information about it, and vice­versa, for both processing and calculating the collision and physics actions as well as providing the ability to simulate these actions on various platforms. Although Platform Independence depending on Skeletal Animation makes little sense, it is depended on by Skeletal Animation for good reason. Skeletal Animation, as mentioned above, handles frame commands, lerping, etc. This means that optimization related to the platform’s hardware is absolutely essential if the performance of this subsystem is to be optimized. Finally, the relationship between Platform Independence and Gameplay Foundations seems quite illogical, but it only

7

Page 8: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

takes a little bit of analysis to realize what’s going on. Inside Gameplay Foundations is a “tools” component, and these involve various initialization and compiling options which are things that require heavy use of the system’s hardware. And like anything else in this system, when something wants to talk to the hardware, they have to talk to the Platform Independence layer first.

High­Level Architecture

When we investigated the unexpected relationships related to the Platform Independence layer, we actually found that it has a two­way dependency relationship with every component in this system. This is because, true to its Object­Oriented roots, absolutely everything needs to get through this layer to reach the platform’s hardware and unlike what we originally expected, Libraries absolutely does not act as a liaison for this. What we find actually, is that Libraries is off on its own, with no conceptual outward dependencies and sparingly few concrete ones and it is bypassed fully, and thus is not actually a layer in the architecture.

This is interesting because we see a part of the layered architecture completely disappear. We must consider the possibility of ditching the layered mentality altogether; is this the best option? Well, if you look at it after a bit of restructuring, you will see that Platform Independence is a layer between the system and the platform, and gameplay foundations is a layer between the workings of Doom 3 and the components that actually make it work. Thus, we can still safely say that this architecture is an Object­Oriented Layered architecture.

8

Page 9: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

Sequence Diagrams

Since the sequence diagrams are too long and have been previously deemed illegible in report format, they have been posted on our group website and can be downloaded for a more detailed view. The following write up refers to the two sequence diagrams posted at:

https://cisc326.wordpress.com/2015/11/13/revised­sequence­diagrams/

Create New World:

Assume: User has already opened the game and is on the main menu screen

The first sequence diagram depicts the interaction between created subsystems to create a new world. The user clicks new game which is first handled by the Platform Abstraction Layer (PAL). It contains the methods required to translate the inputs/outputs to and from various operating systems (Windows,Linux,Mac). This is why it is believed to be the starting point of all user input into the system. Events.cpp, a file in our PAL, contains various functions to poll for user input (an event). With the use of SDL_PollEvent(&ev) from within Sys_GetEvent() the system can translate the users' input into an instruction for the game to perform.

Sys_GetConsoleKey() is used to track a mouse click or select button (typically Enter). If Enter was hit, the campaign button, default selection, is pressed. If it was a mouse click, the location of the mouse is also needed, which can be checked with Sys_GrabMouseCursor(). This process is repeated again as the user selects a difficulty. The information generated is read by Gameplay Foundations which begins building a new world. Function calls like StartNewGame(mapName) and MoveToNewMap(mapName), found in Session.cpp are assumed to begin the loading process as it makes a call to cmdSystem to ExecuteCommandBuffer().

The render system is called to begin loading the world. At the same time, the sound system is sent the same message. This is so that appropriate sounds can be loaded for initial cut­scenes, dialogue and sound effects. The renderer returns with a scene and begins to load entities from the libraries. Each entity rendered requires their own sound coordinates (to muffle/distort appropriately). This is why the renderer has a dependency on sound. Once the sound files have been loaded, the renderer and the sound subsystem send data to the PAL and the first scene is displayed on the user's console. The PAL produces appropriate output for said operating system.

9

Page 10: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

Move Forward:

Once in game, after any introductory cutscenes, one of the first things a user typically does is look around or move forward. We decided to look into the use case of moving forward as it must check for collisions while looking around involves polling the mouse and updating camera view; Thought to be too similar to the first use case.

Sys_GetEvent gets user input and it is then processed by gameplay foundations via Sys_GetConsoleKey. The Platform Abstraction Layer also contains a function mapkey() which maps all special characters to use them for access to commands such as quick save + screenshots. It was first thought out that mapkey() was the function used for simple inputs such as WASD or mouse movements. Upon further analysis it was observed that it is for keys >= SDLK_z, anything <= z will be returned straight away.

The system acknowledges that the user wants to move forward by processing the input of the 'w' key and begins to check if any rigid bodies (npc/monster entities) or static elements like a wall or door are in the character's immediate path via CheckForCollision(). One of the physics files contains ActivateContactEntities() which is called to turn on collisions between npcs/monsters and the user. It should be called before checking for collisions but doesn't necessarily need to be included in the diagram if we were to assume entity collision points are already active.

Once the user's path is verified, physics_player talks to Skeletal Animation to ensure synchronization between the character model's animation and specified movement speeds and friction chosen within the physics platform. Skeletal animation pulls models from the gameplay foundations which contains animation scripts. An animation is returned and it is rendered to the screen along with the updated view of the world.

10

Page 11: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

Concrete architecture and analysis of a subsystem : Skeletal Animation

11

Page 12: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

We chose to focus on the skeletal animation subsystem because is important for the flow of the game. The skeletal animation subsystem might be thought to actually decides which animations to play, however this is false. Those decisions come from scripts. Skeletal animation holds within it the subsystem Anim, which holds the the practical animation controls. It is in charge of blending animations, leaping between frames, blending bone weights and calling frame commands. The Anim subsystem can be split into four even smaller subsystems: Test Model, Animation Blend, Animation Import and Animate. Test model depends on all three other subsystems to create a fake entity 100 units in front of the current view position, as a test. It will remain immobile, so the user can move around it to view it from different angles. Animation Blend and Animation Import both depend on Animate as well. All three rely on Animate for the

12

Page 13: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

functions that hold the trace and collision models. It also utilizes the geometric dictionaries as well as the data structures that apply universally within Anim.

As far as external dependencies, the first and most important to mention is the connection to the Gameplay Foundation. The Gameplay Foundation subsystem has five subsystems within itself with dependencies on Skeletal Animation called: Framework, Game, Tools, AI and Game System. Game holds the program Game Local which depends on all the subsystems of Anim, because it is where the local implementation of the public game occurs. In other words, this means it is where the game object is initialized at startup, so it requires the each of Anim’s subsystems. Animation Blend and Animate are also depended on by UI which is within the Rendering engine, the former needed by the Platform Abstraction Layer, by Script also. The dependencies also go outward; Animate depends on Game as well, and connects with the physics file. It also depends on the Rendering Engine to model the animations. Animation blend depends on Game and the Rendering Engine too, but connects with AI. Animation Import, Animation Blend and Test Model depend on Game System for the system commands.

In analyzing the source code of Doom 3, you can see the flow created by an organized Skeletal Animation subsystem. There are four unique animation channels: ‘torso’, ‘legs’, ‘head’ and ‘eyelids’. There is also a fifth channel called ‘all’ which controls all the other channels. With this system, a different animation can be playing on each animation channel simultaneously. This happens in one single screen and mesh but each animation affects a unique set of bones. This is what is handled by the Animation Blend system. It makes for smooth movements as well as soft transitions between completely different animations, such as in the case of the user changing a weapon, which requires very quick transitioning.

Design Pattern

We identify our design pattern as observer pattern, this is mainly due to its ability to process changes and react according. For a game such as doom 3 it is highly beneficial to use observer pattern and we can treat the player as the subject and the various game logic and behaviour can an act as an observer and react accordingly to the changes. The actions such as movement polling serves as a good example for utilizing observer pattern, in our concrete architecture we note the interdependency between skeleton animation and gameplay foundations, where most of the input query is handled and the correct actions are taken. The skeleton animation component is in charge of handling the post processing of the movement animation before being sent to the rendering engine. The understanding of placing an observer object in the gameplay foundation allows the game to quickly compute the reactions to the actions taken by the subject. Thus reducing the performance strains on the system and ensuring smooth gameplay for the player. Furthermore, the subject is capable of being monitored by multiple observers, this allows reactions from different observers, and example of this would be that sound can be played depending on the action while simultaneously rendering the action to the screen. In the diagram

13

Page 14: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

below it can be seen how the input polling is handled in terms of observer pattern while ensuring consistency between components.

Figure 1: Observer design pattern for input monitoring

Figure 2: Adapter design pattern for render/update calls

The rendering engine subsystem can be identified as an adapter pattern due to the multiple subsystems contained within which reutilize the main draw() and update() calls. Meaning classes can be reused without changing them to fit the individual needs for each subsystem. This option allows for creation of abstract objects which rely on super class which can share common methods. The main thread of the game which handles updating the game also

14

Page 15: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

handles the update call to rendering classes, thus having a common method call reduces the need for independent calls and reduces the extra objects which need to be created to handle simple behaviour.

Lessons learned

Throughout the process of analyzing the source code of Doom 3, and mapping the components into subsystems to form our conceptual architecture, there were many lessons learned. These insights fall into two categories: lessons learned about completing work efficiently as a group, and lessons learned about the Doom 3 architecture.

Right off the bat after starting this assignment, our group ran into an obstacle trying to analyze the Doom 3 source code. We were given a tool to explore the source code called “Understand”. Understand is a very powerful tool for laying out complex system architectures, mapping components into subsystems, and analyzing dependencies. Unfortunately, the learning curve for the Understand tool is very steep. The software we were trying to use is likely meant for experts who have years of experience and training; diving head first into this assignment, our team spent several hours just to learn the tool. Our team’s struggle with Understand was furthered by the fact that it would not run on every team member’s computer, and it would often crash, erasing all of our work.

To overcome this obstacle, our team learned that the best way to extract information from Understand is to nominate an “Understand Expert” in the group. Instead of wasting work hours teaching the software to each group member, our expert focused mainly on using the tool, and shared the extracted information in the form of images. Sharing images protected us from losing information due to crashing, and having a single expert saved us some time.

Our group also ran into a challenge working as a group due to our varying schedules. With every group member having radically different schedules, we were never able to meet up all at once. Instead, we learned to divide the work up into parts which team members can complete individually. With the help of an online messaging group, we were able to share our work and collaborate remotely.

While producing our conceptual architecture for Doom 3, we were surprised by the amount of dependencies between components. We learned that the Doom 3 architecture is very highly coupled, with our subsystems forming a very nearly complete graph. Certain of these dependencies were due to only one or two function calls, and we were able to simplify the graph by moving parts of the source code to different subsystems. However, despite our efforts to remove as many dependencies as possible, the coupling in this system is very high.

15

Page 16: CISC 326 – Video Game Architecture: Doom 3 – Concrete ... · This report is an analysis of the software architecture of the video game Doom 3. Doom 3 is a video game released

Conclusion

Through the concrete analysis process, we learned a lot about how Doom 3’s architecture works. The sequence diagrams also changed a little bit, because some subsystems didn’t quite do what we thought they did, but we really learned a lot as we figured things out. As we did the reflexion analysis, it seemed that the layering in our conceptual architecture was breaking down and leaving only an object oriented architecture. By the end, we did maintain the layered part of our architecture, but not by much; it was really interesting to see what we did right and what we did wrong in the conceptual architecture, and it was cool to see how close we were.

16