From aa133069745fc59bb2f212b0816add9bae40c376 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 25 Aug 2009 12:10:32 -0700 Subject: [PATCH] glamor: Start adding render acceleration support. This brings in idr's glu3 code. We'll probably want to move to linking to it as a library, once an ABI-stable release is out. --- configure.ac | 1 + glamor/Makefile.am | 4 + glamor/glamor.c | 1 + glamor/glamor_priv.h | 16 + glamor/glamor_render.c | 620 ++++++++++++++++++++++++++++++++++++++ glamor/glu3/Makefile.am | 15 + glamor/glu3/glu3.h | 192 ++++++++++++ glamor/glu3/glu3_scalar.h | 388 ++++++++++++++++++++++++ glamor/glu3/matrix.c | 217 +++++++++++++ 9 files changed, 1454 insertions(+) create mode 100644 glamor/glamor_render.c create mode 100644 glamor/glu3/Makefile.am create mode 100644 glamor/glu3/glu3.h create mode 100644 glamor/glu3/glu3_scalar.h create mode 100644 glamor/glu3/matrix.c diff --git a/configure.ac b/configure.ac index 3954ecc06..7a8e507e7 100644 --- a/configure.ac +++ b/configure.ac @@ -2147,6 +2147,7 @@ Xi/Makefile xfixes/Makefile exa/Makefile glamor/Makefile +glamor/glu3/Makefile hw/Makefile hw/xfree86/Makefile hw/xfree86/common/Makefile diff --git a/glamor/Makefile.am b/glamor/Makefile.am index 098aa37c0..4d307fe7a 100644 --- a/glamor/Makefile.am +++ b/glamor/Makefile.am @@ -4,6 +4,8 @@ noinst_LTLIBRARIES = libglamor.la # built (in hw/xfree86/os-support/solaris) until after glamor is built SOLARIS_ASM_CFLAGS="" +SUBDIRS = glu3 + if XORG sdk_HEADERS = glamor.h endif @@ -24,3 +26,5 @@ libglamor_la_SOURCES = \ glamor_render.c \ glamor_tile.c \ glamor.h +libglamor_la_LIBADD = \ + glu3/libglu3.la diff --git a/glamor/glamor.c b/glamor/glamor.c index a03274a54..43e1c7d3a 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -208,6 +208,7 @@ glamor_init(ScreenPtr screen) glamor_init_solid_shader(screen); glamor_init_tile_shader(screen); + glamor_init_composite_shaders(screen); return TRUE; diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index d054372b4..864be51ab 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -38,6 +38,13 @@ typedef struct glamor_transform_uniforms { GLint y_scale; } glamor_transform_uniforms; +typedef struct glamor_composite_shader { + GLuint prog; + GLint dest_to_dest_uniform_location; + GLint dest_to_source_uniform_location; + GLint dest_to_mask_uniform_location; +} glamor_composite_shader; + typedef struct glamor_screen_private { CreateGCProcPtr saved_create_gc; CreatePixmapProcPtr saved_create_pixmap; @@ -52,8 +59,12 @@ typedef struct glamor_screen_private { GLint solid_color_uniform_location; glamor_transform_uniforms solid_transform; + /* glamor_tile */ GLint tile_prog; glamor_transform_uniforms tile_transform; + + /* glamor_composite */ + glamor_composite_shader composite_shader[2]; } glamor_screen_private; typedef struct glamor_pixmap_private { @@ -75,6 +86,10 @@ glamor_get_pixmap_private(PixmapPtr pixmap) return dixLookupPrivate(&pixmap->devPrivates, glamor_pixmap_private_key); } +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + /** * Returns TRUE if the given planemask covers all the significant bits in the * pixel values for pDrawable. @@ -166,6 +181,7 @@ void glamor_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, PictFormatPtr mask_format, INT16 x_src, INT16 y_src, int ntrap, xTrapezoid *traps); +void glamor_init_composite_shaders(ScreenPtr screen); /* glamor_tile.c */ void glamor_tile(PixmapPtr pixmap, PixmapPtr tile, diff --git a/glamor/glamor_render.c b/glamor/glamor_render.c new file mode 100644 index 000000000..d0c955792 --- /dev/null +++ b/glamor/glamor_render.c @@ -0,0 +1,620 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 (including the next + * paragraph) 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Authors: + * Eric Anholt + * + */ + + +/** @file glamor_render.c + * + * Render acceleration implementation + */ + +#include "glamor_priv.h" + +#ifdef RENDER +#include "mipict.h" + +#include "glu3/glu3.h" + +struct shader_key { + Bool has_mask; +}; + +struct blendinfo { + Bool dest_alpha; + Bool source_alpha; + GLenum source_blend; + GLenum dest_blend; +}; + +static struct blendinfo composite_op_info[] = { + [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO}, + [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO}, + [PictOpDst] = {0, 0, GL_ZERO, GL_ONE}, + [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, + [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE}, + [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO}, + [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA}, + [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO}, + [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA}, + [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, + [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA}, + [PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, + [PictOpAdd] = {0, 0, GL_ONE, GL_ONE}, +}; + +#define HAS_MASK_INDEX 1 + +static glamor_composite_shader * +glamor_lookup_composite_shader(ScreenPtr screen, struct shader_key *key) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + int index = 0; + + if (key->has_mask) + index += HAS_MASK_INDEX; + + assert(index < ARRAY_SIZE(glamor_priv->composite_shader)); + + return &glamor_priv->composite_shader[index]; +} + +static GLuint +glamor_create_composite_fs(struct shader_key *key) +{ + const char *header = + "uniform sampler2D source_sampler;\n" + "varying vec4 source_coords;\n"; + const char *mask_header = + "uniform sampler2D mask_sampler;\n" + "varying vec4 mask_coords;\n"; + const char *main_opening = + "void main()\n" + "{\n" + " vec4 result;\n" + " result = texture2DProj(source_sampler, source_coords.xyw);\n"; + const char *source_in_mask = + " vec4 mask = texture2DProj(mask_sampler, mask_coords.xyw);\n" + " result = result * mask.w;\n"; + const char *main_closing = + " gl_FragColor = result;\n" + "}\n"; + char *source; + GLuint prog; + + source = XNFprintf("%s%s%s%s%s", + header, + key->has_mask ? mask_header : "", + main_opening, + key->has_mask ? source_in_mask : "", + main_closing); + + prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER_ARB, source); + xfree(source); + + return prog; +} + +static GLuint +glamor_create_composite_vs(struct shader_key *key) +{ + const char *header = + "uniform mat4 dest_to_dest;\n" + "uniform mat4 dest_to_source;\n" + "varying vec4 source_coords;\n"; + const char *mask_header = + "uniform mat4 dest_to_mask;\n" + "varying vec4 mask_coords;\n"; + const char *main_opening = + "void main()\n" + "{\n" + " vec4 incoming_dest_coords = vec4(gl_Vertex.xy, 0, 1);\n" + " gl_Position = dest_to_dest * incoming_dest_coords;\n" + " source_coords = dest_to_source * incoming_dest_coords;\n"; + const char *mask_coords = + " mask_coords = dest_to_mask * incoming_dest_coords;\n"; + const char *main_closing = + "}\n"; + char *source; + GLuint prog; + + source = XNFprintf("%s%s%s%s%s", + header, + key->has_mask ? mask_header : "", + main_opening, + key->has_mask ? mask_coords : "", + main_closing); + + prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER_ARB, source); + xfree(source); + + return prog; +} + +static void +glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key) +{ + GLuint vs, fs, prog; + GLint source_sampler_uniform_location, mask_sampler_uniform_location; + glamor_composite_shader *shader; + + shader = glamor_lookup_composite_shader(screen, key); + + vs = glamor_create_composite_vs(key); + if (vs == 0) + return; + fs = glamor_create_composite_fs(key); + if (fs == 0) + return; + + prog = glCreateProgramObjectARB(); + glAttachObjectARB(prog, vs); + glAttachObjectARB(prog, fs); + glamor_link_glsl_prog(prog); + + shader->prog = prog; + + glUseProgramObjectARB(prog); + source_sampler_uniform_location = glGetUniformLocationARB(prog, + "source_sampler"); + shader->dest_to_dest_uniform_location = + glGetUniformLocationARB(prog, "dest_to_dest"); + shader->dest_to_source_uniform_location = + glGetUniformLocationARB(prog, "dest_to_source"); + glUniform1i(source_sampler_uniform_location, 0); + + if (key->has_mask) { + mask_sampler_uniform_location = glGetUniformLocationARB(prog, + "mask_sampler"); + glUniform1i(mask_sampler_uniform_location, 1); + shader->dest_to_mask_uniform_location = + glGetUniformLocationARB(prog, "dest_to_mask"); + } +} + +void +glamor_init_composite_shaders(ScreenPtr screen) +{ + struct shader_key key; + + key.has_mask = FALSE; + glamor_create_composite_shader(screen, &key); + key.has_mask = TRUE; + glamor_create_composite_shader(screen, &key); +} + +static void +glamor_set_composite_transform_matrix(GLUmat4 *m, + PicturePtr picture, + float x_source, + float y_source) +{ + GLUmat4 temp; + DrawablePtr drawable = picture->pDrawable; + GLUvec4 scale = {{1.0f / drawable->width, + 1.0f / drawable->height, + 1.0, + 1.0}}; + + gluTranslate3f(m, -x_source, -y_source, 0.0); + gluScale4v(&temp, &scale); + gluMult4m_4m(m, &temp, m); +} + +static Bool +glamor_set_composite_op(ScreenPtr screen, + CARD8 op, PicturePtr dest, PicturePtr mask) +{ + GLenum source_blend, dest_blend; + struct blendinfo *op_info; + + if (op >= ARRAY_SIZE(composite_op_info)) { + ErrorF("unsupported render op\n"); + return GL_FALSE; + } + op_info = &composite_op_info[op]; + + source_blend = op_info->source_blend; + dest_blend = op_info->dest_blend; + + if (mask && mask->componentAlpha && PICT_FORMAT_RGB(mask->format) != 0 && + op_info->source_alpha && source_blend != GL_ZERO) { + } + + /* If there's no dst alpha channel, adjust the blend op so that we'll treat + * it as always 1. + */ + if (PICT_FORMAT_A(dest->format) == 0 && op_info->dest_alpha) { + if (source_blend == GL_DST_ALPHA) + source_blend = GL_ONE; + else if (source_blend == GL_ONE_MINUS_DST_ALPHA) + source_blend = GL_ZERO; + } + + /* Set up the source alpha value for blending in component alpha mode. */ + if (mask && mask->componentAlpha && PICT_FORMAT_RGB(mask->format) != 0 && + op_info->source_alpha) { + if (source_blend != GL_ZERO) { + ErrorF("Dual-source composite blending not supported\n"); + return GL_FALSE; + } + if (dest_blend == GL_SRC_ALPHA) + dest_blend = GL_SRC_COLOR; + else if (dest_blend == GL_ONE_MINUS_SRC_ALPHA) + dest_blend = GL_ONE_MINUS_SRC_COLOR; + } + + if (source_blend == GL_ONE && dest_blend == GL_ZERO) { + glDisable(GL_BLEND); + } else { + glEnable(GL_BLEND); + glBlendFunc(source_blend, dest_blend); + } + return TRUE; +} + +static void +glamor_set_composite_texture(ScreenPtr screen, int unit, PicturePtr picture, + glamor_pixmap_private *pixmap_priv) +{ + glActiveTexture(GL_TEXTURE0 + unit); + glBindTexture(GL_TEXTURE_2D, pixmap_priv->tex); + switch (picture->repeatType) { + case RepeatNone: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + break; + case RepeatNormal: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + case RepeatPad: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + break; + case RepeatReflect: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + break; + } + + switch (picture->filter) { + case PictFilterNearest: + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + case PictFilterBilinear: + default: + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + } + + glEnable(GL_TEXTURE_2D); +} + +void +glamor_composite(CARD8 op, + PicturePtr source, + PicturePtr mask, + PicturePtr dest, + INT16 x_source, + INT16 y_source, + INT16 x_mask, + INT16 y_mask, + INT16 x_dest, + INT16 y_dest, + CARD16 width, + CARD16 height) +{ + ScreenPtr screen = dest->pDrawable->pScreen; + PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable); + PixmapPtr source_pixmap, mask_pixmap = NULL; + glamor_pixmap_private *source_pixmap_priv, *mask_pixmap_priv = NULL; + struct shader_key key; + glamor_composite_shader *shader; + GLUmat4 dest_to_dest, dest_to_source, dest_to_mask; + RegionRec region; + int i; + + /* Do two-pass PictOpOver componentAlpha, until we enable + * dual source color blending. + */ + if (mask && mask->componentAlpha && op == PictOpOver) { + glamor_composite(PictOpOutReverse, + source, mask, dest, + x_source, y_source, + x_mask, y_mask, + x_dest, y_dest, + width, height); + glamor_composite(PictOpAdd, + source, mask, dest, + x_source, y_source, + x_mask, y_mask, + x_dest, y_dest, + width, height); + return; + } + + key.has_mask = (mask != NULL); + if (!source->pDrawable) { + ErrorF("source-only source\n"); + goto fail; + } + if (mask && !mask->pDrawable) { + ErrorF("source-only mask\n"); + goto fail; + } + if (source->alphaMap) { + ErrorF("source alphaMap\n"); + goto fail; + } + if (mask && mask->alphaMap) { + ErrorF("mask alphaMap\n"); + goto fail; + } + + source_pixmap = glamor_get_drawable_pixmap(source->pDrawable); + source_pixmap_priv = glamor_get_pixmap_private(source_pixmap); + if (source_pixmap == dest_pixmap) { + ErrorF("source == dest\n"); + goto fail; + } + if (!source_pixmap_priv || source_pixmap_priv->tex == 0) { + ErrorF("no FBO in source\n"); + goto fail; + } + if (mask) { + mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable); + mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap); + if (mask_pixmap == dest_pixmap) { + ErrorF("mask == dest\n"); + goto fail; + } + if (!mask_pixmap_priv || mask_pixmap_priv->tex == 0) { + ErrorF("no FBO in mask\n"); + goto fail; + } + } + + shader = glamor_lookup_composite_shader(screen, &key); + if (shader->prog == 0) { + ErrorF("No program compiled for this render accel mode\n"); + goto fail; + } + + glUseProgramObjectARB(shader->prog); + + if (!glamor_set_destination_pixmap(dest_pixmap)) + goto fail; + + if (!glamor_set_composite_op(screen, op, dest, mask)) { + goto fail; + } + + x_dest += dest->pDrawable->x; + y_dest += dest->pDrawable->y; + if (source->pDrawable) { + x_source += source->pDrawable->x; + y_source += source->pDrawable->y; + } + if (mask && mask->pDrawable) { + x_mask += mask->pDrawable->x; + y_mask += mask->pDrawable->y; + } + + gluOrtho6f(&dest_to_dest, + dest_pixmap->screen_x, dest_pixmap->screen_x + width, + dest_pixmap->screen_y, dest_pixmap->screen_y + height, + -1, 1); + glUniformMatrix4fvARB(shader->dest_to_dest_uniform_location, 1, 0, + (float *)&dest_to_dest); + glamor_set_composite_transform_matrix(&dest_to_source, + source, + x_source - x_dest, + y_source - x_dest); + glUniformMatrix4fvARB(shader->dest_to_source_uniform_location, 1, 0, + (float *)&dest_to_source); + + if (mask) { + glamor_set_composite_transform_matrix(&dest_to_mask, + mask, + x_mask - x_dest, + y_mask - x_dest); + glUniformMatrix4fvARB(shader->dest_to_mask_uniform_location, 1, 0, + (float *)&dest_to_mask); + } + + glamor_set_composite_texture(screen, 0, source, source_pixmap_priv); + if (mask) + glamor_set_composite_texture(screen, 1, mask, mask_pixmap_priv); + + if (!miComputeCompositeRegion(®ion, + source, mask, dest, + x_source, y_source, + x_mask, y_mask, + x_dest, y_dest, + width, height)) + return; + + glBegin(GL_QUADS); + for (i = 0; i < REGION_NUM_RECTS(®ion); i++) { + BoxPtr box = ®ION_RECTS(®ion)[i]; + glVertex2i(box->x1, box->y1); + glVertex2i(box->x2, box->y1); + glVertex2i(box->x2, box->y2); + glVertex2i(box->x1, box->y2); + } + glEnd(); + + glamor_set_composite_op(screen, PictOpSrc, dest, mask); + glUseProgramObjectARB(0); + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + return; + +fail: + glamor_set_composite_op(screen, PictOpSrc, dest, mask); + glUseProgramObjectARB(0); + glamor_solid_fail_region(dest_pixmap, x_dest, y_dest, width, height); +} + + +/** + * Creates an appropriate picture to upload our alpha mask into (which + * we calculated in system memory) + */ +static PicturePtr +glamor_create_mask_picture(ScreenPtr screen, + PicturePtr dst, + PictFormatPtr pict_format, + CARD16 width, + CARD16 height) +{ + PixmapPtr pixmap; + PicturePtr picture; + int error; + + if (!pict_format) { + if (dst->polyEdge == PolyEdgeSharp) + pict_format = PictureMatchFormat(screen, 1, PICT_a1); + else + pict_format = PictureMatchFormat(screen, 8, PICT_a8); + if (!pict_format) + return 0; + } + + pixmap = screen->CreatePixmap(screen, width, height, + pict_format->depth, + 0); + if (!pixmap) + return 0; + picture = CreatePicture(0, &pixmap->drawable, pict_format, + 0, 0, serverClient, &error); + screen->DestroyPixmap(pixmap); + return picture; +} + +/** + * glamor_trapezoids is a copy of miTrapezoids that does all the trapezoid + * accumulation in system memory. + */ +void +glamor_trapezoids(CARD8 op, + PicturePtr src, PicturePtr dst, + PictFormatPtr mask_format, INT16 x_src, INT16 y_src, + int ntrap, xTrapezoid *traps) +{ + ScreenPtr screen = dst->pDrawable->pScreen; + BoxRec bounds; + PicturePtr picture; + INT16 x_dst, y_dst; + INT16 x_rel, y_rel; + int width, height, stride; + PixmapPtr pixmap; + GCPtr gc; + pixman_image_t *image; + + /* If a mask format wasn't provided, we get to choose, but behavior should + * be as if there was no temporary mask the traps were accumulated into. + */ + if (!mask_format) { + if (dst->polyEdge == PolyEdgeSharp) + mask_format = PictureMatchFormat(screen, 1, PICT_a1); + else + mask_format = PictureMatchFormat(screen, 8, PICT_a8); + for (; ntrap; ntrap--, traps++) + glamor_trapezoids(op, src, dst, mask_format, x_src, y_src, + 1, traps); + return; + } + + miTrapezoidBounds(ntrap, traps, &bounds); + + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return; + + x_dst = traps[0].left.p1.x >> 16; + y_dst = traps[0].left.p1.y >> 16; + + width = bounds.x2 - bounds.x1; + height = bounds.y2 - bounds.y1; + stride = (width * BitsPerPixel(mask_format->depth) + 7) / 8; + + picture = glamor_create_mask_picture(screen, dst, mask_format, + width, height); + if (!picture) + return; + + image = pixman_image_create_bits(picture->format, + width, height, + NULL, stride); + if (!image) { + FreePicture(picture, 0); + return; + } + + for (; ntrap; ntrap--, traps++) + pixman_rasterize_trapezoid(image, (pixman_trapezoid_t *) traps, + -bounds.x1, -bounds.y1); + + pixmap = GetScratchPixmapHeader(screen, width, height, + mask_format->depth, + BitsPerPixel(mask_format->depth), + PixmapBytePad(width, mask_format->depth), + pixman_image_get_data(image)); + if (!pixmap) { + FreePicture(picture, 0); + pixman_image_unref(image); + return; + } + + gc = GetScratchGC(picture->pDrawable->depth, screen); + if (!gc) { + FreeScratchPixmapHeader(pixmap); + pixman_image_unref (image); + FreePicture(picture, 0); + return; + } + ValidateGC(picture->pDrawable, gc); + + gc->ops->CopyArea(&pixmap->drawable, picture->pDrawable, + gc, 0, 0, width, height, 0, 0); + + FreeScratchGC(gc); + FreeScratchPixmapHeader(pixmap); + pixman_image_unref(image); + + x_rel = bounds.x1 + x_src - x_dst; + y_rel = bounds.y1 + y_src - y_dst; + CompositePicture(op, src, picture, dst, + x_rel, y_rel, + 0, 0, + bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); + FreePicture(picture, 0); +} + +#endif /* RENDER */ diff --git a/glamor/glu3/Makefile.am b/glamor/glu3/Makefile.am new file mode 100644 index 000000000..7d141a7fc --- /dev/null +++ b/glamor/glu3/Makefile.am @@ -0,0 +1,15 @@ +noinst_LTLIBRARIES = libglu3.la + +# Override these since glu3 doesn't need them and the needed files aren't +# built (in hw/xfree86/os-support/solaris) until after glu3 is built +SOLARIS_ASM_CFLAGS="" + +INCLUDES = \ + $(XORG_INCS) + +AM_CFLAGS = $(XORG_CFLAGS) $(DIX_CFLAGS) + +libglu3_la_SOURCES = \ + matrix.c \ + glu3.h \ + glu3_scalar.h diff --git a/glamor/glu3/glu3.h b/glamor/glu3/glu3.h new file mode 100644 index 000000000..29dba380a --- /dev/null +++ b/glamor/glu3/glu3.h @@ -0,0 +1,192 @@ +/* + * Copyright © 2009 Ian D. Romanick + * + * 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 (including the next + * paragraph) 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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. + */ + +#ifndef __glu3_h__ +#define __glu3_h__ + +#include + +#define GLU_VERSION_3_0 + +struct GLUmat4; + +struct GLUvec4 { + GLfloat values[4]; + +#ifdef __cplusplus + inline GLUvec4(void) + { + } + + inline GLUvec4(GLfloat x , GLfloat y, GLfloat z, GLfloat w) + { + values[0] = x; + values[1] = y; + values[2] = z; + values[3] = w; + } + + inline GLUvec4(const GLUvec4 &v) + { + values[0] = v.values[0]; + values[1] = v.values[1]; + values[2] = v.values[2]; + values[3] = v.values[3]; + } + + GLUvec4 operator *(const GLUmat4 &) const; + GLUvec4 operator *(const GLUvec4 &) const; + GLUvec4 operator *(GLfloat) const; + + GLUvec4 operator +(const GLUvec4 &) const; + GLUvec4 operator -(const GLUvec4 &) const; +#endif /* __cplusplus */ +}; + + +struct GLUmat4 { + struct GLUvec4 col[4]; + +#ifdef __cplusplus + inline GLUmat4(void) + { + } + + inline GLUmat4(const GLUvec4 & c0, const GLUvec4 & c1, + const GLUvec4 & c2, const GLUvec4 & c3) + { + col[0] = c0; + col[1] = c1; + col[2] = c2; + col[3] = c3; + } + + inline GLUmat4(const GLUmat4 &m) + { + col[0] = m.col[0]; + col[1] = m.col[1]; + col[2] = m.col[2]; + col[3] = m.col[3]; + } + + + GLUvec4 operator *(const GLUvec4 &) const; + GLUmat4 operator *(const GLUmat4 &) const; + GLUmat4 operator *(GLfloat) const; + + GLUmat4 operator +(const GLUmat4 &) const; + GLUmat4 operator -(const GLUmat4 &) const; +#endif /* __cplusplus */ +}; + +#define GLU_MAX_STACK_DEPTH 32 + +struct GLUmat4Stack { + struct GLUmat4 stack[GLU_MAX_STACK_DEPTH]; + unsigned top; + +#ifdef __cplusplus + GLUmat4Stack() : top(0) + { + /* empty */ + } +#endif /* __cplusplus */ +}; + +#ifndef __cplusplus +typedef struct GLUvec4 GLUvec4; +typedef struct GLUmat4 GLUmat4; +typedef struct GLUmat4Stack GLUmat4Stack; +#endif /* __cplusplus */ + + +#ifdef __cplusplus +extern "C" { +#endif + +GLfloat gluDot4_4v(const GLUvec4 *, const GLUvec4 *); +GLfloat gluDot3_4v(const GLUvec4 *, const GLUvec4 *); +GLfloat gluDot2_4v(const GLUvec4 *, const GLUvec4 *); + +void gluCross4v(GLUvec4 *result, const GLUvec4 *, const GLUvec4 *); +void gluNormalize4v(GLUvec4 *result, const GLUvec4 *); +GLfloat gluLength4v(const GLUvec4 *); +GLfloat gluLengthSqr4v(const GLUvec4 *); +void gluOuter4v(GLUmat4 *result, const GLUvec4 *, const GLUvec4 *); + + +void gluMult4v_4v(GLUvec4 *result, const GLUvec4 *, const GLUvec4 *); +void gluDiv4v_4v(GLUvec4 *result, const GLUvec4 *, const GLUvec4 *); +void gluAdd4v_4v(GLUvec4 *result, const GLUvec4 *, const GLUvec4 *); +void gluSub4v_4v(GLUvec4 *result, const GLUvec4 *, const GLUvec4 *); + +void gluMult4v_f(GLUvec4 *result, const GLUvec4 *, GLfloat); +void gluDiv4v_f(GLUvec4 *result, const GLUvec4 *, GLfloat); +void gluAdd4v_f(GLUvec4 *result, const GLUvec4 *, GLfloat); +void gluSub4v_f(GLUvec4 *result, const GLUvec4 *, GLfloat); + +void gluMult4m_4m(GLUmat4 *result, const GLUmat4 *, const GLUmat4 *); +void gluAdd4m_4m(GLUmat4 *result, const GLUmat4 *, const GLUmat4 *); +void gluSub4m_4m(GLUmat4 *result, const GLUmat4 *, const GLUmat4 *); +void gluMult4m_4v(GLUvec4 *result, const GLUmat4 *m, const GLUvec4 *v); + +void gluMult4m_f(GLUmat4 *result, const GLUmat4 *, GLfloat); + +void gluScale4v(GLUmat4 *result, const GLUvec4 *); +void gluTranslate3f(GLUmat4 *result, GLfloat x, GLfloat y, GLfloat z); +void gluTranslate4v(GLUmat4 *result, const GLUvec4 *); +void gluRotate4v(GLUmat4 *result, const GLUvec4 *axis, GLfloat angle); +void gluLookAt4v(GLUmat4 *result, const GLUvec4 *eye, const GLUvec4 *center, + const GLUvec4 *up); +void gluPerspective4f(GLUmat4 *result, GLfloat fovy, GLfloat aspect, + GLfloat near, GLfloat far); +void gluTranspose4m(GLUmat4 *result, const GLUmat4 *m); +void gluFrustum6f(GLUmat4 *result, + GLfloat left, GLfloat right, + GLfloat bottom, GLfloat top, + GLfloat near, GLfloat far); +void gluOrtho6f(GLUmat4 *result, + GLfloat left, GLfloat right, + GLfloat bottom, GLfloat top, + GLfloat near, GLfloat far); + +extern const GLUmat4 gluIdentityMatrix; + +#ifdef __cplusplus +}; +#endif + +#ifdef __cplusplus +GLfloat gluDot4(const GLUvec4 &, const GLUvec4 &); +GLfloat gluDot3(const GLUvec4 &, const GLUvec4 &); +GLfloat gluDot2(const GLUvec4 &, const GLUvec4 &); + +GLUvec4 gluCross(const GLUvec4 &, const GLUvec4 &); +GLUvec4 gluNormalize(const GLUvec4 &); +GLfloat gluLength(const GLUvec4 &); +GLfloat gluLengthSqr(const GLUvec4 &); +#endif /* __cplusplus */ + +#include "glu3_scalar.h" + +#endif /* __glu3_h__ */ diff --git a/glamor/glu3/glu3_scalar.h b/glamor/glu3/glu3_scalar.h new file mode 100644 index 000000000..3e87b8cce --- /dev/null +++ b/glamor/glu3/glu3_scalar.h @@ -0,0 +1,388 @@ +/* + * Copyright © 2009 Ian D. Romanick + * + * 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 (including the next + * paragraph) 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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 +#include + +extern inline void gluMult4v_4v(GLUvec4 *result, + const GLUvec4 *v1, const GLUvec4 *v2) +{ + result->values[0] = v1->values[0] * v2->values[0]; + result->values[1] = v1->values[1] * v2->values[1]; + result->values[2] = v1->values[2] * v2->values[2]; + result->values[3] = v1->values[3] * v2->values[3]; +} + + +extern inline void gluDiv4v_4v(GLUvec4 *result, + const GLUvec4 *v1, const GLUvec4 *v2) +{ + result->values[0] = v1->values[0] / v2->values[0]; + result->values[1] = v1->values[1] / v2->values[1]; + result->values[2] = v1->values[2] / v2->values[2]; + result->values[3] = v1->values[3] / v2->values[3]; +} + + +extern inline void gluAdd4v_4v(GLUvec4 *result, + const GLUvec4 *v1, const GLUvec4 *v2) +{ + result->values[0] = v1->values[0] + v2->values[0]; + result->values[1] = v1->values[1] + v2->values[1]; + result->values[2] = v1->values[2] + v2->values[2]; + result->values[3] = v1->values[3] + v2->values[3]; +} + + +extern inline void gluSub4v_4v(GLUvec4 *result, + const GLUvec4 *v1, const GLUvec4 *v2) +{ + result->values[0] = v1->values[0] - v2->values[0]; + result->values[1] = v1->values[1] - v2->values[1]; + result->values[2] = v1->values[2] - v2->values[2]; + result->values[3] = v1->values[3] - v2->values[3]; +} + + +extern inline void gluMult4v_f(GLUvec4 *result, + const GLUvec4 *v1, GLfloat f) +{ + result->values[0] = v1->values[0] * f; + result->values[1] = v1->values[1] * f; + result->values[2] = v1->values[2] * f; + result->values[3] = v1->values[3] * f; +} + + +extern inline void gluDiv4v_f(GLUvec4 *result, + const GLUvec4 *v1, GLfloat f) +{ + result->values[0] = v1->values[0] / f; + result->values[1] = v1->values[1] / f; + result->values[2] = v1->values[2] / f; + result->values[3] = v1->values[3] / f; +} + + +extern inline void gluAdd4v_f(GLUvec4 *result, + const GLUvec4 *v1, GLfloat f) +{ + result->values[0] = v1->values[0] + f; + result->values[1] = v1->values[1] + f; + result->values[2] = v1->values[2] + f; + result->values[3] = v1->values[3] + f; +} + + +extern inline void gluSub4v_f(GLUvec4 *result, + const GLUvec4 *v1, GLfloat f) +{ + result->values[0] = v1->values[0] - f; + result->values[1] = v1->values[1] - f; + result->values[2] = v1->values[2] - f; + result->values[3] = v1->values[3] - f; +} + + +extern inline void gluMult4m_f(GLUmat4 *result, + const GLUmat4 *m, GLfloat f) +{ + GLUmat4 temp; + + gluMult4v_f(& temp.col[0], & m->col[0], f); + gluMult4v_f(& temp.col[1], & m->col[1], f); + gluMult4v_f(& temp.col[2], & m->col[2], f); + gluMult4v_f(& temp.col[3], & m->col[3], f); + *result = temp; +} + + +extern inline void gluMult4m_4v(GLUvec4 *result, + const GLUmat4 *m, const GLUvec4 *v) +{ + GLUvec4 temp[6]; + unsigned i; + + for (i = 0; i < 4; i++) { + gluMult4v_f(& temp[i], & m->col[i], v->values[i]); + } + + gluAdd4v_4v(& temp[4], & temp[0], & temp[1]); + gluAdd4v_4v(& temp[5], & temp[2], & temp[3]); + gluAdd4v_4v(result, & temp[4], & temp[5]); +} + + +extern inline void gluAdd4m_4m(GLUmat4 *result, + const GLUmat4 *m1, const GLUmat4 *m2) +{ + GLUmat4 temp; + + gluAdd4v_4v(& temp.col[0], & m1->col[0], & m2->col[0]); + gluAdd4v_4v(& temp.col[1], & m1->col[1], & m2->col[1]); + gluAdd4v_4v(& temp.col[2], & m1->col[2], & m2->col[2]); + gluAdd4v_4v(& temp.col[3], & m1->col[3], & m2->col[3]); + *result = temp; +} + +extern inline void gluSub4m_4m(GLUmat4 *result, + const GLUmat4 *m1, const GLUmat4 *m2) +{ + GLUmat4 temp; + + gluSub4v_4v(& temp.col[0], & m1->col[0], & m2->col[0]); + gluSub4v_4v(& temp.col[1], & m1->col[1], & m2->col[1]); + gluSub4v_4v(& temp.col[2], & m1->col[2], & m2->col[2]); + gluSub4v_4v(& temp.col[3], & m1->col[3], & m2->col[3]); + *result = temp; +} + +extern inline GLfloat gluDot4_4v(const GLUvec4 *v1, const GLUvec4 *v2) +{ + return v1->values[0] * v2->values[0] + + v1->values[1] * v2->values[1] + + v1->values[2] * v2->values[2] + + v1->values[3] * v2->values[3]; +} + + +extern inline GLfloat gluDot3_4v(const GLUvec4 *v1, const GLUvec4 *v2) +{ + return v1->values[0] * v2->values[0] + + v1->values[1] * v2->values[1] + + v1->values[2] * v2->values[2]; +} + + +extern inline GLfloat gluDot2_4v(const GLUvec4 *v1, const GLUvec4 *v2) +{ + return v1->values[0] * v2->values[0] + + v1->values[1] * v2->values[1]; +} + + +extern inline void gluCross4v(GLUvec4 *result, + const GLUvec4 *v1, const GLUvec4 *v2) +{ + GLUvec4 temp; + + temp.values[0] = (v1->values[1] * v2->values[2]) + - (v1->values[2] * v2->values[1]); + temp.values[1] = (v1->values[2] * v2->values[0]) + - (v1->values[0] * v2->values[2]); + temp.values[2] = (v1->values[0] * v2->values[1]) + - (v1->values[1] * v2->values[0]); + temp.values[3] = 0.0; + *result = temp; +} + + +extern inline void gluOuter4v(GLUmat4 *result, + const GLUvec4 *v1, const GLUvec4 *v2) +{ + GLUmat4 temp; + + gluMult4v_f(& temp.col[0], v1, v2->values[0]); + gluMult4v_f(& temp.col[1], v1, v2->values[1]); + gluMult4v_f(& temp.col[2], v1, v2->values[2]); + gluMult4v_f(& temp.col[3], v1, v2->values[3]); + *result = temp; +} + + +extern inline GLfloat gluLengthSqr4v(const GLUvec4 *v) +{ + return gluDot4_4v(v, v); +} + + +extern inline GLfloat gluLength4v(const GLUvec4 *v) +{ + return sqrt(gluLengthSqr4v(v)); +} + + +extern inline void gluNormalize4v(GLUvec4 *result, const GLUvec4 *v) +{ + gluDiv4v_f(result, v, gluLength4v(v)); +} + + + +extern inline void gluTranspose4m(GLUmat4 *result, const GLUmat4 *m) +{ + unsigned i; + unsigned j; + GLUmat4 temp; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + temp.col[i].values[j] = m->col[j].values[i]; + } + } + + *result = temp; +} + + +extern inline void gluMult4m_4m(GLUmat4 *result, + const GLUmat4 *m1, const GLUmat4 *m2) +{ + GLUmat4 temp; + unsigned i; + + for (i = 0; i < 4; i++) { + gluMult4m_4v(& temp.col[i], m1, & m2->col[i]); + } + + *result = temp; +} + + + +extern inline void gluTranslate3f(GLUmat4 *result, + GLfloat x, GLfloat y, GLfloat z) +{ + memcpy(result, & gluIdentityMatrix, sizeof(gluIdentityMatrix)); + result->col[3].values[0] = x; + result->col[3].values[1] = y; + result->col[3].values[2] = z; +} + + +#ifdef __cplusplus +extern inline GLfloat gluDot4(const GLUvec4 &v1, const GLUvec4 &v2) +{ + return v1.values[0] * v2.values[0] + + v1.values[1] * v2.values[1] + + v1.values[2] * v2.values[2] + + v1.values[3] * v2.values[3]; +} + + +extern inline GLfloat gluDot3(const GLUvec4 &v1, const GLUvec4 &v2) +{ + return v1.values[0] * v2.values[0] + + v1.values[1] * v2.values[1] + + v1.values[2] * v2.values[2]; +} + + +extern inline GLfloat gluDot2(const GLUvec4 &v1, const GLUvec4 &v2) +{ + return v1.values[0] * v2.values[0] + + v1.values[1] * v2.values[1]; +} + + +inline GLUvec4 GLUvec4::operator+(const GLUvec4 &v) const +{ + return GLUvec4(values[0] + v.values[0], + values[1] + v.values[1], + values[2] + v.values[2], + values[3] + v.values[3]); +} + + +inline GLUvec4 GLUvec4::operator-(const GLUvec4 &v) const +{ + return GLUvec4(values[0] - v.values[0], + values[1] - v.values[1], + values[2] - v.values[2], + values[3] - v.values[3]); +} + + +inline GLUvec4 GLUvec4::operator*(const GLUvec4 &v) const +{ + return GLUvec4(values[0] * v.values[0], + values[1] * v.values[1], + values[2] * v.values[2], + values[3] * v.values[3]); +} + + +inline GLUvec4 GLUvec4::operator*(GLfloat f) const +{ + return GLUvec4(values[0] * f, + values[1] * f, + values[2] * f, + values[3] * f); +} + + +inline GLUvec4 GLUvec4::operator*(const GLUmat4 &m) const +{ + return GLUvec4(gluDot4(*this, m.col[0]), + gluDot4(*this, m.col[1]), + gluDot4(*this, m.col[2]), + gluDot4(*this, m.col[3])); +} + + +inline GLUmat4 GLUmat4::operator+(const GLUmat4 &m) const +{ + GLUmat4 temp; + + gluAdd4m_4m(& temp, this, &m); + return temp; +} + + +inline GLUmat4 GLUmat4::operator-(const GLUmat4 &m) const +{ + return GLUmat4(col[0] - m.col[0], + col[1] - m.col[1], + col[2] - m.col[2], + col[3] - m.col[3]); +} + + +inline GLUmat4 GLUmat4::operator*(GLfloat f) const +{ + GLUmat4 temp; + + gluMult4m_f(& temp, this, f); + return temp; +} + + +inline GLUvec4 GLUmat4::operator*(const GLUvec4 &v) const +{ + return (col[0] * v.values[0]) + + (col[1] * v.values[1]) + + (col[2] * v.values[2]) + + (col[3] * v.values[3]); +} + + +inline GLUmat4 GLUmat4::operator*(const GLUmat4 &m) const +{ + GLUmat4 temp; + + gluMult4m_4m(& temp, this, &m); + return temp; +} + + +#endif /* __cplusplus */ diff --git a/glamor/glu3/matrix.c b/glamor/glu3/matrix.c new file mode 100644 index 000000000..b3d5819f7 --- /dev/null +++ b/glamor/glu3/matrix.c @@ -0,0 +1,217 @@ +/* + * Copyright © 2009 Ian D. Romanick + * + * 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 (including the next + * paragraph) 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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 +#include "glu3.h" + +#define DEG2RAD(d) ((d) * M_PI / 180.0) + +const GLUmat4 gluIdentityMatrix = { + { + { { 1.0f, 0.0f, 0.0f, 0.0f } }, + { { 0.0f, 1.0f, 0.0f, 0.0f } }, + { { 0.0f, 0.0f, 1.0f, 0.0f } }, + { { 0.0f, 0.0f, 0.0f, 1.0f } } + } +}; + + +void gluTranslate4v(GLUmat4 *result, const GLUvec4 *t) +{ + memcpy(result, & gluIdentityMatrix, sizeof(gluIdentityMatrix)); + result->col[3] = *t; + result->col[3].values[3] = 1.0f; +} + + +void gluScale4v(GLUmat4 *result, const GLUvec4 *t) +{ + memcpy(result, & gluIdentityMatrix, sizeof(gluIdentityMatrix)); + result->col[0].values[0] = t->values[0]; + result->col[1].values[1] = t->values[1]; + result->col[2].values[2] = t->values[2]; +} + + +void gluLookAt4v(GLUmat4 *result, + const GLUvec4 *_eye, + const GLUvec4 *_center, + const GLUvec4 *_up) +{ + static const GLUvec4 col3 = { { 0.0f, 0.0f, 0.0f, 1.0f } }; + const GLUvec4 e = { + { -_eye->values[0], -_eye->values[1], -_eye->values[2], 0.0f } + }; + GLUmat4 translate; + GLUmat4 rotate; + GLUmat4 rotateT; + GLUvec4 f; + GLUvec4 s; + GLUvec4 u; + GLUvec4 center, up; + + center = *_center; + center.values[3] = 0; + up = *_up; + up.values[3] = 0; + + gluAdd4v_4v(& f, ¢er, &e); + gluNormalize4v(& f, & f); + + gluNormalize4v(& u, &up); + + gluCross4v(& s, & f, & u); + gluCross4v(& u, & s, & f); + + rotate.col[0] = s; + rotate.col[1] = u; + rotate.col[2].values[0] = -f.values[0]; + rotate.col[2].values[1] = -f.values[1]; + rotate.col[2].values[2] = -f.values[2]; + rotate.col[2].values[3] = 0.0f; + rotate.col[3] = col3; + gluTranspose4m(& rotateT, & rotate); + + gluTranslate4v(& translate, & e); + gluMult4m_4m(result, & rotateT, & translate); +} + + +void gluRotate4v(GLUmat4 *result, const GLUvec4 *_axis, GLfloat angle) +{ + GLUvec4 axis; + const float c = cos(angle); + const float s = sin(angle); + const float one_c = 1.0 - c; + + float xx; + float yy; + float zz; + + float xs; + float ys; + float zs; + + float xy; + float xz; + float yz; + + /* Only normalize the 3-component axis. A gluNormalize3v might be + * appropriate to save us some computation. + */ + axis = *_axis; + axis.values[3] = 0; + gluNormalize4v(&axis, &axis); + + xx = axis.values[0] * axis.values[0]; + yy = axis.values[1] * axis.values[1]; + zz = axis.values[2] * axis.values[2]; + + xs = axis.values[0] * s; + ys = axis.values[1] * s; + zs = axis.values[2] * s; + + xy = axis.values[0] * axis.values[1]; + xz = axis.values[0] * axis.values[2]; + yz = axis.values[1] * axis.values[2]; + + + result->col[0].values[0] = (one_c * xx) + c; + result->col[0].values[1] = (one_c * xy) + zs; + result->col[0].values[2] = (one_c * xz) - ys; + result->col[0].values[3] = 0.0; + + result->col[1].values[0] = (one_c * xy) - zs; + result->col[1].values[1] = (one_c * yy) + c; + result->col[1].values[2] = (one_c * yz) + xs; + result->col[1].values[3] = 0.0; + + + result->col[2].values[0] = (one_c * xz) + ys; + result->col[2].values[1] = (one_c * yz) - xs; + result->col[2].values[2] = (one_c * zz) + c; + result->col[2].values[3] = 0.0; + + result->col[3].values[0] = 0.0; + result->col[3].values[1] = 0.0; + result->col[3].values[2] = 0.0; + result->col[3].values[3] = 1.0; +} + + +void +gluPerspective4f(GLUmat4 *result, + GLfloat fovy, GLfloat aspect, GLfloat near, GLfloat far) +{ + const double sine = sin(DEG2RAD(fovy / 2.0)); + const double cosine = cos(DEG2RAD(fovy / 2.0)); + const double sine_aspect = sine * aspect; + const double dz = far - near; + + + memcpy(result, &gluIdentityMatrix, sizeof(gluIdentityMatrix)); + if ((sine == 0.0) || (dz == 0.0) || (sine_aspect == 0.0)) { + return; + } + + result->col[0].values[0] = cosine / sine_aspect; + result->col[1].values[1] = cosine / sine; + result->col[2].values[2] = -(far + near) / dz; + result->col[2].values[3] = -1.0; + result->col[3].values[2] = -2.0 * near * far / dz; + result->col[3].values[3] = 0.0; +} + +void gluFrustum6f(GLUmat4 *result, + GLfloat left, GLfloat right, + GLfloat bottom, GLfloat top, + GLfloat near, GLfloat far) +{ + memcpy(result, &gluIdentityMatrix, sizeof(gluIdentityMatrix)); + + result->col[0].values[0] = (2.0 * near) / (right - left); + result->col[1].values[1] = (2.0 * near) / (top - bottom); + result->col[2].values[0] = (right + left) / (right - left); + result->col[2].values[1] = (top + bottom) / (top - bottom); + result->col[2].values[2] = -(far + near) / (far - near); + result->col[2].values[3] = -1.0; + result->col[3].values[2] = -2.0 * near * far / (far - near); + result->col[3].values[3] = 0.0; +} + +void gluOrtho6f(GLUmat4 *result, + GLfloat left, GLfloat right, + GLfloat bottom, GLfloat top, + GLfloat near, GLfloat far) +{ + memcpy(result, &gluIdentityMatrix, sizeof(gluIdentityMatrix)); + + result->col[0].values[0] = 2.0f / (right - left); + result->col[3].values[0] = -(right + left) / (right - left); + + result->col[1].values[1] = 2.0f / (top - bottom); + result->col[3].values[1] = -(top + bottom) / (top - bottom); + + result->col[2].values[2] = -2.0f / (far - near); + result->col[3].values[2] = -(far + near) / (far - near); +}