summaryrefslogtreecommitdiff
path: root/glew/auto/EGL-Registry/extensions/NV/EGL_NV_coverage_sample.txt
diff options
context:
space:
mode:
Diffstat (limited to 'glew/auto/EGL-Registry/extensions/NV/EGL_NV_coverage_sample.txt')
-rw-r--r--glew/auto/EGL-Registry/extensions/NV/EGL_NV_coverage_sample.txt554
1 files changed, 554 insertions, 0 deletions
diff --git a/glew/auto/EGL-Registry/extensions/NV/EGL_NV_coverage_sample.txt b/glew/auto/EGL-Registry/extensions/NV/EGL_NV_coverage_sample.txt
new file mode 100644
index 0000000..e016a6f
--- /dev/null
+++ b/glew/auto/EGL-Registry/extensions/NV/EGL_NV_coverage_sample.txt
@@ -0,0 +1,554 @@
+Name
+
+ NV_coverage_sample
+
+Name Strings
+
+ GL_NV_coverage_sample
+ EGL_NV_coverage_sample
+
+Contact
+
+ Gary King, NVIDIA Corporation (gking 'at' nvidia.com)
+
+Notice
+
+ Copyright NVIDIA Corporation, 2005 - 2007
+
+Status
+
+ NVIDIA Proprietary
+
+Version
+
+ Last Modified Date: 2007/03/20
+ NVIDIA Revision: 1.0
+
+Number
+
+ EGL Extension #17
+ OpenGL ES Extension #72
+
+Dependencies
+
+ Written based on the wording of the OpenGL 2.0 specification
+ and the EXT_framebuffer_object specification.
+
+ Written based on the wording of the EGL 1.2 specification.
+
+ Requires OpenGL-ES 2.0 and OES_framebuffer_object.
+
+ Requires EGL 1.1.
+
+Overview
+
+ Anti-aliasing is a critical component for delivering high-quality
+ OpenGL rendering. Traditionally, OpenGL implementations have
+ implemented two anti-aliasing algorithms: edge anti-aliasing
+ and multisampling.
+
+ Edge anti-aliasing computes fractional fragment coverage for all
+ primitives in a rendered frame, and blends edges of abutting
+ and/or overlapping primitives to produce smooth results. The
+ image quality produced by this approach is exceptionally high;
+ however, applications are render their geometry perfectly ordered
+ back-to-front in order to avoid artifacts such as bleed-through.
+ Given the algorithmic complexity and performance cost of performing
+ exact geometric sorts, edge anti-aliasing has been used very
+ sparingly, and almost never in interactive games.
+
+ Multisampling, on the other hand, computes and stores subpixel
+ (a.k.a. "sample") coverage for rasterized fragments, and replicates
+ all post-alpha test operations (e.g., depth test, stencil test,
+ alpha blend) for each sample. After the entire scene is rendered,
+ the samples are filtered to compute the final anti-aliased image.
+ Because the post-alpha test operations are replicated for each sample,
+ all of the bleed-through and ordering artifacts that could occur with
+ edge anti-aliasing are avoided completely; however, since each sample
+ must be computed and stored separately, anti-aliasing quality is
+ limited by framebuffer storage and rendering performance.
+
+ This extension introduces a new anti-aliasing algorithm to OpenGL,
+ which dramatically improves multisampling quality without
+ adversely affecting multisampling's robustness or significantly
+ increasing the storage required, coverage sampling.
+
+ Coverage sampling adds an additional high-precision geometric
+ coverage buffer to the framebuffer, which is used to produce
+ high-quality filtered results (with or without the presence of a
+ multisample buffer). This coverage information is computed and stored
+ during rasterization; since applications may render objects where the
+ specified geometry does not correspond to the visual result (examples
+ include alpha-testing for "imposters," or extruded volume rendering
+ for stencil shadow volumes), coverage buffer updates may be masked
+ by the application, analagous to masking the depth buffer.
+
+IP Status
+
+ NVIDIA Proprietary
+
+New Procedures and Functions
+
+ void CoverageMaskNV( boolean mask )
+ void CoverageOperationNV( enum operation )
+
+New Tokens
+
+
+ Accepted by the <attrib_list> parameter of eglChooseConfig
+ and eglCreatePbufferSurface, and by the <attribute>
+ parameter of eglGetConfigAttrib
+
+ EGL_COVERAGE_BUFFERS_NV 0x30E0
+ EGL_COVERAGE_SAMPLES_NV 0x30E1
+
+ Accepted by the <internalformat> parameter of
+ RenderbufferStorageEXT and the <format> parameter of ReadPixels
+
+ COVERAGE_COMPONENT_NV 0x8ED0
+
+ Accepted by the <internalformat> parameter of
+ RenderbufferStorageEXT
+
+ COVERAGE_COMPONENT4_NV 0x8ED1
+
+ Accepted by the <operation> parameter of CoverageOperationNV
+
+ COVERAGE_ALL_FRAGMENTS_NV 0x8ED5
+ COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6
+ COVERAGE_AUTOMATIC_NV 0x8ED7
+
+ Accepted by the <attachment> parameter of
+ FramebufferRenderbuffer, and GetFramebufferAttachmentParameteriv
+
+ COVERAGE_ATTACHMENT_NV 0x8ED2
+
+ Accepted by the <buf> parameter of Clear
+
+ COVERAGE_BUFFER_BIT_NV 0x8000
+
+ Accepted by the <pname> parameter of GetIntegerv
+
+ COVERAGE_BUFFERS_NV 0x8ED3
+ COVERAGE_SAMPLES_NV 0x8ED4
+
+Changes to Chapter 4 of the OpenGL 2.0 Specification
+
+ Insert a new section, after Section 3.2.1 (Multisampling)
+
+ "3.2.2 Coverage Sampling
+
+ Coverage sampling is a mechanism to antialias all GL primitives: points,
+ lines, polygons, bitmaps and images. The technique is similar to
+ multisampling, with all primitives being sampled multiple times at each
+ pixel, and a sample resolve applied to compute the color values stored
+ in the framebuffer's color buffers. As with multisampling, coverage
+ sampling resolves color sample and coverage values to a single, displayable
+ color each time a pixel is updated, so antialiasing appears to be automatic
+ at the application level. Coverage sampling may be used simultaneously
+ with multisampling; however, this is not required.
+
+ An additional buffer, called the coverage buffer, is added to
+ the framebuffer. This buffer stores additional coverage information
+ that may be used to produce higher-quality antialiasing than what is
+ provided by conventional multisampling.
+
+ When the framebuffer includes a multisample buffer (3.5.6), the
+ samples contain this coverage information, and the framebuffer
+ does not include the coverage buffer.
+
+ If the value of COVERAGE_BUFFERS_NV is one, the rasterization of
+ all primitives is changed, and is referred to as coverage sample
+ rasterization. Otherwise, primitive rasterization is referred to
+ as multisample rasterization (if SAMPLE_BUFFERS is one) or
+ single-sample rasterization (otherwise). The value of
+ COVERAGE_BUFFERS_NV is queried by calling GetIntegerv with <pname>
+ set to COVERAGE_BUFFERS_NV.
+
+ During coverage sample rasterization the pixel fragment contents
+ are modified to include COVERAGE_SAMPLES_NV coverage values. The
+ value of COVERAGE_SAMPLES_NV is an implementation-dependent
+ constant, and is queried by calling GetIntegerv with <pname> set
+ to COVERAGE_SAMPLES_NV.
+
+ The command
+
+ CoverageOperationNV(enum operation)
+
+ may be used to modify the manner in which coverage sampling is
+ performed for all primitives. If <operation> is
+ COVERAGE_ALL_FRAGMENTS_NV, coverage sampling will be performed and the
+ coverage buffer updated for all fragments generated during rasterization.
+ If <operation> is COVERAGE_EDGE_FRAGMENTS_NV, coverage sampling will
+ only be performed for fragments generated at the edge of the
+ primitive (by only updating fragments at the edges of primitives,
+ applications may get better visual results when rendering partially
+ transparent objects). If <operation> is COVERAGE_AUTOMATIC_NV,
+ the GL will automatically select the appropriate coverage operation,
+ dependent on the GL blend mode and the use of gl_LastFragColor /
+ gl_LastFragData in the bound fragment program. If blending is enabled,
+ or gl_LastFragColor / gl_LastFragData appears in the bound fragment
+ program, COVERAGE_AUTOMATIC_NV will behave identically to
+ COVERAGE_EDGE_FRAGMENTS_NV; otherwise, COVERAGE_AUTOMATIC_NV will behave
+ identically to COVERAGE_ALL_FRAGMENTS_NV. The default coverage operation
+ is COVERAGE_AUTOMATIC_NV."
+
+ Insert a new section, after Section 3.3.3 (Point Multisample
+ Rasterization)
+
+ "3.3.4 Point Coverage Sample Rasterization
+
+ If the value of COVERAGE_BUFFERS_NV is one, then points are
+ rasterized using the following algorithm, regardless of whether
+ point antialiasing (POINT_SMOOTH) is enabled or disabled. Point
+ rasterization produces fragments using the same algorithm described
+ in section 3.3.3; however, sample points are divided into SAMPLES
+ multisample points and COVERAGE_SAMPLES_NV coverage sample points.
+
+ Rasterization for multisample points uses the algorithm described
+ in section 3.3.3. Rasterization for coverage sample points uses
+ implementation-dependent algorithms, ultimately storing the results
+ in the coverage buffer."
+
+ Insert a new section, after Section 3.4.4 (Line Multisample
+ Rasterization)
+
+ "3.4.5 Line Coverage Sample Rasterization
+
+ If the value of COVERAGE_BUFFERS_NV is one, then lines are
+ rasterized using the following algorithm, regardless of whether
+ line antialiasing (LINE_SMOOTH) is enabled or disabled. Line
+ rasterization produces fragments using the same algorithm described
+ in section 3.4.4; however, sample points are divided into SAMPLES
+ multisample points and COVERAGE_SAMPLES_NV coverage sample points.
+
+ Rasterization for multisample points uses the algorithm described in
+ section 3.4.4. Rasterization for coverage sample points uses
+ implementation-dependent algorithms, ultimately storing results in
+ the coverage buffer."
+
+ Insert a new section, after Section 3.5.6 (Polygon Multisample
+ Rasterization)
+
+ "3.5.7 Polygon Coverage Sample Rasterization
+
+ If the value of COVERAGE_BUFFERS_NV is one, then polygons are
+ rasterized using the following algorithm, regardless of whether
+ polygon antialiasing (POLYGON_SMOOTH) is enabled or disabled. Polygon
+ rasterization produces fragments using the same algorithm described in
+ section 3.5.6; however, sample points are divided into SAMPLES multisample
+ points and COVERAGE_SAMPLES_NV coverage sample points.
+
+ Rasterization for multisample points uses the algorithm described in
+ section 3.5.7. Rasterization for coverage sample points uses
+ implementation-dependent algorithms, ultimately storing results in the
+ coverage buffer."
+
+ Insert a new section, after Section 3.6.6 (Pixel Rectangle Multisample
+ Rasterization)
+
+ "3.6.7 Pixel Rectangle Coverage Sample Rasterization
+
+ If the value of COVERAGE_BUFFERS_NV is one, then pixel rectangles are
+ rasterized using the algorithm described in section 3.6.6."
+
+ Modify the first sentence of the second-to-last paragraph of section
+ 3.7 (Bitmaps) to read:
+
+ "Bitmap Multisample and Coverage Sample Rasterization
+
+ If MULTISAMPLE is enabled, and the value of SAMPLE_BUFFERS is one;
+ or if the value of COVERAGE_BUFFERS_NV is one, then bitmaps are
+ rasterized using the following algorithm. [...]"
+
+ Insert after the first paragraph of Section 4.2.2 (Fine Control of
+ Buffer Updates):
+
+ "The coverage buffer can be enabled or disabled for writing coverage
+ sample values using
+
+ void CoverageMaskNV( boolean mask );
+
+ If <mask> is non-zero, the coverage buffer is enabled for writing;
+ otherwise, it is disabled. In the initial state, the coverage
+ buffer is enabled for writing."
+
+ And change the text of the last 2 paragraphs of Section 4.2.2 to read:
+
+ "The state required for the various masking operations is three
+ integers and two bits: an integer for color indices, an integer for
+ the front and back stencil values, a bit for depth values, and a
+ bit for coverage sample values. A set of four bits is also required
+ indicating which components of an RGBA value should be written. In the
+ initial state, the integer masks are all ones, as are the bits
+ controlling the depth value, coverage sample value and RGBA component
+ writing.
+
+ Fine Control of Multisample Buffer Updates
+
+ When the value of SAMPLE_BUFFERS is one, ColorMask, DepthMask,
+ CoverageMask, and StencilMask or StencilMaskSeparate control the
+ modification of values in the multisample buffer. [...]"
+
+ Change paragraph 2 of Section 4.2.3 (Clearing the Buffers) to read:
+
+ "is the bitwise OR of a number of values indicating which buffers are to
+ be cleared. The values are COLOR_BUFFER_BIT, DEPTH_BUFFER_BIT,
+ STENCIL_BUFFER_BIT, ACCUM_BUFFER_BIT and COVERAGE_BUFFER_BIT_NV, indicating
+ the buffers currently enabled for color writing, the depth buffer,
+ the stencil buffer, the accumulation buffer and the virtual-coverage
+ buffer, respectively. [...]"
+
+ Insert a new paragraph after paragraph 4 of Section 4.3.2 (Reading Pixels)
+ (beginning with "If there is a multisample buffer ..."):
+
+ "If the <format> is COVERAGE_COMPONENT_NV, then values are taken from the
+ coverage buffer; again, if there is no coverage buffer, the error
+ INVALID_OPERATION occurs. When <format> is COVERAGE_COMPONENT_NV,
+ <type> must be GL_UNSIGNED_BYTE. Any other value for <type> will
+ generate the error INVALID_ENUM. If there is a multisample buffer, the
+ values are undefined."
+
+
+
+Modifications to the OES_framebuffer_object specification
+
+ Add a new table at the end of Section 4.4.2.1 (Renderbuffer Objects)
+
+ "+-------------------------+-----------------------+-----------+
+ | Sized internal format | Base Internal Format | C Samples |
+ +-------------------------+-----------------------+-----------+
+ | COVERAGE_COMPONENT4_NV | COVERAGE_COMPONENT_NV | 4 |
+ +-------------------------+-----------------------+-----------+
+ Table 1.ooo Desired component resolution for each sized internal
+ format that can be used only with renderbuffers"
+
+ Add to the bullet list in Section 4.4.4 (Framebuffer Completeness)
+
+ "An internal format is 'coverage-renderable' if it is COVERAGE_COMPONENT_NV
+ or one of the COVERAGE_COMPONENT_NV formats from table 1.ooo. No other
+ formats are coverage-renderable"
+
+ Add to the bullet list in Section 4.4.4.1 (Framebuffer Attachment
+ Completeness)
+
+ "If <attachment> is COVERAGE_ATTACHMENT_NV, then <image> must have a
+ coverage-renderable internal format."
+
+ Add a paragraph at the end of Section 4.4.4.2 (Framebuffer Completeness)
+
+ "The values of COVERAGE_BUFFERS_NV and COVERAGE_SAMPLES_NV are derived from
+ the attachments of the currently bound framebuffer object. If the current
+ FRAMEBUFFER_BINDING_OES is not 'framebuffer-complete', then both
+ COVERAGE_BUFFERS_NV and COVERAGE_SAMPLES_NV are undefined. Otherwise,
+ COVERAGE_SAMPLES_NV is equal to the number of coverage samples for the
+ image attached to COVERAGE_ATTACHMENT_NV, or zero if COVERAGE_ATTACHMENT_NV
+ is zero."
+
+Additions to the EGL 1.2 Specification
+
+ Add to Table 3.1 (EGLConfig attributes)
+ +---------------------------+---------+-----------------------------------+
+ | Attribute | Type | Notes |
+ +---------------------------+---------+-----------------------------------+
+ | EGL_COVERAGE_BUFFERS_NV | integer | number of coverage buffers |
+ | EGL_COVERAGE_SAMPLES_NV | integer | number of coverage samples per |
+ | | | pixel |
+ +---------------------------+---------+-----------------------------------+
+
+ Modify the first sentence of the last paragraph of the "Buffer
+ Descriptions and Attributes" subsection of Section 3.4 (Configuration
+ Management), p. 16
+
+ "There are no single-sample depth, stencil or coverage buffers for a
+ multisample EGLConfig; the only depth, stencil and coverage buffers are
+ those in the multisample buffer. [...]"
+
+ And add the following text at the end of that paragraph:
+
+ "The <coverage buffer> is used only by OpenGL ES. It contains primitive
+ coverage information that is used to produce a high-quality anti-aliased
+ image. The format of the coverage buffer is not specified, and its
+ contents are not directly accessible. Only the existence of the coverage
+ buffer, and the number of coverage samples it contains, are exposed by EGL.
+
+ EGL_COVERAGE_BUFFERS_NV indicates the number of coverage buffers, which
+ must be zero or one. EGL_COVERAGE_SAMPLES_NV gives the number of coverage
+ samples per pixel; if EGL_COVERAGE_BUFFERS_NV is zero, then
+ EGL_COVERAGE_SAMPLES_NV will also be zero."
+
+ Add to Table 3.4 (Default values and match criteria for EGLConfig
+ attributes)
+
+ +---------------------------+-----------+-------------+---------+---------+
+ | Attribute | Default | Selection | Sort | Sort |
+ | | | Criteria | Order | Priority|
+ +---------------------------+-----------+-------------+---------+---------+
+ | EGL_COVERAGE_BUFFERS_NV | 0 | At Least | Smaller | 7 |
+ | EGL_COVERAGE_SAMPLES_NV | 0 | At Least | Smaller | 8 |
+ +---------------------------+-----------+-------------+---------+---------+
+ And renumber existing sort priorities 7-11 as 9-13.
+
+ Modify the list in "Sorting of EGLConfigs" (Section 3.4.1, pg 20)
+
+ " [...]
+ 5. Smaller EGL_SAMPLE_BUFFERS
+ 6. Smaller EGL_SAMPLES
+ 7. Smaller EGL_COVERAGE_BUFFERS_NV
+ 8. Smaller EGL_COVERAGE_SAMPLES_NV
+ 9. Smaller EGL_DEPTH_SIZE
+ 10. Smaller EGL_STENCIL_SIZE
+ 11. Smaller EGL_ALPHA_MASK_SIZE
+ 12. Special: [...]
+ 13. Smaller EGL_CONFIG_ID [...]"
+
+Usage Examples
+
+ (1) Basic Coverage Sample Rasterization
+
+ glCoverageMaskNV(GL_TRUE);
+ glDepthMask(GL_TRUE);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ while (1)
+ {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
+ GL_COVERAGE_BUFFER_BIT_NV);
+ glDrawElements(...);
+ eglSwapBuffers(...);
+ }
+
+ (2) Multi-Pass Rendering Algorithms
+
+ while (1)
+ {
+ glDepthMask(GL_TRUE);
+ glCoverageMaskNV(GL_TRUE);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
+ GL_COVERAGE_BUFFER_BIT_NV);
+
+ // first render pass: render Z-only (occlusion surface), with
+ // coverage info. color writes are disabled
+
+ glCoverageMaskNV(GL_TRUE);
+ glDepthMask(GL_TRUE);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ glDepthFunc(GL_LESS);
+ glDrawElements(...);
+
+ // second render pass: set Z test to Z-equals, disable Z-writes &
+ // coverage writes. enable color writes. coverage may be
+ // disabled, because subsequent rendering passes are rendering
+ // identical geometry -- since the final coverage buffer will be
+ // unchanged, we can disable coverage writes as an optimization.
+
+ glCoverageMaskNV(GL_FALSE);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_EQUAL);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDrawElements(...);
+
+ eglSwapBuffers();
+ }
+
+ (3) Rendering Translucent Objects on Top of Opaque Objects
+
+ while (1)
+ {
+ glDepthMask(GL_TRUE);
+ glCoverageMaskNV(GL_TRUE);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
+ GL_COVERAGE_BUFFER_BIT_NV);
+
+ // render opaque, Z-buffered geometry with coverage info for the
+ // entire primitive. Overwrite coverage data for all fragments, so
+ // that interior fragments do not get resolved incorrectly.
+
+ glDepthFunc(GL_LESS);
+ glCoverageOperationNV(GL_COVERAGE_ALL_FRAGMENTS_NV);
+ glDrawElements(...);
+
+ // render translucent, Z-buffered geometry. to ensure that visible
+ // edges of opaque geometry remain anti-aliased, change the
+ // coverage operation to just edge fragments. this will maintain
+ // the coverage information underneath the translucent geometry,
+ // except at translucent edges.
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glCoverageOperationNV(GL_COVERAGE_EDGE_FRAGMENTS_NV);
+ glEnable(GL_BLEND);
+ glDrawElements(...);
+ glDisable(GL_BLEND);
+
+ eglSwapBuffers();
+ }
+
+ (4) Rendering Opacity-Mapped Particle Systems & HUDs on Top of Opaque
+ Geometry
+
+ while (1)
+ {
+ glDepthMask(GL_TRUE);
+ glCoverageMaskNV(GL_TRUE);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
+ GL_COVERAGE_BUFFER_BIT_NV);
+
+ // render opaque, Z-buffered geometry, with coverage info.
+ glDepthFunc(GL_LESS);
+ glDrawElements(...);
+
+ // render opacity-mapped geometry. disable Z writes, enable alpha
+ // blending. also, disable coverage writes -- the edges of the
+ // geometry used for the HUD/particle system have alpha values
+ // tapering to zero, so edge coverage is uninteresting, and
+ // interior coverage should still refer to the underlying opaque
+ // geometry, so that opaque edges visible through the translucent
+ // regions remain anti-aliased.
+
+ glCoverageMaskNV(GL_FALSE);
+ glDepthMask(GL_FALSE);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glDrawElements(...);
+ glDisable(GL_BLEND);
+
+ eglSwapBuffers();
+ }
+
+
+Issues
+
+ 1. Is any specific discussion of coverage sampling resolves required,
+ particularly with respect to application-provided framebuffer objects?
+
+ RESOLVED: No. Because the coverage sampling resolve is an
+ implementation-dependent algorithm, it is always legal behavior for
+ framebuffer read / copy functions to return the value in the selected
+ ReadBuffer as if COVERAGE_BUFFERS_NV was zero. This allows
+ textures attached to the color attachment points of framebuffer objects
+ to behave predictably, even when COVERAGE_BUFFERS_NV is one.
+
+ Implementations are encouraged, whenever possible, to use the highest-
+ quality coverage sample resolve supported for calls to eglSwapBuffers,
+ eglCopyBuffers, ReadPixels, CopyPixels and CopyTex{Sub}Image.
+
+ 2. Should all render buffer & texture types be legal sources for image
+ resolves and coverage attachment?
+
+ RESOLVED: This spec should not place any arbitrary limits on usage;
+ however, there are many reasons why implementers may not wish to
+ support coverage sampling for all surface types.
+
+ Implementations may return FRAMEBUFFER_UNSUPPORTED_OES from
+ CheckFramebufferStatusOES if an object bound to COVERAGE_ATTACHMENT_NV
+ is incompatible with one or more objects bound to DEPTH_ATTACHMENT_OES,
+ STENCIL_ATTACHMENT_OES, or COLOR_ATTACHMENTi_OES.
+
+Revision History
+
+#1.0 - 20.03.2007
+
+ Renumbered enumerants. Reformatted to 80 columns.