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.