mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
420 lines
14 KiB
C
420 lines
14 KiB
C
/*
|
|
* Mesa 3-D graphics library
|
|
* Version: 7.1
|
|
*
|
|
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include <precomp.h>
|
|
|
|
/**
|
|
* Compute the bounds of the region resulting from zooming a pixel span.
|
|
* The resulting region will be entirely inside the window/scissor bounds
|
|
* so no additional clipping is needed.
|
|
* \param imageX, imageY position of the mage being drawn (gl WindowPos)
|
|
* \param spanX, spanY position of span being drawing
|
|
* \param width number of pixels in span
|
|
* \param x0, x1 returned X bounds of zoomed region [x0, x1)
|
|
* \param y0, y1 returned Y bounds of zoomed region [y0, y1)
|
|
* \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
|
|
*/
|
|
static GLboolean
|
|
compute_zoomed_bounds(struct gl_context *ctx, GLint imageX, GLint imageY,
|
|
GLint spanX, GLint spanY, GLint width,
|
|
GLint *x0, GLint *x1, GLint *y0, GLint *y1)
|
|
{
|
|
const struct gl_framebuffer *fb = ctx->DrawBuffer;
|
|
GLint c0, c1, r0, r1;
|
|
|
|
ASSERT(spanX >= imageX);
|
|
ASSERT(spanY >= imageY);
|
|
|
|
/*
|
|
* Compute destination columns: [c0, c1)
|
|
*/
|
|
c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
|
|
c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
|
|
if (c1 < c0) {
|
|
/* swap */
|
|
GLint tmp = c1;
|
|
c1 = c0;
|
|
c0 = tmp;
|
|
}
|
|
c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
|
|
c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
|
|
if (c0 == c1) {
|
|
return GL_FALSE; /* no width */
|
|
}
|
|
|
|
/*
|
|
* Compute destination rows: [r0, r1)
|
|
*/
|
|
r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
|
|
r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
|
|
if (r1 < r0) {
|
|
/* swap */
|
|
GLint tmp = r1;
|
|
r1 = r0;
|
|
r0 = tmp;
|
|
}
|
|
r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
|
|
r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
|
|
if (r0 == r1) {
|
|
return GL_FALSE; /* no height */
|
|
}
|
|
|
|
*x0 = c0;
|
|
*x1 = c1;
|
|
*y0 = r0;
|
|
*y1 = r1;
|
|
|
|
return GL_TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert a zoomed x image coordinate back to an unzoomed x coord.
|
|
* 'zx' is screen position of a pixel in the zoomed image, who's left edge
|
|
* is at 'imageX'.
|
|
* return corresponding x coord in the original, unzoomed image.
|
|
* This can use this for unzooming X or Y values.
|
|
*/
|
|
static inline GLint
|
|
unzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
|
|
{
|
|
/*
|
|
zx = imageX + (x - imageX) * zoomX;
|
|
zx - imageX = (x - imageX) * zoomX;
|
|
(zx - imageX) / zoomX = x - imageX;
|
|
*/
|
|
GLint x;
|
|
if (zoomX < 0.0)
|
|
zx++;
|
|
x = imageX + (GLint) ((zx - imageX) / zoomX);
|
|
return x;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Helper function called from _swrast_write_zoomed_rgba/rgb/
|
|
* index/depth_span().
|
|
*/
|
|
static void
|
|
zoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span,
|
|
const GLvoid *src, GLenum format )
|
|
{
|
|
SWcontext *swrast = SWRAST_CONTEXT(ctx);
|
|
SWspan zoomed;
|
|
GLint x0, x1, y0, y1;
|
|
GLint zoomedWidth;
|
|
|
|
if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
|
|
&x0, &x1, &y0, &y1)) {
|
|
return; /* totally clipped */
|
|
}
|
|
|
|
if (!swrast->ZoomedArrays) {
|
|
/* allocate on demand */
|
|
swrast->ZoomedArrays = (SWspanarrays *) CALLOC(sizeof(SWspanarrays));
|
|
if (!swrast->ZoomedArrays)
|
|
return;
|
|
}
|
|
|
|
zoomedWidth = x1 - x0;
|
|
ASSERT(zoomedWidth > 0);
|
|
ASSERT(zoomedWidth <= MAX_WIDTH);
|
|
|
|
/* no pixel arrays! must be horizontal spans. */
|
|
ASSERT((span->arrayMask & SPAN_XY) == 0);
|
|
ASSERT(span->primitive == GL_BITMAP);
|
|
|
|
INIT_SPAN(zoomed, GL_BITMAP);
|
|
zoomed.x = x0;
|
|
zoomed.end = zoomedWidth;
|
|
zoomed.array = swrast->ZoomedArrays;
|
|
zoomed.array->ChanType = span->array->ChanType;
|
|
if (zoomed.array->ChanType == GL_UNSIGNED_BYTE)
|
|
zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba8;
|
|
else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT)
|
|
zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba16;
|
|
else
|
|
zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->attribs[FRAG_ATTRIB_COL];
|
|
|
|
COPY_4V(zoomed.attrStart[FRAG_ATTRIB_WPOS], span->attrStart[FRAG_ATTRIB_WPOS]);
|
|
COPY_4V(zoomed.attrStepX[FRAG_ATTRIB_WPOS], span->attrStepX[FRAG_ATTRIB_WPOS]);
|
|
COPY_4V(zoomed.attrStepY[FRAG_ATTRIB_WPOS], span->attrStepY[FRAG_ATTRIB_WPOS]);
|
|
|
|
zoomed.attrStart[FRAG_ATTRIB_FOGC][0] = span->attrStart[FRAG_ATTRIB_FOGC][0];
|
|
zoomed.attrStepX[FRAG_ATTRIB_FOGC][0] = span->attrStepX[FRAG_ATTRIB_FOGC][0];
|
|
zoomed.attrStepY[FRAG_ATTRIB_FOGC][0] = span->attrStepY[FRAG_ATTRIB_FOGC][0];
|
|
|
|
if (format == GL_RGBA || format == GL_RGB) {
|
|
/* copy Z info */
|
|
zoomed.z = span->z;
|
|
zoomed.zStep = span->zStep;
|
|
/* we'll generate an array of colorss */
|
|
zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
|
|
zoomed.arrayMask |= SPAN_RGBA;
|
|
zoomed.arrayAttribs |= FRAG_BIT_COL; /* we'll produce these values */
|
|
ASSERT(span->arrayMask & SPAN_RGBA);
|
|
}
|
|
else if (format == GL_DEPTH_COMPONENT) {
|
|
/* Copy color info */
|
|
zoomed.red = span->red;
|
|
zoomed.green = span->green;
|
|
zoomed.blue = span->blue;
|
|
zoomed.alpha = span->alpha;
|
|
zoomed.redStep = span->redStep;
|
|
zoomed.greenStep = span->greenStep;
|
|
zoomed.blueStep = span->blueStep;
|
|
zoomed.alphaStep = span->alphaStep;
|
|
/* we'll generate an array of depth values */
|
|
zoomed.interpMask = span->interpMask & ~SPAN_Z;
|
|
zoomed.arrayMask |= SPAN_Z;
|
|
ASSERT(span->arrayMask & SPAN_Z);
|
|
}
|
|
else {
|
|
_mesa_problem(ctx, "Bad format in zoom_span");
|
|
return;
|
|
}
|
|
|
|
/* zoom the span horizontally */
|
|
if (format == GL_RGBA) {
|
|
if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
|
|
const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
|
|
GLint i;
|
|
for (i = 0; i < zoomedWidth; i++) {
|
|
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
|
|
ASSERT(j >= 0);
|
|
ASSERT(j < (GLint) span->end);
|
|
COPY_4UBV(zoomed.array->rgba8[i], rgba[j]);
|
|
}
|
|
}
|
|
else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
|
|
const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
|
|
GLint i;
|
|
for (i = 0; i < zoomedWidth; i++) {
|
|
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
|
|
ASSERT(j >= 0);
|
|
ASSERT(j < (GLint) span->end);
|
|
COPY_4V(zoomed.array->rgba16[i], rgba[j]);
|
|
}
|
|
}
|
|
else {
|
|
const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
|
|
GLint i;
|
|
for (i = 0; i < zoomedWidth; i++) {
|
|
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
|
|
ASSERT(j >= 0);
|
|
ASSERT(j < span->end);
|
|
COPY_4V(zoomed.array->attribs[FRAG_ATTRIB_COL][i], rgba[j]);
|
|
}
|
|
}
|
|
}
|
|
else if (format == GL_RGB) {
|
|
if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
|
|
const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
|
|
GLint i;
|
|
for (i = 0; i < zoomedWidth; i++) {
|
|
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
|
|
ASSERT(j >= 0);
|
|
ASSERT(j < (GLint) span->end);
|
|
zoomed.array->rgba8[i][0] = rgb[j][0];
|
|
zoomed.array->rgba8[i][1] = rgb[j][1];
|
|
zoomed.array->rgba8[i][2] = rgb[j][2];
|
|
zoomed.array->rgba8[i][3] = 0xff;
|
|
}
|
|
}
|
|
else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
|
|
const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
|
|
GLint i;
|
|
for (i = 0; i < zoomedWidth; i++) {
|
|
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
|
|
ASSERT(j >= 0);
|
|
ASSERT(j < (GLint) span->end);
|
|
zoomed.array->rgba16[i][0] = rgb[j][0];
|
|
zoomed.array->rgba16[i][1] = rgb[j][1];
|
|
zoomed.array->rgba16[i][2] = rgb[j][2];
|
|
zoomed.array->rgba16[i][3] = 0xffff;
|
|
}
|
|
}
|
|
else {
|
|
const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
|
|
GLint i;
|
|
for (i = 0; i < zoomedWidth; i++) {
|
|
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
|
|
ASSERT(j >= 0);
|
|
ASSERT(j < span->end);
|
|
zoomed.array->attribs[FRAG_ATTRIB_COL][i][0] = rgb[j][0];
|
|
zoomed.array->attribs[FRAG_ATTRIB_COL][i][1] = rgb[j][1];
|
|
zoomed.array->attribs[FRAG_ATTRIB_COL][i][2] = rgb[j][2];
|
|
zoomed.array->attribs[FRAG_ATTRIB_COL][i][3] = 1.0F;
|
|
}
|
|
}
|
|
}
|
|
else if (format == GL_DEPTH_COMPONENT) {
|
|
const GLuint *zValues = (const GLuint *) src;
|
|
GLint i;
|
|
for (i = 0; i < zoomedWidth; i++) {
|
|
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
|
|
ASSERT(j >= 0);
|
|
ASSERT(j < (GLint) span->end);
|
|
zoomed.array->z[i] = zValues[j];
|
|
}
|
|
/* Now, fall into the RGB path below */
|
|
format = GL_RGBA;
|
|
}
|
|
|
|
/* write the span in rows [r0, r1) */
|
|
if (format == GL_RGBA || format == GL_RGB) {
|
|
/* Writing the span may modify the colors, so make a backup now if we're
|
|
* going to call _swrast_write_zoomed_span() more than once.
|
|
* Also, clipping may change the span end value, so store it as well.
|
|
*/
|
|
const GLint end = zoomed.end; /* save */
|
|
void *rgbaSave;
|
|
const GLint pixelSize =
|
|
(zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
|
|
((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
|
|
: 4 * sizeof(GLfloat));
|
|
|
|
rgbaSave = malloc(zoomed.end * pixelSize);
|
|
if (!rgbaSave) {
|
|
return;
|
|
}
|
|
|
|
if (y1 - y0 > 1) {
|
|
memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
|
|
}
|
|
for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
|
|
_swrast_write_rgba_span(ctx, &zoomed);
|
|
zoomed.end = end; /* restore */
|
|
if (y1 - y0 > 1) {
|
|
/* restore the colors */
|
|
memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
|
|
}
|
|
}
|
|
|
|
free(rgbaSave);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
_swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
|
|
const SWspan *span, const GLvoid *rgba)
|
|
{
|
|
zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
|
|
}
|
|
|
|
|
|
void
|
|
_swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
|
|
const SWspan *span, const GLvoid *rgb)
|
|
{
|
|
zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
|
|
}
|
|
|
|
|
|
void
|
|
_swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
|
|
const SWspan *span)
|
|
{
|
|
zoom_span(ctx, imgX, imgY, span,
|
|
(const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
|
|
}
|
|
|
|
|
|
/**
|
|
* Zoom/write stencil values.
|
|
* No per-fragment operations are applied.
|
|
*/
|
|
void
|
|
_swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY,
|
|
GLint width, GLint spanX, GLint spanY,
|
|
const GLubyte stencil[])
|
|
{
|
|
GLubyte zoomedVals[MAX_WIDTH];
|
|
GLint x0, x1, y0, y1, y;
|
|
GLint i, zoomedWidth;
|
|
|
|
if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
|
|
&x0, &x1, &y0, &y1)) {
|
|
return; /* totally clipped */
|
|
}
|
|
|
|
zoomedWidth = x1 - x0;
|
|
ASSERT(zoomedWidth > 0);
|
|
ASSERT(zoomedWidth <= MAX_WIDTH);
|
|
|
|
/* zoom the span horizontally */
|
|
for (i = 0; i < zoomedWidth; i++) {
|
|
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
|
|
ASSERT(j >= 0);
|
|
ASSERT(j < width);
|
|
zoomedVals[i] = stencil[j];
|
|
}
|
|
|
|
/* write the zoomed spans */
|
|
for (y = y0; y < y1; y++) {
|
|
_swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Zoom/write 32-bit Z values.
|
|
* No per-fragment operations are applied.
|
|
*/
|
|
void
|
|
_swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
|
|
GLint width, GLint spanX, GLint spanY,
|
|
const GLuint *zVals)
|
|
{
|
|
struct gl_renderbuffer *rb =
|
|
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
|
|
GLuint zoomedVals[MAX_WIDTH];
|
|
GLint x0, x1, y0, y1, y;
|
|
GLint i, zoomedWidth;
|
|
|
|
if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
|
|
&x0, &x1, &y0, &y1)) {
|
|
return; /* totally clipped */
|
|
}
|
|
|
|
zoomedWidth = x1 - x0;
|
|
ASSERT(zoomedWidth > 0);
|
|
ASSERT(zoomedWidth <= MAX_WIDTH);
|
|
|
|
/* zoom the span horizontally */
|
|
for (i = 0; i < zoomedWidth; i++) {
|
|
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
|
|
ASSERT(j >= 0);
|
|
ASSERT(j < width);
|
|
zoomedVals[i] = zVals[j];
|
|
}
|
|
|
|
/* write the zoomed spans */
|
|
for (y = y0; y < y1; y++) {
|
|
GLubyte *dst = _swrast_pixel_address(rb, x0, y);
|
|
_mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst);
|
|
}
|
|
}
|