Difference between revisions of "Medusa effect"

From DoomWiki.org

[unchecked revision][quality revision]
(Rejected the last text change (by 178.234.210.144) and restored revision 91302 by Jartapran)
(30 intermediate revisions by 19 users not shown)
Line 1: Line 1:
The '''Medusa effect''' occurs when there is more than one [[wall patch]] in any "middle" [[wall texture]] of a two-sided [[sidedef]] that is visible in the display window. Due to a game engine limitation, in [[vanilla Doom]] the computer will slow to a crawl and make play impossible until the offending wall is out of view.
+
[[Image:Medusa effect(stone2).png|320px|thumb|Screenshot of a Medusa effect.]]
  
The effect is named for [[Wikipedia:Medusa|a creature in Greek mythology]]. Medusa is the most well-known of the Gorgons. The Gorgons were created from beautiful maidens who claimed to be more beautiful than the gods. The gods punished them by turning them into hideous monsters with live snakes for hair. The Gorgons are so ugly that anyone who looks upon them will turn to stone. The hero Perseus killed Medusa by using a mirror to cause Medusa herself to turn to stone by looking at her reflection.
+
The '''Medusa effect''' occurs when there is more than one [[wall patch|patch]] occupying the same column in any middle [[wall texture|texture]] of a two-sided [[linedef]] that is visible in the display window. Due to a game engine limitation, these will not display properly. The area where the middle texture would be displayed is instead a series of multicolored horizontal lines. This "wall" of multicolored lines appears to extend infinitely into the floor. Moving close to the wall will make the framerate in [[vanilla Doom]] slow to a crawl and make play nearly impossible until the offending wall is out of view.
 +
 
 +
To understand why this occurs, a basic understanding of the [[Doom rendering engine]] is required. The effect is due to the way multi-patch textures are loaded in memory. The game renders all middle textures on two sided walls with the same drawing function as sprites, which is {{c|R_DrawMaskedColumn()}}. This function correctly handles each of the columns along with the posts that make up the column. The problem does not exist in this function, but instead exists in the code that loads the texture into memory.
 +
 
 +
When a normal wall is drawn, the function {{c|R_DrawColumn()}} is used. When drawing it uses the height of the texture and disregards any offset and length information contained in posts and does not even bother to check for other posts to draw. This limitation also causes the [[Tutti-frutti effect]]. However, {{c|R_DrawMaskedColumn()}} takes into consideration the post offset and length.
 +
 
 +
When a texture needs to be loaded into memory, the function {{c|R_GenerateComposite()}} is called. This function loads the texture data from the WAD. When loading a texture, it runs through a list that was determined at load time. The list contains the number of patches that exist on each column, or rather the number of lumps for each column. When a column that has multiple patches is encountered, the game then calls {{c|R_DrawColumnInCache()}}. The problem arises in this function. The function {{c|R_DrawColumnInCache()}} takes a shortcut, it renders the column of the patch on top of the existing cache without checking the end of the column and does not update the existing post (offset and length) data. Thus, neither the height nor the offset of the column/post are ever updated. {{c|R_DrawMaskedColumn()}} then uses the invalid information. In short, after drawing a post the function checks to see if there are more posts afterwards (the value 255 means there are no more). It will continue to draw posts of varying length and offsets, pulling unrelated memory off the [[Zone memory|zone heap]] until by chance a byte with the marker value of 255 is hit, at which it will then terminate drawing.
 +
 
 +
Since the actual data for a texture varies, the end marker may be found early thus causing little or no slow down, or it could be found late where it causes an extreme slow down to occur. It is theoretically possible for the game to crash or freeze indefinitely if the conditions are correct, however there is always a 0.39% chance of landing on an end marker with each byte drawn.
 +
 
 +
The effect is named after {{wp|Medusa}}, the creature in Greek mythology who had live snakes for hair and was so ugly that a single glance at her would turn the beholder to stone.
  
 
==Sources==
 
==Sources==
  
 
This article is based on information in the [[Unofficial Doom Specs]].
 
This article is based on information in the [[Unofficial Doom Specs]].
 
 
[[Category:Errors and bugs]]
 
[[Category:Errors and bugs]]
 +
[[Category:Doom engine]]
 +
[[Category:Textures]]

Revision as of 15:32, 25 June 2017

Screenshot of a Medusa effect.

The Medusa effect occurs when there is more than one patch occupying the same column in any middle texture of a two-sided linedef that is visible in the display window. Due to a game engine limitation, these will not display properly. The area where the middle texture would be displayed is instead a series of multicolored horizontal lines. This "wall" of multicolored lines appears to extend infinitely into the floor. Moving close to the wall will make the framerate in vanilla Doom slow to a crawl and make play nearly impossible until the offending wall is out of view.

To understand why this occurs, a basic understanding of the Doom rendering engine is required. The effect is due to the way multi-patch textures are loaded in memory. The game renders all middle textures on two sided walls with the same drawing function as sprites, which is R_DrawMaskedColumn(). This function correctly handles each of the columns along with the posts that make up the column. The problem does not exist in this function, but instead exists in the code that loads the texture into memory.

When a normal wall is drawn, the function R_DrawColumn() is used. When drawing it uses the height of the texture and disregards any offset and length information contained in posts and does not even bother to check for other posts to draw. This limitation also causes the Tutti-frutti effect. However, R_DrawMaskedColumn() takes into consideration the post offset and length.

When a texture needs to be loaded into memory, the function R_GenerateComposite() is called. This function loads the texture data from the WAD. When loading a texture, it runs through a list that was determined at load time. The list contains the number of patches that exist on each column, or rather the number of lumps for each column. When a column that has multiple patches is encountered, the game then calls R_DrawColumnInCache(). The problem arises in this function. The function R_DrawColumnInCache() takes a shortcut, it renders the column of the patch on top of the existing cache without checking the end of the column and does not update the existing post (offset and length) data. Thus, neither the height nor the offset of the column/post are ever updated. R_DrawMaskedColumn() then uses the invalid information. In short, after drawing a post the function checks to see if there are more posts afterwards (the value 255 means there are no more). It will continue to draw posts of varying length and offsets, pulling unrelated memory off the zone heap until by chance a byte with the marker value of 255 is hit, at which it will then terminate drawing.

Since the actual data for a texture varies, the end marker may be found early thus causing little or no slow down, or it could be found late where it causes an extreme slow down to occur. It is theoretically possible for the game to crash or freeze indefinitely if the conditions are correct, however there is always a 0.39% chance of landing on an end marker with each byte drawn.

The effect is named after Medusa, the creature in Greek mythology who had live snakes for hair and was so ugly that a single glance at her would turn the beholder to stone.

Sources

This article is based on information in the Unofficial Doom Specs.