/programs/develop/libraries/Mesa/src/mesa/tnl/descrip.mms |
---|
0,0 → 1,68 |
# Makefile for core library for VMS |
# contributed by Jouk Jansen joukj@hrem.nano.tudelft.nl |
# Last revision : 39 September 2008 |
.first |
define gl [---.include.gl] |
define math [-.math] |
define vbo [-.vbo] |
define shader [-.shader] |
define swrast [-.swrast] |
define array_cache [-.array_cache] |
define main [-.main] |
define glapi [-.glapi] |
define tnl [-.tnl] |
.include [---]mms-config. |
##### MACROS ##### |
VPATH = RCS |
INCDIR = [---.include],[-.main],[-.glapi],[-.shader],[-.shader.slang] |
LIBDIR = [---.lib] |
CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)/float=ieee/ieee=denorm |
SOURCES = t_context.c t_draw.c \ |
t_pipeline.c t_vb_fog.c \ |
t_vb_light.c t_vb_normals.c t_vb_points.c t_vb_program.c \ |
t_vb_render.c t_vb_texgen.c t_vb_texmat.c t_vb_vertex.c \ |
t_vertex.c t_rasterpos.c\ |
t_vertex_generic.c t_vp_build.c |
OBJECTS = t_context.obj,t_draw.obj,\ |
t_pipeline.obj,t_vb_fog.obj,t_vb_light.obj,t_vb_normals.obj,\ |
t_vb_points.obj,t_vb_program.obj,t_vb_render.obj,t_vb_texgen.obj,\ |
t_vb_texmat.obj,t_vb_vertex.obj,t_rasterpos.obj,\ |
t_vertex.obj,t_vertex_generic.obj,\ |
t_vp_build.obj |
##### RULES ##### |
VERSION=Mesa V3.4 |
##### TARGETS ##### |
# Make the library |
$(LIBDIR)$(GL_LIB) : $(OBJECTS) |
@ library $(LIBDIR)$(GL_LIB) $(OBJECTS) |
clean : |
purge |
delete *.obj;* |
t_context.obj : t_context.c |
t_draw.obj : t_draw.c |
t_pipeline.obj : t_pipeline.c |
t_vb_fog.obj : t_vb_fog.c |
t_vb_light.obj : t_vb_light.c |
t_vb_normals.obj : t_vb_normals.c |
t_vb_points.obj : t_vb_points.c |
t_vb_program.obj : t_vb_program.c |
t_vb_render.obj : t_vb_render.c |
t_vb_texgen.obj : t_vb_texgen.c |
t_vb_texmat.obj : t_vb_texmat.c |
t_vb_vertex.obj : t_vb_vertex.c |
t_vertex.obj : t_vertex.c |
t_vertex_generic.obj : t_vertex_generic.c |
t_vp_build.obj : t_vp_build.c |
t_rasterpos.obj : t_rasterpos.c |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_context.c |
---|
0,0 → 1,223 |
/* |
* Mesa 3-D graphics library |
* Version: 7.2 |
* |
* 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/imports.h" |
#include "main/context.h" |
#include "main/macros.h" |
#include "main/mtypes.h" |
#include "main/light.h" |
#include "math/m_translate.h" |
#include "math/m_xform.h" |
#include "tnl.h" |
#include "t_context.h" |
#include "t_pipeline.h" |
#include "vbo/vbo.h" |
GLboolean |
_tnl_CreateContext( struct gl_context *ctx ) |
{ |
TNLcontext *tnl; |
/* Create the TNLcontext structure |
*/ |
ctx->swtnl_context = tnl = (TNLcontext *) CALLOC( sizeof(TNLcontext) ); |
if (!tnl) { |
return GL_FALSE; |
} |
/* Initialize the VB. |
*/ |
tnl->vb.Size = ctx->Const.MaxArrayLockSize + MAX_CLIPPED_VERTICES; |
/* Initialize tnl state. |
*/ |
if (ctx->VertexProgram._MaintainTnlProgram) { |
_tnl_install_pipeline( ctx, _tnl_vp_pipeline ); |
} else { |
_tnl_install_pipeline( ctx, _tnl_default_pipeline ); |
} |
tnl->NeedNdcCoords = GL_TRUE; |
tnl->AllowVertexFog = GL_TRUE; |
tnl->AllowPixelFog = GL_TRUE; |
/* Set a few default values in the driver struct. |
*/ |
tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts; |
tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts; |
tnl->Driver.NotifyMaterialChange = _mesa_validate_all_lighting_tables; |
tnl->nr_blocks = 0; |
/* plug in the VBO drawing function */ |
vbo_set_draw_func(ctx, _tnl_vbo_draw_prims); |
_math_init_transformation(); |
_math_init_translate(); |
return GL_TRUE; |
} |
void |
_tnl_DestroyContext( struct gl_context *ctx ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
_tnl_destroy_pipeline( ctx ); |
FREE(tnl); |
ctx->swtnl_context = NULL; |
} |
void |
_tnl_InvalidateState( struct gl_context *ctx, GLuint new_state ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
const struct gl_vertex_program *vp = ctx->VertexProgram._Current; |
const struct gl_fragment_program *fp = ctx->FragmentProgram._Current; |
GLuint i; |
if (new_state & (_NEW_HINT | _NEW_PROGRAM)) { |
ASSERT(tnl->AllowVertexFog || tnl->AllowPixelFog); |
tnl->_DoVertexFog = ((tnl->AllowVertexFog && (ctx->Hint.Fog != GL_NICEST)) |
|| !tnl->AllowPixelFog) && !fp; |
} |
tnl->pipeline.new_state |= new_state; |
/* Calculate tnl->render_inputs. This bitmask indicates which vertex |
* attributes need to be emitted to the rasterizer. |
*/ |
RENDERINPUTS_ZERO( tnl->render_inputs_bitset ); |
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_POS ); |
if (!fp || (fp->Base.InputsRead & FRAG_BIT_COL0)) { |
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_COLOR0 ); |
} |
if (NEED_SECONDARY_COLOR(ctx)) |
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_COLOR1 ); |
for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { |
if (ctx->Texture._EnabledCoordUnits & (1 << i) || |
(fp && fp->Base.InputsRead & FRAG_BIT_TEX(i))) { |
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_TEX(i) ); |
} |
} |
if (ctx->Fog.Enabled) { |
/* fixed-function fog */ |
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_FOG ); |
} |
else if (fp) { |
if (fp->FogOption != GL_NONE || (fp->Base.InputsRead & FRAG_BIT_FOGC)) { |
/* fragment program needs fog coord */ |
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_FOG ); |
} |
} |
if (ctx->Polygon.FrontMode != GL_FILL || |
ctx->Polygon.BackMode != GL_FILL) |
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_EDGEFLAG ); |
if (ctx->RenderMode == GL_FEEDBACK) |
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_TEX0 ); |
if (ctx->Point._Attenuated || |
(ctx->VertexProgram._Enabled && ctx->VertexProgram.PointSizeEnabled)) |
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_POINTSIZE ); |
/* check for varying vars which are written by the vertex program */ |
if (vp) { |
GLuint i; |
for (i = 0; i < MAX_VARYING; i++) { |
if (vp->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_VAR0 + i)) { |
RENDERINPUTS_SET(tnl->render_inputs_bitset, |
_TNL_ATTRIB_GENERIC(i)); |
} |
} |
} |
} |
void |
_tnl_wakeup( struct gl_context *ctx ) |
{ |
/* Assume we haven't been getting state updates either: |
*/ |
_tnl_InvalidateState( ctx, ~0 ); |
#if 0 |
if (ctx->Light.ColorMaterialEnabled) { |
_mesa_update_color_material( ctx, |
ctx->Current.Attrib[VERT_ATTRIB_COLOR0] ); |
} |
#endif |
} |
/** |
* Drivers call this function to tell the TCL module whether or not |
* it wants Normalized Device Coords (NDC) computed. I.e. whether |
* we should "Divide-by-W". Software renders will want that. |
*/ |
void |
_tnl_need_projected_coords( struct gl_context *ctx, GLboolean mode ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
tnl->NeedNdcCoords = mode; |
} |
void |
_tnl_allow_vertex_fog( struct gl_context *ctx, GLboolean value ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
tnl->AllowVertexFog = value; |
tnl->_DoVertexFog = ((tnl->AllowVertexFog && (ctx->Hint.Fog != GL_NICEST)) |
|| !tnl->AllowPixelFog) && !ctx->FragmentProgram._Current; |
} |
void |
_tnl_allow_pixel_fog( struct gl_context *ctx, GLboolean value ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
tnl->AllowPixelFog = value; |
tnl->_DoVertexFog = ((tnl->AllowVertexFog && (ctx->Hint.Fog != GL_NICEST)) |
|| !tnl->AllowPixelFog) && !ctx->FragmentProgram._Current; |
} |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_context.h |
---|
0,0 → 1,545 |
/* |
* mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 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. |
*/ |
/** |
* \file t_context.h |
* \brief TnL module datatypes and definitions. |
* \author Keith Whitwell |
*/ |
/** |
* \mainpage The TNL-module |
* |
* TNL stands for "transform and lighting", i.e. this module implements |
* a pipeline that receives as input a buffer of vertices and does all |
* necessary transformations (rotations, clipping, vertex shader etc.) |
* and passes then the output to the rasterizer. |
* |
* The tnl_pipeline contains the array of all stages, which should be |
* applied. Each stage is a black-box, which is described by an |
* tnl_pipeline_stage. The function ::_tnl_run_pipeline applies all the |
* stages to the vertex_buffer TNLcontext::vb, where the vertex data |
* is stored. The last stage in the pipeline is the rasterizer. |
* |
*/ |
#ifndef _T_CONTEXT_H |
#define _T_CONTEXT_H |
#include "main/glheader.h" |
#include "main/bitset.h" |
#include "main/mtypes.h" |
#include "math/m_vector.h" |
#include "vbo/vbo.h" |
#define MAX_PIPELINE_STAGES 30 |
/* |
* Note: The first attributes match the VERT_ATTRIB_* definitions |
* in mtypes.h. However, the tnl module has additional attributes |
* for materials, color indexes, edge flags, etc. |
*/ |
/* Although it's nice to use these as bit indexes in a DWORD flag, we |
* could manage without if necessary. Another limit currently is the |
* number of bits allocated for these numbers in places like vertex |
* program instruction formats and register layouts. |
*/ |
/* The bit space exhaustion is a fact now, done by _TNL_ATTRIB_ATTRIBUTE* for |
* GLSL vertex shader which cannot be aliased with conventional vertex attribs. |
* Compacting _TNL_ATTRIB_MAT_* attribs would not work, they would not give |
* as many free bits (11 plus already 1 free bit) as _TNL_ATTRIB_ATTRIBUTE* |
* attribs want (16). |
*/ |
enum { |
_TNL_ATTRIB_POS = 0, |
_TNL_ATTRIB_WEIGHT = 1, |
_TNL_ATTRIB_NORMAL = 2, |
_TNL_ATTRIB_COLOR0 = 3, |
_TNL_ATTRIB_COLOR1 = 4, |
_TNL_ATTRIB_FOG = 5, |
_TNL_ATTRIB_COLOR_INDEX = 6, |
_TNL_ATTRIB_EDGEFLAG = 7, |
_TNL_ATTRIB_TEX0 = 8, |
_TNL_ATTRIB_TEX1 = 9, |
_TNL_ATTRIB_TEX2 = 10, |
_TNL_ATTRIB_TEX3 = 11, |
_TNL_ATTRIB_TEX4 = 12, |
_TNL_ATTRIB_TEX5 = 13, |
_TNL_ATTRIB_TEX6 = 14, |
_TNL_ATTRIB_TEX7 = 15, |
_TNL_ATTRIB_GENERIC0 = 16, /* doesn't really exist! */ |
_TNL_ATTRIB_GENERIC1 = 17, |
_TNL_ATTRIB_GENERIC2 = 18, |
_TNL_ATTRIB_GENERIC3 = 19, |
_TNL_ATTRIB_GENERIC4 = 20, |
_TNL_ATTRIB_GENERIC5 = 21, |
_TNL_ATTRIB_GENERIC6 = 22, |
_TNL_ATTRIB_GENERIC7 = 23, |
_TNL_ATTRIB_GENERIC8 = 24, |
_TNL_ATTRIB_GENERIC9 = 25, |
_TNL_ATTRIB_GENERIC10 = 26, |
_TNL_ATTRIB_GENERIC11 = 27, |
_TNL_ATTRIB_GENERIC12 = 28, |
_TNL_ATTRIB_GENERIC13 = 29, |
_TNL_ATTRIB_GENERIC14 = 30, |
_TNL_ATTRIB_GENERIC15 = 31, |
/* These alias with the generics, but they are not active |
* concurrently, so it's not a problem. The TNL module |
* doesn't have to do anything about this as this is how they |
* are passed into the _draw_prims callback. |
* |
* When we generate fixed-function replacement programs (in |
* t_vp_build.c currently), they refer to the appropriate |
* generic attribute in order to pick up per-vertex material |
* data. |
*/ |
_TNL_ATTRIB_MAT_FRONT_AMBIENT = 16, |
_TNL_ATTRIB_MAT_BACK_AMBIENT = 17, |
_TNL_ATTRIB_MAT_FRONT_DIFFUSE = 18, |
_TNL_ATTRIB_MAT_BACK_DIFFUSE = 19, |
_TNL_ATTRIB_MAT_FRONT_SPECULAR = 20, |
_TNL_ATTRIB_MAT_BACK_SPECULAR = 21, |
_TNL_ATTRIB_MAT_FRONT_EMISSION = 22, |
_TNL_ATTRIB_MAT_BACK_EMISSION = 23, |
_TNL_ATTRIB_MAT_FRONT_SHININESS = 24, |
_TNL_ATTRIB_MAT_BACK_SHININESS = 25, |
_TNL_ATTRIB_MAT_FRONT_INDEXES = 26, |
_TNL_ATTRIB_MAT_BACK_INDEXES = 27, |
/* This is really a VERT_RESULT, not an attrib. Need to fix |
* tnl to understand the difference. |
*/ |
_TNL_ATTRIB_POINTSIZE = 16, |
_TNL_ATTRIB_MAX = 32 |
} ; |
#define _TNL_ATTRIB_TEX(u) (_TNL_ATTRIB_TEX0 + (u)) |
#define _TNL_ATTRIB_GENERIC(n) (_TNL_ATTRIB_GENERIC0 + (n)) |
/* special index used for handing invalid glVertexAttribute() indices */ |
#define _TNL_ATTRIB_ERROR (_TNL_ATTRIB_GENERIC15 + 1) |
/** |
* Handy attribute ranges: |
*/ |
#define _TNL_FIRST_PROG _TNL_ATTRIB_WEIGHT |
#define _TNL_LAST_PROG _TNL_ATTRIB_TEX7 |
#define _TNL_FIRST_TEX _TNL_ATTRIB_TEX0 |
#define _TNL_LAST_TEX _TNL_ATTRIB_TEX7 |
#define _TNL_FIRST_GENERIC _TNL_ATTRIB_GENERIC0 |
#define _TNL_LAST_GENERIC _TNL_ATTRIB_GENERIC15 |
#define _TNL_FIRST_MAT _TNL_ATTRIB_MAT_FRONT_AMBIENT /* GENERIC0 */ |
#define _TNL_LAST_MAT _TNL_ATTRIB_MAT_BACK_INDEXES /* GENERIC11 */ |
/* Number of available generic attributes */ |
#define _TNL_NUM_GENERIC 16 |
/* Number of attributes used for evaluators */ |
#define _TNL_NUM_EVAL 16 |
#define PRIM_BEGIN 0x10 |
#define PRIM_END 0x20 |
#define PRIM_MODE_MASK 0x0f |
static INLINE GLuint _tnl_translate_prim( const struct _mesa_prim *prim ) |
{ |
GLuint flag; |
flag = prim->mode; |
if (prim->begin) flag |= PRIM_BEGIN; |
if (prim->end) flag |= PRIM_END; |
return flag; |
} |
/** |
* Contains the current state of a running pipeline. |
*/ |
struct vertex_buffer |
{ |
GLuint Size; /**< Max vertices per vertex buffer, constant */ |
/* Constant over the pipeline. |
*/ |
GLuint Count; /**< Number of vertices currently in buffer */ |
/* Pointers to current data. Most of the data is in AttribPtr -- all of |
* it that is one of VERT_ATTRIB_X. For things only produced by TNL, |
* such as backface color or eye-space coordinates, they are stored |
* here. |
*/ |
GLuint *Elts; |
GLvector4f *EyePtr; /* _TNL_BIT_POS */ |
GLvector4f *ClipPtr; /* _TNL_BIT_POS */ |
GLvector4f *NdcPtr; /* _TNL_BIT_POS */ |
GLubyte ClipOrMask; /* _TNL_BIT_POS */ |
GLubyte ClipAndMask; /* _TNL_BIT_POS */ |
GLubyte *ClipMask; /* _TNL_BIT_POS */ |
GLfloat *NormalLengthPtr; /* _TNL_BIT_NORMAL */ |
GLboolean *EdgeFlag; /* _TNL_BIT_EDGEFLAG */ |
GLvector4f *BackfaceIndexPtr; |
GLvector4f *BackfaceColorPtr; |
GLvector4f *BackfaceSecondaryColorPtr; |
const struct _mesa_prim *Primitive; |
GLuint PrimitiveCount; |
/* Inputs to the vertex program stage */ |
GLvector4f *AttribPtr[_TNL_ATTRIB_MAX]; /* GL_NV_vertex_program */ |
}; |
/** |
* Describes an individual operation on the pipeline. |
*/ |
struct tnl_pipeline_stage |
{ |
const char *name; |
/* Private data for the pipeline stage: |
*/ |
void *privatePtr; |
/* Allocate private data |
*/ |
GLboolean (*create)( struct gl_context *ctx, struct tnl_pipeline_stage * ); |
/* Free private data. |
*/ |
void (*destroy)( struct tnl_pipeline_stage * ); |
/* Called on any statechange or input array size change or |
* input array change to/from zero stride. |
*/ |
void (*validate)( struct gl_context *ctx, struct tnl_pipeline_stage * ); |
/* Called from _tnl_run_pipeline(). The stage.changed_inputs value |
* encodes all inputs to thee struct which have changed. If |
* non-zero, recompute all affected outputs of the stage, otherwise |
* execute any 'sideeffects' of the stage. |
* |
* Return value: GL_TRUE - keep going |
* GL_FALSE - finished pipeline |
*/ |
GLboolean (*run)( struct gl_context *ctx, struct tnl_pipeline_stage * ); |
}; |
/** Contains the array of all pipeline stages. |
* The default values are defined at the end of t_pipeline.c |
*/ |
struct tnl_pipeline { |
GLuint last_attrib_stride[_TNL_ATTRIB_MAX]; |
GLuint last_attrib_size[_TNL_ATTRIB_MAX]; |
GLuint input_changes; |
GLuint new_state; |
struct tnl_pipeline_stage stages[MAX_PIPELINE_STAGES+1]; |
GLuint nr_stages; |
}; |
struct tnl_clipspace; |
struct tnl_clipspace_attr; |
typedef void (*tnl_extract_func)( const struct tnl_clipspace_attr *a, |
GLfloat *out, |
const GLubyte *v ); |
typedef void (*tnl_insert_func)( const struct tnl_clipspace_attr *a, |
GLubyte *v, |
const GLfloat *in ); |
typedef void (*tnl_emit_func)( struct gl_context *ctx, |
GLuint count, |
GLubyte *dest ); |
/** |
* Describes how to convert/move a vertex attribute from a vertex array |
* to a vertex structure. |
*/ |
struct tnl_clipspace_attr |
{ |
GLuint attrib; /* which vertex attrib (0=position, etc) */ |
GLuint format; |
GLuint vertoffset; /* position of the attrib in the vertex struct */ |
GLuint vertattrsize; /* size of the attribute in bytes */ |
GLubyte *inputptr; |
GLuint inputstride; |
GLuint inputsize; |
const tnl_insert_func *insert; |
tnl_insert_func emit; |
tnl_extract_func extract; |
const GLfloat *vp; /* NDC->Viewport mapping matrix */ |
}; |
typedef void (*tnl_points_func)( struct gl_context *ctx, GLuint first, GLuint last ); |
typedef void (*tnl_line_func)( struct gl_context *ctx, GLuint v1, GLuint v2 ); |
typedef void (*tnl_triangle_func)( struct gl_context *ctx, |
GLuint v1, GLuint v2, GLuint v3 ); |
typedef void (*tnl_quad_func)( struct gl_context *ctx, GLuint v1, GLuint v2, |
GLuint v3, GLuint v4 ); |
typedef void (*tnl_render_func)( struct gl_context *ctx, GLuint start, GLuint count, |
GLuint flags ); |
typedef void (*tnl_interp_func)( struct gl_context *ctx, |
GLfloat t, GLuint dst, GLuint out, GLuint in, |
GLboolean force_boundary ); |
typedef void (*tnl_copy_pv_func)( struct gl_context *ctx, GLuint dst, GLuint src ); |
typedef void (*tnl_setup_func)( struct gl_context *ctx, |
GLuint start, GLuint end, |
GLuint new_inputs); |
struct tnl_attr_type { |
GLuint format; |
GLuint size; |
GLuint stride; |
GLuint offset; |
}; |
struct tnl_clipspace_fastpath { |
GLuint vertex_size; |
GLuint attr_count; |
GLboolean match_strides; |
struct tnl_attr_type *attr; |
tnl_emit_func func; |
struct tnl_clipspace_fastpath *next; |
}; |
/** |
* Used to describe conversion of vertex arrays to vertex structures. |
* I.e. Structure of arrays to arrays of structs. |
*/ |
struct tnl_clipspace |
{ |
GLboolean need_extras; |
GLuint new_inputs; |
GLubyte *vertex_buf; |
GLuint vertex_size; |
GLuint max_vertex_size; |
struct tnl_clipspace_attr attr[_TNL_ATTRIB_MAX]; |
GLuint attr_count; |
tnl_emit_func emit; |
tnl_interp_func interp; |
tnl_copy_pv_func copy_pv; |
/* Parameters and constants for codegen: |
*/ |
GLboolean need_viewport; |
GLfloat vp_scale[4]; |
GLfloat vp_xlate[4]; |
GLfloat chan_scale[4]; |
GLfloat identity[4]; |
struct tnl_clipspace_fastpath *fastpath; |
void (*codegen_emit)( struct gl_context *ctx ); |
}; |
struct tnl_device_driver |
{ |
/*** |
*** TNL Pipeline |
***/ |
void (*RunPipeline)(struct gl_context *ctx); |
/* Replaces PipelineStart/PipelineFinish -- intended to allow |
* drivers to wrap _tnl_run_pipeline() with code to validate state |
* and grab/release hardware locks. |
*/ |
void (*NotifyMaterialChange)(struct gl_context *ctx); |
/* Alert tnl-aware drivers of changes to material. |
*/ |
/*** |
*** Rendering -- These functions called only from t_vb_render.c |
***/ |
struct |
{ |
void (*Start)(struct gl_context *ctx); |
void (*Finish)(struct gl_context *ctx); |
/* Called before and after all rendering operations, including DrawPixels, |
* ReadPixels, Bitmap, span functions, and CopyTexImage, etc commands. |
* These are a suitable place for grabbing/releasing hardware locks. |
*/ |
void (*PrimitiveNotify)(struct gl_context *ctx, GLenum mode); |
/* Called between RenderStart() and RenderFinish() to indicate the |
* type of primitive we're about to draw. Mode will be one of the |
* modes accepted by glBegin(). |
*/ |
tnl_interp_func Interp; |
/* The interp function is called by the clipping routines when we need |
* to generate an interpolated vertex. All pertinant vertex ancilliary |
* data should be computed by interpolating between the 'in' and 'out' |
* vertices. |
*/ |
tnl_copy_pv_func CopyPV; |
/* The copy function is used to make a copy of a vertex. All pertinant |
* vertex attributes should be copied. |
*/ |
void (*ClippedPolygon)( struct gl_context *ctx, const GLuint *elts, GLuint n ); |
/* Render a polygon with <n> vertices whose indexes are in the <elts> |
* array. |
*/ |
void (*ClippedLine)( struct gl_context *ctx, GLuint v0, GLuint v1 ); |
/* Render a line between the two vertices given by indexes v0 and v1. */ |
tnl_points_func Points; /* must now respect vb->elts */ |
tnl_line_func Line; |
tnl_triangle_func Triangle; |
tnl_quad_func Quad; |
/* These functions are called in order to render points, lines, |
* triangles and quads. These are only called via the T&L module. |
*/ |
tnl_render_func *PrimTabVerts; |
tnl_render_func *PrimTabElts; |
/* Render whole unclipped primitives (points, lines, linestrips, |
* lineloops, etc). The tables are indexed by the GL enum of the |
* primitive to be rendered. RenderTabVerts is used for non-indexed |
* arrays of vertices. RenderTabElts is used for indexed arrays of |
* vertices. |
*/ |
void (*ResetLineStipple)( struct gl_context *ctx ); |
/* Reset the hardware's line stipple counter. |
*/ |
tnl_setup_func BuildVertices; |
/* This function is called whenever new vertices are required for |
* rendering. The vertices in question are those n such that start |
* <= n < end. The new_inputs parameter indicates those fields of |
* the vertex which need to be updated, if only a partial repair of |
* the vertex is required. |
* |
* This function is called only from _tnl_render_stage in tnl/t_render.c. |
*/ |
GLboolean (*Multipass)( struct gl_context *ctx, GLuint passno ); |
/* Driver may request additional render passes by returning GL_TRUE |
* when this function is called. This function will be called |
* after the first pass, and passes will be made until the function |
* returns GL_FALSE. If no function is registered, only one pass |
* is made. |
* |
* This function will be first invoked with passno == 1. |
*/ |
} Render; |
}; |
#define DECLARE_RENDERINPUTS(name) BITSET64_DECLARE(name, _TNL_ATTRIB_MAX) |
#define RENDERINPUTS_COPY BITSET64_COPY |
#define RENDERINPUTS_EQUAL BITSET64_EQUAL |
#define RENDERINPUTS_ZERO BITSET64_ZERO |
#define RENDERINPUTS_ONES BITSET64_ONES |
#define RENDERINPUTS_TEST BITSET64_TEST |
#define RENDERINPUTS_SET BITSET64_SET |
#define RENDERINPUTS_CLEAR BITSET64_CLEAR |
#define RENDERINPUTS_TEST_RANGE BITSET64_TEST_RANGE |
#define RENDERINPUTS_SET_RANGE BITSET64_SET_RANGE |
#define RENDERINPUTS_CLEAR_RANGE BITSET64_CLEAR_RANGE |
/** |
* Context state for T&L context. |
*/ |
typedef struct |
{ |
/* Driver interface. |
*/ |
struct tnl_device_driver Driver; |
/* Pipeline |
*/ |
struct tnl_pipeline pipeline; |
struct vertex_buffer vb; |
/* Clipspace/ndc/window vertex managment: |
*/ |
struct tnl_clipspace clipspace; |
/* Probably need a better configuration mechanism: |
*/ |
GLboolean NeedNdcCoords; |
GLboolean AllowVertexFog; |
GLboolean AllowPixelFog; |
GLboolean _DoVertexFog; /* eval fog function at each vertex? */ |
DECLARE_RENDERINPUTS(render_inputs_bitset); |
GLvector4f tmp_inputs[VERT_ATTRIB_MAX]; |
/* Temp storage for t_draw.c: |
*/ |
GLubyte *block[VERT_ATTRIB_MAX]; |
GLuint nr_blocks; |
} TNLcontext; |
#define TNL_CONTEXT(ctx) ((TNLcontext *)((ctx)->swtnl_context)) |
#define TYPE_IDX(t) ((t) & 0xf) |
#define MAX_TYPES TYPE_IDX(GL_DOUBLE)+1 /* 0xa + 1 */ |
extern void |
tnl_clip_prepare(struct gl_context *ctx); |
#endif |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_draw.c |
---|
0,0 → 1,527 |
/* |
* Mesa 3-D graphics library |
* Version: 7.1 |
* |
* Copyright (C) 1999-2007 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/condrender.h" |
#include "main/context.h" |
#include "main/imports.h" |
#include "main/mtypes.h" |
#include "main/macros.h" |
#include "main/enums.h" |
#include "t_context.h" |
#include "tnl.h" |
static GLubyte *get_space(struct gl_context *ctx, GLuint bytes) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
GLubyte *space = malloc(bytes); |
tnl->block[tnl->nr_blocks++] = space; |
return space; |
} |
static void free_space(struct gl_context *ctx) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
GLuint i; |
for (i = 0; i < tnl->nr_blocks; i++) |
free(tnl->block[i]); |
tnl->nr_blocks = 0; |
} |
/* Convert the incoming array to GLfloats. Understands the |
* array->Normalized flag and selects the correct conversion method. |
*/ |
#define CONVERT( TYPE, MACRO ) do { \ |
GLuint i, j; \ |
if (input->Normalized) { \ |
for (i = 0; i < count; i++) { \ |
const TYPE *in = (TYPE *)ptr; \ |
for (j = 0; j < sz; j++) { \ |
*fptr++ = MACRO(*in); \ |
in++; \ |
} \ |
ptr += input->StrideB; \ |
} \ |
} else { \ |
for (i = 0; i < count; i++) { \ |
const TYPE *in = (TYPE *)ptr; \ |
for (j = 0; j < sz; j++) { \ |
*fptr++ = (GLfloat)(*in); \ |
in++; \ |
} \ |
ptr += input->StrideB; \ |
} \ |
} \ |
} while (0) |
/** |
* Convert array of BGRA/GLubyte[4] values to RGBA/float[4] |
* \param ptr input/ubyte array |
* \param fptr output/float array |
*/ |
static void |
convert_bgra_to_float(const struct gl_client_array *input, |
const GLubyte *ptr, GLfloat *fptr, |
GLuint count ) |
{ |
GLuint i; |
assert(input->Normalized); |
assert(input->Size == 4); |
for (i = 0; i < count; i++) { |
const GLubyte *in = (GLubyte *) ptr; /* in is in BGRA order */ |
*fptr++ = UBYTE_TO_FLOAT(in[2]); /* red */ |
*fptr++ = UBYTE_TO_FLOAT(in[1]); /* green */ |
*fptr++ = UBYTE_TO_FLOAT(in[0]); /* blue */ |
*fptr++ = UBYTE_TO_FLOAT(in[3]); /* alpha */ |
ptr += input->StrideB; |
} |
} |
static void |
convert_half_to_float(const struct gl_client_array *input, |
const GLubyte *ptr, GLfloat *fptr, |
GLuint count, GLuint sz) |
{ |
GLuint i, j; |
for (i = 0; i < count; i++) { |
GLhalfARB *in = (GLhalfARB *)ptr; |
for (j = 0; j < sz; j++) { |
*fptr++ = _mesa_half_to_float(in[j]); |
} |
ptr += input->StrideB; |
} |
} |
/** |
* \brief Convert fixed-point to floating-point. |
* |
* In OpenGL, a fixed-point number is a "signed 2's complement 16.16 scaled |
* integer" (Table 2.2 of the OpenGL ES 2.0 spec). |
* |
* If the buffer has the \c normalized flag set, the formula |
* \code normalize(x) := (2*x + 1) / (2^16 - 1) \endcode |
* is used to map the fixed-point numbers into the range [-1, 1]. |
*/ |
static void |
convert_fixed_to_float(const struct gl_client_array *input, |
const GLubyte *ptr, GLfloat *fptr, |
GLuint count) |
{ |
GLuint i, j; |
const GLint size = input->Size; |
if (input->Normalized) { |
for (i = 0; i < count; ++i) { |
const GLfixed *in = (GLfixed *) ptr; |
for (j = 0; j < size; ++j) { |
*fptr++ = (GLfloat) (2 * in[j] + 1) / (GLfloat) ((1 << 16) - 1); |
} |
ptr += input->StrideB; |
} |
} else { |
for (i = 0; i < count; ++i) { |
const GLfixed *in = (GLfixed *) ptr; |
for (j = 0; j < size; ++j) { |
*fptr++ = in[j] / (GLfloat) (1 << 16); |
} |
ptr += input->StrideB; |
} |
} |
} |
/* Adjust pointer to point at first requested element, convert to |
* floating point, populate VB->AttribPtr[]. |
*/ |
static void _tnl_import_array( struct gl_context *ctx, |
GLuint attrib, |
GLuint count, |
const struct gl_client_array *input, |
const GLubyte *ptr ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
GLuint stride = input->StrideB; |
if (input->Type != GL_FLOAT) { |
const GLuint sz = input->Size; |
GLubyte *buf = get_space(ctx, count * sz * sizeof(GLfloat)); |
GLfloat *fptr = (GLfloat *)buf; |
switch (input->Type) { |
case GL_BYTE: |
CONVERT(GLbyte, BYTE_TO_FLOAT); |
break; |
case GL_UNSIGNED_BYTE: |
if (input->Format == GL_BGRA) { |
/* See GL_EXT_vertex_array_bgra */ |
convert_bgra_to_float(input, ptr, fptr, count); |
} |
else { |
CONVERT(GLubyte, UBYTE_TO_FLOAT); |
} |
break; |
case GL_SHORT: |
CONVERT(GLshort, SHORT_TO_FLOAT); |
break; |
case GL_UNSIGNED_SHORT: |
CONVERT(GLushort, USHORT_TO_FLOAT); |
break; |
case GL_INT: |
CONVERT(GLint, INT_TO_FLOAT); |
break; |
case GL_UNSIGNED_INT: |
CONVERT(GLuint, UINT_TO_FLOAT); |
break; |
case GL_DOUBLE: |
CONVERT(GLdouble, (GLfloat)); |
break; |
case GL_HALF_FLOAT: |
convert_half_to_float(input, ptr, fptr, count, sz); |
break; |
case GL_FIXED: |
convert_fixed_to_float(input, ptr, fptr, count); |
break; |
default: |
assert(0); |
break; |
} |
ptr = buf; |
stride = sz * sizeof(GLfloat); |
} |
VB->AttribPtr[attrib] = &tnl->tmp_inputs[attrib]; |
VB->AttribPtr[attrib]->data = (GLfloat (*)[4])ptr; |
VB->AttribPtr[attrib]->start = (GLfloat *)ptr; |
VB->AttribPtr[attrib]->count = count; |
VB->AttribPtr[attrib]->stride = stride; |
VB->AttribPtr[attrib]->size = input->Size; |
/* This should die, but so should the whole GLvector4f concept: |
*/ |
VB->AttribPtr[attrib]->flags = (((1<<input->Size)-1) | |
VEC_NOT_WRITEABLE | |
(stride == 4*sizeof(GLfloat) ? 0 : VEC_BAD_STRIDE)); |
VB->AttribPtr[attrib]->storage = NULL; |
} |
#define CLIPVERTS ((6 + MAX_CLIP_PLANES) * 2) |
static GLboolean *_tnl_import_edgeflag( struct gl_context *ctx, |
const GLvector4f *input, |
GLuint count) |
{ |
const GLubyte *ptr = (const GLubyte *)input->data; |
const GLuint stride = input->stride; |
GLboolean *space = (GLboolean *)get_space(ctx, count + CLIPVERTS); |
GLboolean *bptr = space; |
GLuint i; |
for (i = 0; i < count; i++) { |
*bptr++ = ((GLfloat *)ptr)[0] == 1.0; |
ptr += stride; |
} |
return space; |
} |
static void bind_inputs( struct gl_context *ctx, |
const struct gl_client_array *inputs[], |
GLint count, |
struct gl_buffer_object **bo, |
GLuint *nr_bo ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
GLuint i; |
/* Map all the VBOs |
*/ |
for (i = 0; i < VERT_ATTRIB_MAX; i++) { |
const void *ptr; |
if (inputs[i]->BufferObj->Name) { |
if (!inputs[i]->BufferObj->Pointer) { |
bo[*nr_bo] = inputs[i]->BufferObj; |
(*nr_bo)++; |
ctx->Driver.MapBuffer(ctx, |
GL_ARRAY_BUFFER, |
GL_READ_ONLY_ARB, |
inputs[i]->BufferObj); |
assert(inputs[i]->BufferObj->Pointer); |
} |
ptr = ADD_POINTERS(inputs[i]->BufferObj->Pointer, |
inputs[i]->Ptr); |
} |
else |
ptr = inputs[i]->Ptr; |
/* Just make sure the array is floating point, otherwise convert to |
* temporary storage. |
* |
* XXX: remove the GLvector4f type at some stage and just use |
* client arrays. |
*/ |
_tnl_import_array(ctx, i, count, inputs[i], ptr); |
} |
/* We process only the vertices between min & max index: |
*/ |
VB->Count = count; |
/* These should perhaps be part of _TNL_ATTRIB_* */ |
VB->BackfaceColorPtr = NULL; |
VB->BackfaceIndexPtr = NULL; |
VB->BackfaceSecondaryColorPtr = NULL; |
/* Clipping and drawing code still requires this to be a packed |
* array of ubytes which can be written into. TODO: Fix and |
* remove. |
*/ |
if (ctx->Polygon.FrontMode != GL_FILL || |
ctx->Polygon.BackMode != GL_FILL) |
{ |
VB->EdgeFlag = _tnl_import_edgeflag( ctx, |
VB->AttribPtr[_TNL_ATTRIB_EDGEFLAG], |
VB->Count ); |
} |
else { |
/* the data previously pointed to by EdgeFlag may have been freed */ |
VB->EdgeFlag = NULL; |
} |
} |
/* Translate indices to GLuints and store in VB->Elts. |
*/ |
static void bind_indices( struct gl_context *ctx, |
const struct _mesa_index_buffer *ib, |
struct gl_buffer_object **bo, |
GLuint *nr_bo) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
GLuint i; |
void *ptr; |
if (!ib) { |
VB->Elts = NULL; |
return; |
} |
if (ib->obj->Name && !ib->obj->Pointer) { |
bo[*nr_bo] = ib->obj; |
(*nr_bo)++; |
ctx->Driver.MapBuffer(ctx, |
GL_ELEMENT_ARRAY_BUFFER, |
GL_READ_ONLY_ARB, |
ib->obj); |
assert(ib->obj->Pointer); |
} |
ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr); |
if (ib->type == GL_UNSIGNED_INT && VB->Primitive[0].basevertex == 0) { |
VB->Elts = (GLuint *) ptr; |
} |
else { |
GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint)); |
VB->Elts = elts; |
if (ib->type == GL_UNSIGNED_INT) { |
const GLuint *in = (GLuint *)ptr; |
for (i = 0; i < ib->count; i++) |
*elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; |
} |
else if (ib->type == GL_UNSIGNED_SHORT) { |
const GLushort *in = (GLushort *)ptr; |
for (i = 0; i < ib->count; i++) |
*elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; |
} |
else { |
const GLubyte *in = (GLubyte *)ptr; |
for (i = 0; i < ib->count; i++) |
*elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; |
} |
} |
} |
static void bind_prims( struct gl_context *ctx, |
const struct _mesa_prim *prim, |
GLuint nr_prims ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
VB->Primitive = prim; |
VB->PrimitiveCount = nr_prims; |
} |
static void unmap_vbos( struct gl_context *ctx, |
struct gl_buffer_object **bo, |
GLuint nr_bo ) |
{ |
GLuint i; |
for (i = 0; i < nr_bo; i++) { |
ctx->Driver.UnmapBuffer(ctx, |
0, /* target -- I don't see why this would be needed */ |
bo[i]); |
} |
} |
void _tnl_vbo_draw_prims(struct gl_context *ctx, |
const struct gl_client_array *arrays[], |
const struct _mesa_prim *prim, |
GLuint nr_prims, |
const struct _mesa_index_buffer *ib, |
GLboolean index_bounds_valid, |
GLuint min_index, |
GLuint max_index) |
{ |
if (!index_bounds_valid) |
vbo_get_minmax_index(ctx, prim, ib, &min_index, &max_index); |
_tnl_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index); |
} |
/* This is the main entrypoint into the slimmed-down software tnl |
* module. In a regular swtnl driver, this can be plugged straight |
* into the vbo->Driver.DrawPrims() callback. |
*/ |
void _tnl_draw_prims( struct gl_context *ctx, |
const struct gl_client_array *arrays[], |
const struct _mesa_prim *prim, |
GLuint nr_prims, |
const struct _mesa_index_buffer *ib, |
GLuint min_index, |
GLuint max_index) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
const GLuint TEST_SPLIT = 0; |
const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES; |
GLint max_basevertex = prim->basevertex; |
GLuint i; |
/* Mesa core state should have been validated already */ |
assert(ctx->NewState == 0x0); |
if (!_mesa_check_conditional_render(ctx)) |
return; /* don't draw */ |
for (i = 1; i < nr_prims; i++) |
max_basevertex = MAX2(max_basevertex, prim[i].basevertex); |
if (0) |
{ |
printf("%s %d..%d\n", __FUNCTION__, min_index, max_index); |
for (i = 0; i < nr_prims; i++) |
printf("prim %d: %s start %d count %d\n", i, |
_mesa_lookup_enum_by_nr(prim[i].mode), |
prim[i].start, |
prim[i].count); |
} |
if (min_index) { |
/* We always translate away calls with min_index != 0. |
*/ |
vbo_rebase_prims( ctx, arrays, prim, nr_prims, ib, |
min_index, max_index, |
_tnl_vbo_draw_prims ); |
return; |
} |
else if ((GLint)max_index + max_basevertex > max) { |
/* The software TNL pipeline has a fixed amount of storage for |
* vertices and it is necessary to split incoming drawing commands |
* if they exceed that limit. |
*/ |
struct split_limits limits; |
limits.max_verts = max; |
limits.max_vb_size = ~0; |
limits.max_indices = ~0; |
/* This will split the buffers one way or another and |
* recursively call back into this function. |
*/ |
vbo_split_prims( ctx, arrays, prim, nr_prims, ib, |
0, max_index + prim->basevertex, |
_tnl_vbo_draw_prims, |
&limits ); |
} |
else { |
/* May need to map a vertex buffer object for every attribute plus |
* one for the index buffer. |
*/ |
struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1]; |
GLuint nr_bo = 0; |
for (i = 0; i < nr_prims;) { |
GLuint this_nr_prims; |
/* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices |
* will rebase the elements to the basevertex, and we'll only |
* emit strings of prims with the same basevertex in one draw call. |
*/ |
for (this_nr_prims = 1; i + this_nr_prims < nr_prims; |
this_nr_prims++) { |
if (prim[i].basevertex != prim[i + this_nr_prims].basevertex) |
break; |
} |
/* Binding inputs may imply mapping some vertex buffer objects. |
* They will need to be unmapped below. |
*/ |
bind_prims(ctx, &prim[i], this_nr_prims); |
bind_inputs(ctx, arrays, max_index + prim[i].basevertex + 1, |
bo, &nr_bo); |
bind_indices(ctx, ib, bo, &nr_bo); |
TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx); |
unmap_vbos(ctx, bo, nr_bo); |
free_space(ctx); |
i += this_nr_prims; |
} |
} |
} |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_pipeline.c |
---|
0,0 → 1,210 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5.3 |
* |
* Copyright (C) 1999-2007 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/context.h" |
#include "main/imports.h" |
#include "main/mtypes.h" |
#include "t_context.h" |
#include "t_pipeline.h" |
#include "t_vp_build.h" |
#include "t_vertex.h" |
void _tnl_install_pipeline( struct gl_context *ctx, |
const struct tnl_pipeline_stage **stages ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
GLuint i; |
tnl->pipeline.new_state = ~0; |
/* Create a writeable copy of each stage. |
*/ |
for (i = 0 ; i < MAX_PIPELINE_STAGES && stages[i] ; i++) { |
struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i]; |
memcpy(s, stages[i], sizeof(*s)); |
if (s->create) |
s->create(ctx, s); |
} |
tnl->pipeline.nr_stages = i; |
} |
void _tnl_destroy_pipeline( struct gl_context *ctx ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
GLuint i; |
for (i = 0 ; i < tnl->pipeline.nr_stages ; i++) { |
struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i]; |
if (s->destroy) |
s->destroy(s); |
} |
tnl->pipeline.nr_stages = 0; |
} |
static GLuint check_input_changes( struct gl_context *ctx ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
GLuint i; |
for (i = 0; i <= _TNL_LAST_MAT; i++) { |
if (tnl->vb.AttribPtr[i]->size != tnl->pipeline.last_attrib_size[i] || |
tnl->vb.AttribPtr[i]->stride != tnl->pipeline.last_attrib_stride[i]) { |
tnl->pipeline.last_attrib_size[i] = tnl->vb.AttribPtr[i]->size; |
tnl->pipeline.last_attrib_stride[i] = tnl->vb.AttribPtr[i]->stride; |
tnl->pipeline.input_changes |= 1<<i; |
} |
} |
return tnl->pipeline.input_changes; |
} |
static GLuint check_output_changes( struct gl_context *ctx ) |
{ |
#if 0 |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
for (i = 0; i < VERT_RESULT_MAX; i++) { |
if (tnl->vb.ResultPtr[i]->size != tnl->last_result_size[i] || |
tnl->vb.ResultPtr[i]->stride != tnl->last_result_stride[i]) { |
tnl->last_result_size[i] = tnl->vb.ResultPtr[i]->size; |
tnl->last_result_stride[i] = tnl->vb.ResultPtr[i]->stride; |
tnl->pipeline.output_changes |= 1<<i; |
} |
} |
if (tnl->pipeline.output_changes) |
tnl->Driver.NotifyOutputChanges( ctx, tnl->pipeline.output_changes ); |
return tnl->pipeline.output_changes; |
#else |
return ~0; |
#endif |
} |
void _tnl_run_pipeline( struct gl_context *ctx ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
unsigned short __tmp; |
GLuint i; |
if (!tnl->vb.Count) |
return; |
/* Check for changed input sizes or change in stride to/from zero |
* (ie const or non-const). |
*/ |
if (check_input_changes( ctx ) || tnl->pipeline.new_state) { |
if (ctx->VertexProgram._MaintainTnlProgram) |
_tnl_UpdateFixedFunctionProgram( ctx ); |
for (i = 0; i < tnl->pipeline.nr_stages ; i++) { |
struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i]; |
if (s->validate) |
s->validate( ctx, s ); |
} |
tnl->pipeline.new_state = 0; |
tnl->pipeline.input_changes = 0; |
/* Pipeline can only change its output in response to either a |
* statechange or an input size/stride change. No other changes |
* are allowed. |
*/ |
if (check_output_changes( ctx )) |
_tnl_notify_pipeline_output_change( ctx ); |
} |
START_FAST_MATH(__tmp); |
for (i = 0; i < tnl->pipeline.nr_stages ; i++) { |
struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i]; |
if (!s->run( ctx, s )) |
break; |
} |
END_FAST_MATH(__tmp); |
} |
/* The default pipeline. This is useful for software rasterizers, and |
* simple hardware rasterizers. For customization, I don't recommend |
* tampering with the internals of these stages in the way that |
* drivers did in Mesa 3.4. These stages are basically black boxes, |
* and should be left intact. |
* |
* To customize the pipeline, consider: |
* |
* - removing redundant stages (making sure that the software rasterizer |
* can cope with this on fallback paths). An example is fog |
* coordinate generation, which is not required in the FX driver. |
* |
* - replacing general-purpose machine-independent stages with |
* general-purpose machine-specific stages. There is no example of |
* this to date, though it must be borne in mind that all subsequent |
* stages that reference the output of the new stage must cope with |
* any machine-specific data introduced. This may not be easy |
* unless there are no such stages (ie the new stage is the last in |
* the pipe). |
* |
* - inserting optimized (but specialized) stages ahead of the |
* general-purpose fallback implementation. For example, the old |
* fastpath mechanism, which only works when the VB->Elts input is |
* available, can be duplicated by placing the fastpath stage at the |
* head of this pipeline. Such specialized stages are currently |
* constrained to have no outputs (ie. they must either finish the * |
* pipeline by returning GL_FALSE from run(), or do nothing). |
* |
* Some work can be done to lift some of the restrictions in the final |
* case, if it becomes necessary to do so. |
*/ |
const struct tnl_pipeline_stage *_tnl_default_pipeline[] = { |
&_tnl_vertex_transform_stage, |
&_tnl_normal_transform_stage, |
&_tnl_lighting_stage, |
&_tnl_texgen_stage, |
&_tnl_texture_transform_stage, |
&_tnl_point_attenuation_stage, |
&_tnl_vertex_program_stage, |
&_tnl_fog_coordinate_stage, |
&_tnl_render_stage, |
NULL |
}; |
const struct tnl_pipeline_stage *_tnl_vp_pipeline[] = { |
&_tnl_vertex_program_stage, |
&_tnl_render_stage, |
NULL |
}; |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_pipeline.h |
---|
0,0 → 1,73 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5.3 |
* |
* Copyright (C) 1999-2007 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#ifndef _T_PIPELINE_H_ |
#define _T_PIPELINE_H_ |
#include "main/mtypes.h" |
#include "t_context.h" |
extern void _tnl_run_pipeline( struct gl_context *ctx ); |
extern void _tnl_destroy_pipeline( struct gl_context *ctx ); |
extern void _tnl_install_pipeline( struct gl_context *ctx, |
const struct tnl_pipeline_stage **stages ); |
/* These are implemented in the t_vb_*.c files: |
*/ |
extern const struct tnl_pipeline_stage _tnl_vertex_transform_stage; |
extern const struct tnl_pipeline_stage _tnl_normal_transform_stage; |
extern const struct tnl_pipeline_stage _tnl_lighting_stage; |
extern const struct tnl_pipeline_stage _tnl_fog_coordinate_stage; |
extern const struct tnl_pipeline_stage _tnl_texgen_stage; |
extern const struct tnl_pipeline_stage _tnl_texture_transform_stage; |
extern const struct tnl_pipeline_stage _tnl_point_attenuation_stage; |
extern const struct tnl_pipeline_stage _tnl_vertex_program_stage; |
extern const struct tnl_pipeline_stage _tnl_render_stage; |
/* Shorthand to plug in the default pipeline: |
*/ |
extern const struct tnl_pipeline_stage *_tnl_default_pipeline[]; |
extern const struct tnl_pipeline_stage *_tnl_vp_pipeline[]; |
/* Convenience routines provided by t_vb_render.c: |
*/ |
extern tnl_render_func _tnl_render_tab_elts[]; |
extern tnl_render_func _tnl_render_tab_verts[]; |
extern void _tnl_RenderClippedPolygon( struct gl_context *ctx, |
const GLuint *elts, GLuint n ); |
extern void _tnl_RenderClippedLine( struct gl_context *ctx, GLuint ii, GLuint jj ); |
#endif |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_rasterpos.c |
---|
0,0 → 1,486 |
/* |
* Mesa 3-D graphics library |
* Version: 7.1 |
* |
* Copyright (C) 1999-2007 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 "main/glheader.h" |
#include "main/colormac.h" |
#include "main/feedback.h" |
#include "main/light.h" |
#include "main/macros.h" |
#include "main/simple_list.h" |
#include "main/mtypes.h" |
#include "math/m_matrix.h" |
#include "tnl/tnl.h" |
/** |
* Clip a point against the view volume. |
* |
* \param v vertex vector describing the point to clip. |
* |
* \return zero if outside view volume, or one if inside. |
*/ |
static GLuint |
viewclip_point_xy( const GLfloat v[] ) |
{ |
if ( v[0] > v[3] || v[0] < -v[3] |
|| v[1] > v[3] || v[1] < -v[3] ) { |
return 0; |
} |
else { |
return 1; |
} |
} |
/** |
* Clip a point against the far/near Z clipping planes. |
* |
* \param v vertex vector describing the point to clip. |
* |
* \return zero if outside view volume, or one if inside. |
*/ |
static GLuint |
viewclip_point_z( const GLfloat v[] ) |
{ |
if (v[2] > v[3] || v[2] < -v[3] ) { |
return 0; |
} |
else { |
return 1; |
} |
} |
/** |
* Clip a point against the user clipping planes. |
* |
* \param ctx GL context. |
* \param v vertex vector describing the point to clip. |
* |
* \return zero if the point was clipped, or one otherwise. |
*/ |
static GLuint |
userclip_point( struct gl_context *ctx, const GLfloat v[] ) |
{ |
GLuint p; |
for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { |
if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { |
GLfloat dot = v[0] * ctx->Transform._ClipUserPlane[p][0] |
+ v[1] * ctx->Transform._ClipUserPlane[p][1] |
+ v[2] * ctx->Transform._ClipUserPlane[p][2] |
+ v[3] * ctx->Transform._ClipUserPlane[p][3]; |
if (dot < 0.0F) { |
return 0; |
} |
} |
} |
return 1; |
} |
/** |
* Compute lighting for the raster position. Both RGB and CI modes computed. |
* \param ctx the context |
* \param vertex vertex location |
* \param normal normal vector |
* \param Rcolor returned color |
* \param Rspec returned specular color (if separate specular enabled) |
* \param Rindex returned color index |
*/ |
static void |
shade_rastpos(struct gl_context *ctx, |
const GLfloat vertex[4], |
const GLfloat normal[3], |
GLfloat Rcolor[4], |
GLfloat Rspec[4]) |
{ |
/*const*/ GLfloat (*base)[3] = ctx->Light._BaseColor; |
const struct gl_light *light; |
GLfloat diffuseColor[4], specularColor[4]; /* for RGB mode only */ |
GLfloat diffuseCI = 0.0, specularCI = 0.0; /* for CI mode only */ |
_mesa_validate_all_lighting_tables( ctx ); |
COPY_3V(diffuseColor, base[0]); |
diffuseColor[3] = CLAMP( |
ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3], 0.0F, 1.0F ); |
ASSIGN_4V(specularColor, 0.0, 0.0, 0.0, 1.0); |
foreach (light, &ctx->Light.EnabledList) { |
GLfloat attenuation = 1.0; |
GLfloat VP[3]; /* vector from vertex to light pos */ |
GLfloat n_dot_VP; |
GLfloat diffuseContrib[3], specularContrib[3]; |
if (!(light->_Flags & LIGHT_POSITIONAL)) { |
/* light at infinity */ |
COPY_3V(VP, light->_VP_inf_norm); |
attenuation = light->_VP_inf_spot_attenuation; |
} |
else { |
/* local/positional light */ |
GLfloat d; |
/* VP = vector from vertex pos to light[i].pos */ |
SUB_3V(VP, light->_Position, vertex); |
/* d = length(VP) */ |
d = (GLfloat) LEN_3FV( VP ); |
if (d > 1.0e-6) { |
/* normalize VP */ |
GLfloat invd = 1.0F / d; |
SELF_SCALE_SCALAR_3V(VP, invd); |
} |
/* atti */ |
attenuation = 1.0F / (light->ConstantAttenuation + d * |
(light->LinearAttenuation + d * |
light->QuadraticAttenuation)); |
if (light->_Flags & LIGHT_SPOT) { |
GLfloat PV_dot_dir = - DOT3(VP, light->_NormSpotDirection); |
if (PV_dot_dir<light->_CosCutoff) { |
continue; |
} |
else { |
double x = PV_dot_dir * (EXP_TABLE_SIZE-1); |
int k = (int) x; |
GLfloat spot = (GLfloat) (light->_SpotExpTable[k][0] |
+ (x-k)*light->_SpotExpTable[k][1]); |
attenuation *= spot; |
} |
} |
} |
if (attenuation < 1e-3) |
continue; |
n_dot_VP = DOT3( normal, VP ); |
if (n_dot_VP < 0.0F) { |
ACC_SCALE_SCALAR_3V(diffuseColor, attenuation, light->_MatAmbient[0]); |
continue; |
} |
/* Ambient + diffuse */ |
COPY_3V(diffuseContrib, light->_MatAmbient[0]); |
ACC_SCALE_SCALAR_3V(diffuseContrib, n_dot_VP, light->_MatDiffuse[0]); |
diffuseCI += n_dot_VP * light->_dli * attenuation; |
/* Specular */ |
{ |
const GLfloat *h; |
GLfloat n_dot_h; |
ASSIGN_3V(specularContrib, 0.0, 0.0, 0.0); |
if (ctx->Light.Model.LocalViewer) { |
GLfloat v[3]; |
COPY_3V(v, vertex); |
NORMALIZE_3FV(v); |
SUB_3V(VP, VP, v); |
NORMALIZE_3FV(VP); |
h = VP; |
} |
else if (light->_Flags & LIGHT_POSITIONAL) { |
ACC_3V(VP, ctx->_EyeZDir); |
NORMALIZE_3FV(VP); |
h = VP; |
} |
else { |
h = light->_h_inf_norm; |
} |
n_dot_h = DOT3(normal, h); |
if (n_dot_h > 0.0F) { |
GLfloat spec_coef; |
GET_SHINE_TAB_ENTRY( ctx->_ShineTable[0], n_dot_h, spec_coef ); |
if (spec_coef > 1.0e-10) { |
if (ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR) { |
ACC_SCALE_SCALAR_3V( specularContrib, spec_coef, |
light->_MatSpecular[0]); |
} |
else { |
ACC_SCALE_SCALAR_3V( diffuseContrib, spec_coef, |
light->_MatSpecular[0]); |
} |
/*assert(light->_sli > 0.0);*/ |
specularCI += spec_coef * light->_sli * attenuation; |
} |
} |
} |
ACC_SCALE_SCALAR_3V( diffuseColor, attenuation, diffuseContrib ); |
ACC_SCALE_SCALAR_3V( specularColor, attenuation, specularContrib ); |
} |
Rcolor[0] = CLAMP(diffuseColor[0], 0.0F, 1.0F); |
Rcolor[1] = CLAMP(diffuseColor[1], 0.0F, 1.0F); |
Rcolor[2] = CLAMP(diffuseColor[2], 0.0F, 1.0F); |
Rcolor[3] = CLAMP(diffuseColor[3], 0.0F, 1.0F); |
Rspec[0] = CLAMP(specularColor[0], 0.0F, 1.0F); |
Rspec[1] = CLAMP(specularColor[1], 0.0F, 1.0F); |
Rspec[2] = CLAMP(specularColor[2], 0.0F, 1.0F); |
Rspec[3] = CLAMP(specularColor[3], 0.0F, 1.0F); |
} |
/** |
* Do texgen needed for glRasterPos. |
* \param ctx rendering context |
* \param vObj object-space vertex coordinate |
* \param vEye eye-space vertex coordinate |
* \param normal vertex normal |
* \param unit texture unit number |
* \param texcoord incoming texcoord and resulting texcoord |
*/ |
static void |
compute_texgen(struct gl_context *ctx, const GLfloat vObj[4], const GLfloat vEye[4], |
const GLfloat normal[3], GLuint unit, GLfloat texcoord[4]) |
{ |
const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; |
/* always compute sphere map terms, just in case */ |
GLfloat u[3], two_nu, rx, ry, rz, m, mInv; |
COPY_3V(u, vEye); |
NORMALIZE_3FV(u); |
two_nu = 2.0F * DOT3(normal, u); |
rx = u[0] - normal[0] * two_nu; |
ry = u[1] - normal[1] * two_nu; |
rz = u[2] - normal[2] * two_nu; |
m = rx * rx + ry * ry + (rz + 1.0F) * (rz + 1.0F); |
if (m > 0.0F) |
mInv = 0.5F * _mesa_inv_sqrtf(m); |
else |
mInv = 0.0F; |
if (texUnit->TexGenEnabled & S_BIT) { |
switch (texUnit->GenS.Mode) { |
case GL_OBJECT_LINEAR: |
texcoord[0] = DOT4(vObj, texUnit->GenS.ObjectPlane); |
break; |
case GL_EYE_LINEAR: |
texcoord[0] = DOT4(vEye, texUnit->GenS.EyePlane); |
break; |
case GL_SPHERE_MAP: |
texcoord[0] = rx * mInv + 0.5F; |
break; |
case GL_REFLECTION_MAP: |
texcoord[0] = rx; |
break; |
case GL_NORMAL_MAP: |
texcoord[0] = normal[0]; |
break; |
default: |
_mesa_problem(ctx, "Bad S texgen in compute_texgen()"); |
return; |
} |
} |
if (texUnit->TexGenEnabled & T_BIT) { |
switch (texUnit->GenT.Mode) { |
case GL_OBJECT_LINEAR: |
texcoord[1] = DOT4(vObj, texUnit->GenT.ObjectPlane); |
break; |
case GL_EYE_LINEAR: |
texcoord[1] = DOT4(vEye, texUnit->GenT.EyePlane); |
break; |
case GL_SPHERE_MAP: |
texcoord[1] = ry * mInv + 0.5F; |
break; |
case GL_REFLECTION_MAP: |
texcoord[1] = ry; |
break; |
case GL_NORMAL_MAP: |
texcoord[1] = normal[1]; |
break; |
default: |
_mesa_problem(ctx, "Bad T texgen in compute_texgen()"); |
return; |
} |
} |
if (texUnit->TexGenEnabled & R_BIT) { |
switch (texUnit->GenR.Mode) { |
case GL_OBJECT_LINEAR: |
texcoord[2] = DOT4(vObj, texUnit->GenR.ObjectPlane); |
break; |
case GL_EYE_LINEAR: |
texcoord[2] = DOT4(vEye, texUnit->GenR.EyePlane); |
break; |
case GL_REFLECTION_MAP: |
texcoord[2] = rz; |
break; |
case GL_NORMAL_MAP: |
texcoord[2] = normal[2]; |
break; |
default: |
_mesa_problem(ctx, "Bad R texgen in compute_texgen()"); |
return; |
} |
} |
if (texUnit->TexGenEnabled & Q_BIT) { |
switch (texUnit->GenQ.Mode) { |
case GL_OBJECT_LINEAR: |
texcoord[3] = DOT4(vObj, texUnit->GenQ.ObjectPlane); |
break; |
case GL_EYE_LINEAR: |
texcoord[3] = DOT4(vEye, texUnit->GenQ.EyePlane); |
break; |
default: |
_mesa_problem(ctx, "Bad Q texgen in compute_texgen()"); |
return; |
} |
} |
} |
/** |
* glRasterPos transformation. Typically called via ctx->Driver.RasterPos(). |
* XXX some of this code (such as viewport xform, clip testing and setting |
* of ctx->Current.Raster* fields) could get lifted up into the |
* main/rasterpos.c code. |
* |
* \param vObj vertex position in object space |
*/ |
void |
_tnl_RasterPos(struct gl_context *ctx, const GLfloat vObj[4]) |
{ |
if (ctx->VertexProgram._Enabled) { |
/* XXX implement this */ |
_mesa_problem(ctx, "Vertex programs not implemented for glRasterPos"); |
return; |
} |
else { |
GLfloat eye[4], clip[4], ndc[3], d; |
GLfloat *norm, eyenorm[3]; |
GLfloat *objnorm = ctx->Current.Attrib[VERT_ATTRIB_NORMAL]; |
/* apply modelview matrix: eye = MV * obj */ |
TRANSFORM_POINT( eye, ctx->ModelviewMatrixStack.Top->m, vObj ); |
/* apply projection matrix: clip = Proj * eye */ |
TRANSFORM_POINT( clip, ctx->ProjectionMatrixStack.Top->m, eye ); |
/* clip to view volume. */ |
if (!ctx->Transform.DepthClamp) { |
if (viewclip_point_z(clip) == 0) { |
ctx->Current.RasterPosValid = GL_FALSE; |
return; |
} |
} |
if (!ctx->Transform.RasterPositionUnclipped) { |
if (viewclip_point_xy(clip) == 0) { |
ctx->Current.RasterPosValid = GL_FALSE; |
return; |
} |
} |
/* clip to user clipping planes */ |
if (ctx->Transform.ClipPlanesEnabled && !userclip_point(ctx, clip)) { |
ctx->Current.RasterPosValid = GL_FALSE; |
return; |
} |
/* ndc = clip / W */ |
d = (clip[3] == 0.0F) ? 1.0F : 1.0F / clip[3]; |
ndc[0] = clip[0] * d; |
ndc[1] = clip[1] * d; |
ndc[2] = clip[2] * d; |
/* wincoord = viewport_mapping(ndc) */ |
ctx->Current.RasterPos[0] = (ndc[0] * ctx->Viewport._WindowMap.m[MAT_SX] |
+ ctx->Viewport._WindowMap.m[MAT_TX]); |
ctx->Current.RasterPos[1] = (ndc[1] * ctx->Viewport._WindowMap.m[MAT_SY] |
+ ctx->Viewport._WindowMap.m[MAT_TY]); |
ctx->Current.RasterPos[2] = (ndc[2] * ctx->Viewport._WindowMap.m[MAT_SZ] |
+ ctx->Viewport._WindowMap.m[MAT_TZ]) |
/ ctx->DrawBuffer->_DepthMaxF; |
ctx->Current.RasterPos[3] = clip[3]; |
if (ctx->Transform.DepthClamp) { |
ctx->Current.RasterPos[3] = CLAMP(ctx->Current.RasterPos[3], |
ctx->Viewport.Near, |
ctx->Viewport.Far); |
} |
/* compute raster distance */ |
if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT) |
ctx->Current.RasterDistance = ctx->Current.Attrib[VERT_ATTRIB_FOG][0]; |
else |
ctx->Current.RasterDistance = |
SQRTF( eye[0]*eye[0] + eye[1]*eye[1] + eye[2]*eye[2] ); |
/* compute transformed normal vector (for lighting or texgen) */ |
if (ctx->_NeedEyeCoords) { |
const GLfloat *inv = ctx->ModelviewMatrixStack.Top->inv; |
TRANSFORM_NORMAL( eyenorm, objnorm, inv ); |
norm = eyenorm; |
} |
else { |
norm = objnorm; |
} |
/* update raster color */ |
if (ctx->Light.Enabled) { |
/* lighting */ |
shade_rastpos( ctx, vObj, norm, |
ctx->Current.RasterColor, |
ctx->Current.RasterSecondaryColor ); |
} |
else { |
/* use current color */ |
COPY_4FV(ctx->Current.RasterColor, |
ctx->Current.Attrib[VERT_ATTRIB_COLOR0]); |
COPY_4FV(ctx->Current.RasterSecondaryColor, |
ctx->Current.Attrib[VERT_ATTRIB_COLOR1]); |
} |
/* texture coords */ |
{ |
GLuint u; |
for (u = 0; u < ctx->Const.MaxTextureCoordUnits; u++) { |
GLfloat tc[4]; |
COPY_4V(tc, ctx->Current.Attrib[VERT_ATTRIB_TEX0 + u]); |
if (ctx->Texture.Unit[u].TexGenEnabled) { |
compute_texgen(ctx, vObj, eye, norm, u, tc); |
} |
TRANSFORM_POINT(ctx->Current.RasterTexCoords[u], |
ctx->TextureMatrixStack[u].Top->m, tc); |
} |
} |
ctx->Current.RasterPosValid = GL_TRUE; |
} |
if (ctx->RenderMode == GL_SELECT) { |
_mesa_update_hitflag( ctx, ctx->Current.RasterPos[2] ); |
} |
} |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_cliptmp.h |
---|
0,0 → 1,320 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5.2 |
* |
* Copyright (C) 1999-2006 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#define CLIP_DOTPROD(K, A, B, C, D) X(K)*A + Y(K)*B + Z(K)*C + W(K)*D |
#define POLY_CLIP( PLANE_BIT, A, B, C, D ) \ |
do { \ |
if (mask & PLANE_BIT) { \ |
GLuint idxPrev = inlist[0]; \ |
GLfloat dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \ |
GLuint outcount = 0; \ |
GLuint i; \ |
\ |
inlist[n] = inlist[0]; /* prevent rotation of vertices */ \ |
for (i = 1; i <= n; i++) { \ |
GLuint idx = inlist[i]; \ |
GLfloat dp = CLIP_DOTPROD(idx, A, B, C, D ); \ |
\ |
if (!IS_NEGATIVE(dpPrev)) { \ |
outlist[outcount++] = idxPrev; \ |
} \ |
\ |
if (DIFFERENT_SIGNS(dp, dpPrev)) { \ |
if (IS_NEGATIVE(dp)) { \ |
/* Going out of bounds. Avoid division by zero as we \ |
* know dp != dpPrev from DIFFERENT_SIGNS, above. \ |
*/ \ |
GLfloat t = dp / (dp - dpPrev); \ |
INTERP_4F( t, coord[newvert], coord[idx], coord[idxPrev]); \ |
interp( ctx, t, newvert, idx, idxPrev, GL_TRUE ); \ |
} else { \ |
/* Coming back in. \ |
*/ \ |
GLfloat t = dpPrev / (dpPrev - dp); \ |
INTERP_4F( t, coord[newvert], coord[idxPrev], coord[idx]); \ |
interp( ctx, t, newvert, idxPrev, idx, GL_FALSE ); \ |
} \ |
outlist[outcount++] = newvert++; \ |
} \ |
\ |
idxPrev = idx; \ |
dpPrev = dp; \ |
} \ |
\ |
if (outcount < 3) \ |
return; \ |
\ |
{ \ |
GLuint *tmp = inlist; \ |
inlist = outlist; \ |
outlist = tmp; \ |
n = outcount; \ |
} \ |
} \ |
} while (0) |
#define LINE_CLIP(PLANE_BIT, A, B, C, D ) \ |
do { \ |
if (mask & PLANE_BIT) { \ |
const GLfloat dp0 = CLIP_DOTPROD( v0, A, B, C, D ); \ |
const GLfloat dp1 = CLIP_DOTPROD( v1, A, B, C, D ); \ |
const GLboolean neg_dp0 = IS_NEGATIVE(dp0); \ |
const GLboolean neg_dp1 = IS_NEGATIVE(dp1); \ |
\ |
/* For regular clipping, we know from the clipmask that one \ |
* (or both) of these must be negative (otherwise we wouldn't \ |
* be here). \ |
* For userclip, there is only a single bit for all active \ |
* planes, so we can end up here when there is nothing to do, \ |
* hence the second IS_NEGATIVE() test: \ |
*/ \ |
if (neg_dp0 && neg_dp1) \ |
return; /* both vertices outside clip plane: discard */ \ |
\ |
if (neg_dp1) { \ |
GLfloat t = dp1 / (dp1 - dp0); \ |
if (t > t1) t1 = t; \ |
} else if (neg_dp0) { \ |
GLfloat t = dp0 / (dp0 - dp1); \ |
if (t > t0) t0 = t; \ |
} \ |
if (t0 + t1 >= 1.0) \ |
return; /* discard */ \ |
} \ |
} while (0) |
/* Clip a line against the viewport and user clip planes. |
*/ |
static INLINE void |
TAG(clip_line)( struct gl_context *ctx, GLuint v0, GLuint v1, GLubyte mask ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
tnl_interp_func interp = tnl->Driver.Render.Interp; |
GLfloat (*coord)[4] = VB->ClipPtr->data; |
GLuint newvert = VB->Count; |
GLfloat t0 = 0; |
GLfloat t1 = 0; |
GLuint p; |
const GLuint v0_orig = v0; |
if (mask & CLIP_FRUSTUM_BITS) { |
LINE_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 ); |
LINE_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 ); |
LINE_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 ); |
LINE_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 ); |
LINE_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 ); |
LINE_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 ); |
} |
if (mask & CLIP_USER_BIT) { |
for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { |
if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { |
const GLfloat a = ctx->Transform._ClipUserPlane[p][0]; |
const GLfloat b = ctx->Transform._ClipUserPlane[p][1]; |
const GLfloat c = ctx->Transform._ClipUserPlane[p][2]; |
const GLfloat d = ctx->Transform._ClipUserPlane[p][3]; |
LINE_CLIP( CLIP_USER_BIT, a, b, c, d ); |
} |
} |
} |
if (VB->ClipMask[v0]) { |
INTERP_4F( t0, coord[newvert], coord[v0], coord[v1] ); |
interp( ctx, t0, newvert, v0, v1, GL_FALSE ); |
v0 = newvert; |
newvert++; |
} |
else { |
ASSERT(t0 == 0.0); |
} |
/* Note: we need to use vertex v0_orig when computing the new |
* interpolated/clipped vertex position, not the current v0 which |
* may have got set when we clipped the other end of the line! |
*/ |
if (VB->ClipMask[v1]) { |
INTERP_4F( t1, coord[newvert], coord[v1], coord[v0_orig] ); |
interp( ctx, t1, newvert, v1, v0_orig, GL_FALSE ); |
if (ctx->Light.ShadeModel == GL_FLAT) |
tnl->Driver.Render.CopyPV( ctx, newvert, v1 ); |
v1 = newvert; |
newvert++; |
} |
else { |
ASSERT(t1 == 0.0); |
} |
tnl->Driver.Render.ClippedLine( ctx, v0, v1 ); |
} |
/* Clip a triangle against the viewport and user clip planes. |
*/ |
static INLINE void |
TAG(clip_tri)( struct gl_context *ctx, GLuint v0, GLuint v1, GLuint v2, GLubyte mask ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
tnl_interp_func interp = tnl->Driver.Render.Interp; |
GLuint newvert = VB->Count; |
GLfloat (*coord)[4] = VB->ClipPtr->data; |
GLuint pv = v2; |
GLuint vlist[2][MAX_CLIPPED_VERTICES]; |
GLuint *inlist = vlist[0], *outlist = vlist[1]; |
GLuint p; |
GLuint n = 3; |
ASSIGN_3V(inlist, v2, v0, v1 ); /* pv rotated to slot zero */ |
if (0) { |
/* print pre-clip vertex coords */ |
GLuint i, j; |
printf("pre clip:\n"); |
for (i = 0; i < n; i++) { |
j = inlist[i]; |
printf(" %u: %u: %f, %f, %f, %f\n", |
i, j, |
coord[j][0], coord[j][1], coord[j][2], coord[j][3]); |
assert(!IS_INF_OR_NAN(coord[j][0])); |
assert(!IS_INF_OR_NAN(coord[j][1])); |
assert(!IS_INF_OR_NAN(coord[j][2])); |
assert(!IS_INF_OR_NAN(coord[j][3])); |
} |
} |
if (mask & CLIP_FRUSTUM_BITS) { |
POLY_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 ); |
POLY_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 ); |
POLY_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 ); |
POLY_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 ); |
POLY_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 ); |
POLY_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 ); |
} |
if (mask & CLIP_USER_BIT) { |
for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { |
if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { |
const GLfloat a = ctx->Transform._ClipUserPlane[p][0]; |
const GLfloat b = ctx->Transform._ClipUserPlane[p][1]; |
const GLfloat c = ctx->Transform._ClipUserPlane[p][2]; |
const GLfloat d = ctx->Transform._ClipUserPlane[p][3]; |
POLY_CLIP( CLIP_USER_BIT, a, b, c, d ); |
} |
} |
} |
if (ctx->Light.ShadeModel == GL_FLAT) { |
if (pv != inlist[0]) { |
ASSERT( inlist[0] >= VB->Count ); |
tnl->Driver.Render.CopyPV( ctx, inlist[0], pv ); |
} |
} |
if (0) { |
/* print post-clip vertex coords */ |
GLuint i, j; |
printf("post clip:\n"); |
for (i = 0; i < n; i++) { |
j = inlist[i]; |
printf(" %u: %u: %f, %f, %f, %f\n", |
i, j, |
coord[j][0], coord[j][1], coord[j][2], coord[j][3]); |
} |
} |
tnl->Driver.Render.ClippedPolygon( ctx, inlist, n ); |
} |
/* Clip a quad against the viewport and user clip planes. |
*/ |
static INLINE void |
TAG(clip_quad)( struct gl_context *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint v3, |
GLubyte mask ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
tnl_interp_func interp = tnl->Driver.Render.Interp; |
GLuint newvert = VB->Count; |
GLfloat (*coord)[4] = VB->ClipPtr->data; |
GLuint pv = v3; |
GLuint vlist[2][MAX_CLIPPED_VERTICES]; |
GLuint *inlist = vlist[0], *outlist = vlist[1]; |
GLuint p; |
GLuint n = 4; |
ASSIGN_4V(inlist, v3, v0, v1, v2 ); /* pv rotated to slot zero */ |
if (mask & CLIP_FRUSTUM_BITS) { |
POLY_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 ); |
POLY_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 ); |
POLY_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 ); |
POLY_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 ); |
POLY_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 ); |
POLY_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 ); |
} |
if (mask & CLIP_USER_BIT) { |
for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { |
if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { |
const GLfloat a = ctx->Transform._ClipUserPlane[p][0]; |
const GLfloat b = ctx->Transform._ClipUserPlane[p][1]; |
const GLfloat c = ctx->Transform._ClipUserPlane[p][2]; |
const GLfloat d = ctx->Transform._ClipUserPlane[p][3]; |
POLY_CLIP( CLIP_USER_BIT, a, b, c, d ); |
} |
} |
} |
if (ctx->Light.ShadeModel == GL_FLAT) { |
if (pv != inlist[0]) { |
ASSERT( inlist[0] >= VB->Count ); |
tnl->Driver.Render.CopyPV( ctx, inlist[0], pv ); |
} |
} |
tnl->Driver.Render.ClippedPolygon( ctx, inlist, n ); |
} |
#undef W |
#undef Z |
#undef Y |
#undef X |
#undef SIZE |
#undef TAG |
#undef POLY_CLIP |
#undef LINE_CLIP |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_fog.c |
---|
0,0 → 1,276 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/colormac.h" |
#include "main/macros.h" |
#include "main/imports.h" |
#include "main/mtypes.h" |
#include "math/m_xform.h" |
#include "t_context.h" |
#include "t_pipeline.h" |
struct fog_stage_data { |
GLvector4f fogcoord; /* has actual storage allocated */ |
}; |
#define FOG_STAGE_DATA(stage) ((struct fog_stage_data *)stage->privatePtr) |
#define FOG_EXP_TABLE_SIZE 256 |
#define FOG_MAX (10.0) |
#define EXP_FOG_MAX .0006595 |
#define FOG_INCR (FOG_MAX/FOG_EXP_TABLE_SIZE) |
static GLfloat exp_table[FOG_EXP_TABLE_SIZE]; |
static GLfloat inited = 0; |
#if 1 |
#define NEG_EXP( result, narg ) \ |
do { \ |
GLfloat f = (GLfloat) (narg * (1.0/FOG_INCR)); \ |
GLint k = (GLint) f; \ |
if (k > FOG_EXP_TABLE_SIZE-2) \ |
result = (GLfloat) EXP_FOG_MAX; \ |
else \ |
result = exp_table[k] + (f-k)*(exp_table[k+1]-exp_table[k]); \ |
} while (0) |
#else |
#define NEG_EXP( result, narg ) \ |
do { \ |
result = exp(-narg); \ |
} while (0) |
#endif |
/** |
* Initialize the exp_table[] lookup table for approximating exp(). |
*/ |
static void |
init_static_data( void ) |
{ |
GLfloat f = 0.0F; |
GLint i = 0; |
for ( ; i < FOG_EXP_TABLE_SIZE ; i++, f += FOG_INCR) { |
exp_table[i] = EXPF(-f); |
} |
inited = 1; |
} |
/** |
* Compute per-vertex fog blend factors from fog coordinates by |
* evaluating the GL_LINEAR, GL_EXP or GL_EXP2 fog function. |
* Fog coordinates are distances from the eye (typically between the |
* near and far clip plane distances). |
* Note that fogcoords may be negative, if eye z is source absolute |
* value must be taken earlier. |
* Fog blend factors are in the range [0,1]. |
*/ |
static void |
compute_fog_blend_factors(struct gl_context *ctx, GLvector4f *out, const GLvector4f *in) |
{ |
GLfloat end = ctx->Fog.End; |
GLfloat *v = in->start; |
GLuint stride = in->stride; |
GLuint n = in->count; |
GLfloat (*data)[4] = out->data; |
GLfloat d; |
GLuint i; |
out->count = in->count; |
switch (ctx->Fog.Mode) { |
case GL_LINEAR: |
if (ctx->Fog.Start == ctx->Fog.End) |
d = 1.0F; |
else |
d = 1.0F / (ctx->Fog.End - ctx->Fog.Start); |
for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) { |
const GLfloat z = *v; |
GLfloat f = (end - z) * d; |
data[i][0] = CLAMP(f, 0.0F, 1.0F); |
} |
break; |
case GL_EXP: |
d = ctx->Fog.Density; |
for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride)) { |
const GLfloat z = *v; |
NEG_EXP( data[i][0], d * z ); |
} |
break; |
case GL_EXP2: |
d = ctx->Fog.Density*ctx->Fog.Density; |
for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) { |
const GLfloat z = *v; |
NEG_EXP( data[i][0], d * z * z ); |
} |
break; |
default: |
_mesa_problem(ctx, "Bad fog mode in make_fog_coord"); |
return; |
} |
} |
static GLboolean |
run_fog_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
struct fog_stage_data *store = FOG_STAGE_DATA(stage); |
GLvector4f *input; |
if (!ctx->Fog.Enabled) |
return GL_TRUE; |
if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT && !ctx->VertexProgram._Current) { |
GLuint i; |
GLfloat *coord; |
/* Fog is computed from vertex or fragment Z values */ |
/* source = VB->AttribPtr[_TNL_ATTRIB_POS] or VB->EyePtr coords */ |
/* dest = VB->AttribPtr[_TNL_ATTRIB_FOG] = fog stage private storage */ |
VB->AttribPtr[_TNL_ATTRIB_FOG] = &store->fogcoord; |
if (!ctx->_NeedEyeCoords) { |
/* compute fog coords from object coords */ |
const GLfloat *m = ctx->ModelviewMatrixStack.Top->m; |
GLfloat plane[4]; |
/* Use this to store calculated eye z values: |
*/ |
input = &store->fogcoord; |
plane[0] = m[2]; |
plane[1] = m[6]; |
plane[2] = m[10]; |
plane[3] = m[14]; |
/* Full eye coords weren't required, just calculate the |
* eye Z values. |
*/ |
_mesa_dotprod_tab[VB->AttribPtr[_TNL_ATTRIB_POS]->size] |
( (GLfloat *) input->data, |
4 * sizeof(GLfloat), |
VB->AttribPtr[_TNL_ATTRIB_POS], plane ); |
input->count = VB->AttribPtr[_TNL_ATTRIB_POS]->count; |
/* make sure coords are really positive |
NOTE should avoid going through array twice */ |
coord = input->start; |
for (i = 0; i < input->count; i++) { |
*coord = FABSF(*coord); |
STRIDE_F(coord, input->stride); |
} |
} |
else { |
/* fog coordinates = eye Z coordinates - need to copy for ABS */ |
input = &store->fogcoord; |
if (VB->EyePtr->size < 2) |
_mesa_vector4f_clean_elem( VB->EyePtr, VB->Count, 2 ); |
input->stride = 4 * sizeof(GLfloat); |
input->count = VB->EyePtr->count; |
coord = VB->EyePtr->start; |
for (i = 0 ; i < VB->EyePtr->count; i++) { |
input->data[i][0] = FABSF(coord[2]); |
STRIDE_F(coord, VB->EyePtr->stride); |
} |
} |
} |
else { |
/* use glFogCoord() coordinates */ |
input = VB->AttribPtr[_TNL_ATTRIB_FOG]; /* source data */ |
/* input->count may be one if glFogCoord was only called once |
* before glBegin. But we need to compute fog for all vertices. |
*/ |
input->count = VB->AttribPtr[_TNL_ATTRIB_POS]->count; |
VB->AttribPtr[_TNL_ATTRIB_FOG] = &store->fogcoord; /* dest data */ |
} |
if (tnl->_DoVertexFog) { |
/* compute blend factors from fog coordinates */ |
compute_fog_blend_factors( ctx, VB->AttribPtr[_TNL_ATTRIB_FOG], input ); |
} |
else { |
/* results = incoming fog coords (compute fog per-fragment later) */ |
VB->AttribPtr[_TNL_ATTRIB_FOG] = input; |
} |
return GL_TRUE; |
} |
/* Called the first time stage->run() is invoked. |
*/ |
static GLboolean |
alloc_fog_data(struct gl_context *ctx, struct tnl_pipeline_stage *stage) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct fog_stage_data *store; |
stage->privatePtr = MALLOC(sizeof(*store)); |
store = FOG_STAGE_DATA(stage); |
if (!store) |
return GL_FALSE; |
_mesa_vector4f_alloc( &store->fogcoord, 0, tnl->vb.Size, 32 ); |
if (!inited) |
init_static_data(); |
return GL_TRUE; |
} |
static void |
free_fog_data(struct tnl_pipeline_stage *stage) |
{ |
struct fog_stage_data *store = FOG_STAGE_DATA(stage); |
if (store) { |
_mesa_vector4f_free( &store->fogcoord ); |
FREE( store ); |
stage->privatePtr = NULL; |
} |
} |
const struct tnl_pipeline_stage _tnl_fog_coordinate_stage = |
{ |
"build fog coordinates", /* name */ |
NULL, /* private_data */ |
alloc_fog_data, /* dtr */ |
free_fog_data, /* dtr */ |
NULL, /* check */ |
run_fog_stage /* run -- initially set to init. */ |
}; |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_light.c |
---|
0,0 → 1,343 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 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 "main/glheader.h" |
#include "main/colormac.h" |
#include "main/light.h" |
#include "main/macros.h" |
#include "main/imports.h" |
#include "main/simple_list.h" |
#include "main/mtypes.h" |
#include "math/m_translate.h" |
#include "t_context.h" |
#include "t_pipeline.h" |
#define LIGHT_TWOSIDE 0x1 |
#define LIGHT_MATERIAL 0x2 |
#define MAX_LIGHT_FUNC 0x4 |
typedef void (*light_func)( struct gl_context *ctx, |
struct vertex_buffer *VB, |
struct tnl_pipeline_stage *stage, |
GLvector4f *input ); |
/** |
* Information for updating current material attributes from vertex color, |
* for GL_COLOR_MATERIAL. |
*/ |
struct material_cursor { |
const GLfloat *ptr; /* points to src vertex color (in VB array) */ |
GLuint stride; /* stride to next vertex color (bytes) */ |
GLfloat *current; /* points to material attribute to update */ |
GLuint size; /* vertex/color size: 1, 2, 3 or 4 */ |
}; |
/** |
* Data private to this pipeline stage. |
*/ |
struct light_stage_data { |
GLvector4f Input; |
GLvector4f LitColor[2]; |
GLvector4f LitSecondary[2]; |
light_func *light_func_tab; |
struct material_cursor mat[MAT_ATTRIB_MAX]; |
GLuint mat_count; |
GLuint mat_bitmask; |
}; |
#define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr)) |
/** |
* In the case of colormaterial, the effected material attributes |
* should already have been bound to point to the incoming color data, |
* prior to running the pipeline. |
* This function copies the vertex's color to the material attributes |
* which are tracking glColor. |
* It's called per-vertex in the lighting loop. |
*/ |
static void |
update_materials(struct gl_context *ctx, struct light_stage_data *store) |
{ |
GLuint i; |
for (i = 0 ; i < store->mat_count ; i++) { |
/* update the material */ |
COPY_CLEAN_4V(store->mat[i].current, store->mat[i].size, store->mat[i].ptr); |
/* increment src vertex color pointer */ |
STRIDE_F(store->mat[i].ptr, store->mat[i].stride); |
} |
/* recompute derived light/material values */ |
_mesa_update_material( ctx, store->mat_bitmask ); |
/* XXX we should only call this if we're tracking/changing the specular |
* exponent. |
*/ |
_mesa_validate_all_lighting_tables( ctx ); |
} |
/** |
* Prepare things prior to running the lighting stage. |
* Return number of material attributes which will track vertex color. |
*/ |
static GLuint |
prepare_materials(struct gl_context *ctx, |
struct vertex_buffer *VB, struct light_stage_data *store) |
{ |
GLuint i; |
store->mat_count = 0; |
store->mat_bitmask = 0; |
/* Examine the ColorMaterialBitmask to determine which materials |
* track vertex color. Override the material attribute's pointer |
* with the color pointer for each one. |
*/ |
if (ctx->Light.ColorMaterialEnabled) { |
const GLuint bitmask = ctx->Light.ColorMaterialBitmask; |
for (i = 0 ; i < MAT_ATTRIB_MAX ; i++) |
if (bitmask & (1<<i)) |
VB->AttribPtr[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] = VB->AttribPtr[_TNL_ATTRIB_COLOR0]; |
} |
/* Now, for each material attribute that's tracking vertex color, save |
* some values (ptr, stride, size, current) that we'll need in |
* update_materials(), above, that'll actually copy the vertex color to |
* the material attribute(s). |
*/ |
for (i = _TNL_FIRST_MAT; i <= _TNL_LAST_MAT; i++) { |
if (VB->AttribPtr[i]->stride) { |
const GLuint j = store->mat_count++; |
const GLuint attr = i - _TNL_ATTRIB_MAT_FRONT_AMBIENT; |
store->mat[j].ptr = VB->AttribPtr[i]->start; |
store->mat[j].stride = VB->AttribPtr[i]->stride; |
store->mat[j].size = VB->AttribPtr[i]->size; |
store->mat[j].current = ctx->Light.Material.Attrib[attr]; |
store->mat_bitmask |= (1<<attr); |
} |
} |
/* FIXME: Is this already done? |
*/ |
_mesa_update_material( ctx, ~0 ); |
_mesa_validate_all_lighting_tables( ctx ); |
return store->mat_count; |
} |
/* Tables for all the shading functions. |
*/ |
static light_func _tnl_light_tab[MAX_LIGHT_FUNC]; |
static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC]; |
static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC]; |
static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC]; |
#define TAG(x) x |
#define IDX (0) |
#include "t_vb_lighttmp.h" |
#define TAG(x) x##_twoside |
#define IDX (LIGHT_TWOSIDE) |
#include "t_vb_lighttmp.h" |
#define TAG(x) x##_material |
#define IDX (LIGHT_MATERIAL) |
#include "t_vb_lighttmp.h" |
#define TAG(x) x##_twoside_material |
#define IDX (LIGHT_TWOSIDE|LIGHT_MATERIAL) |
#include "t_vb_lighttmp.h" |
static void init_lighting_tables( void ) |
{ |
static int done; |
if (!done) { |
init_light_tab(); |
init_light_tab_twoside(); |
init_light_tab_material(); |
init_light_tab_twoside_material(); |
done = 1; |
} |
} |
static GLboolean run_lighting( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
struct light_stage_data *store = LIGHT_STAGE_DATA(stage); |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->AttribPtr[_TNL_ATTRIB_POS]; |
GLuint idx; |
if (!ctx->Light.Enabled || ctx->VertexProgram._Current) |
return GL_TRUE; |
/* Make sure we can talk about position x,y and z: |
*/ |
if (input->size <= 2 && input == VB->AttribPtr[_TNL_ATTRIB_POS]) { |
_math_trans_4f( store->Input.data, |
VB->AttribPtr[_TNL_ATTRIB_POS]->data, |
VB->AttribPtr[_TNL_ATTRIB_POS]->stride, |
GL_FLOAT, |
VB->AttribPtr[_TNL_ATTRIB_POS]->size, |
0, |
VB->Count ); |
if (input->size <= 2) { |
/* Clean z. |
*/ |
_mesa_vector4f_clean_elem(&store->Input, VB->Count, 2); |
} |
if (input->size <= 1) { |
/* Clean y. |
*/ |
_mesa_vector4f_clean_elem(&store->Input, VB->Count, 1); |
} |
input = &store->Input; |
} |
idx = 0; |
if (prepare_materials( ctx, VB, store )) |
idx |= LIGHT_MATERIAL; |
if (ctx->Light.Model.TwoSide) |
idx |= LIGHT_TWOSIDE; |
/* The individual functions know about replaying side-effects |
* vs. full re-execution. |
*/ |
store->light_func_tab[idx]( ctx, VB, stage, input ); |
return GL_TRUE; |
} |
/* Called in place of do_lighting when the light table may have changed. |
*/ |
static void validate_lighting( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
light_func *tab; |
if (!ctx->Light.Enabled || ctx->VertexProgram._Current) |
return; |
if (ctx->Light._NeedVertices) { |
if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) |
tab = _tnl_light_spec_tab; |
else |
tab = _tnl_light_tab; |
} |
else { |
if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev) |
tab = _tnl_light_fast_single_tab; |
else |
tab = _tnl_light_fast_tab; |
} |
LIGHT_STAGE_DATA(stage)->light_func_tab = tab; |
/* This and the above should only be done on _NEW_LIGHT: |
*/ |
TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx ); |
} |
/* Called the first time stage->run is called. In effect, don't |
* allocate data until the first time the stage is run. |
*/ |
static GLboolean init_lighting( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct light_stage_data *store; |
GLuint size = tnl->vb.Size; |
stage->privatePtr = MALLOC(sizeof(*store)); |
store = LIGHT_STAGE_DATA(stage); |
if (!store) |
return GL_FALSE; |
/* Do onetime init. |
*/ |
init_lighting_tables(); |
_mesa_vector4f_alloc( &store->Input, 0, size, 32 ); |
_mesa_vector4f_alloc( &store->LitColor[0], 0, size, 32 ); |
_mesa_vector4f_alloc( &store->LitColor[1], 0, size, 32 ); |
_mesa_vector4f_alloc( &store->LitSecondary[0], 0, size, 32 ); |
_mesa_vector4f_alloc( &store->LitSecondary[1], 0, size, 32 ); |
store->LitColor[0].size = 4; |
store->LitColor[1].size = 4; |
store->LitSecondary[0].size = 3; |
store->LitSecondary[1].size = 3; |
return GL_TRUE; |
} |
static void dtr( struct tnl_pipeline_stage *stage ) |
{ |
struct light_stage_data *store = LIGHT_STAGE_DATA(stage); |
if (store) { |
_mesa_vector4f_free( &store->Input ); |
_mesa_vector4f_free( &store->LitColor[0] ); |
_mesa_vector4f_free( &store->LitColor[1] ); |
_mesa_vector4f_free( &store->LitSecondary[0] ); |
_mesa_vector4f_free( &store->LitSecondary[1] ); |
FREE( store ); |
stage->privatePtr = NULL; |
} |
} |
const struct tnl_pipeline_stage _tnl_lighting_stage = |
{ |
"lighting", /* name */ |
NULL, /* private_data */ |
init_lighting, |
dtr, /* destroy */ |
validate_lighting, |
run_lighting |
}; |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_lighttmp.h |
---|
0,0 → 1,651 |
/* |
* Mesa 3-D graphics library |
* Version: 5.1 |
* |
* Copyright (C) 1999-2003 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. |
* |
* |
* Authors: |
* Brian Paul |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#if IDX & LIGHT_TWOSIDE |
# define NR_SIDES 2 |
#else |
# define NR_SIDES 1 |
#endif |
/* define TRACE to trace lighting code */ |
/* #define TRACE 1 */ |
/* |
* ctx is the current context |
* VB is the vertex buffer |
* stage is the lighting stage-private data |
* input is the vector of eye or object-space vertex coordinates |
*/ |
static void TAG(light_rgba_spec)( struct gl_context *ctx, |
struct vertex_buffer *VB, |
struct tnl_pipeline_stage *stage, |
GLvector4f *input ) |
{ |
struct light_stage_data *store = LIGHT_STAGE_DATA(stage); |
GLfloat (*base)[3] = ctx->Light._BaseColor; |
GLfloat sumA[2]; |
GLuint j; |
const GLuint vstride = input->stride; |
const GLfloat *vertex = (GLfloat *)input->data; |
const GLuint nstride = VB->AttribPtr[_TNL_ATTRIB_NORMAL]->stride; |
const GLfloat *normal = (GLfloat *)VB->AttribPtr[_TNL_ATTRIB_NORMAL]->data; |
GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data; |
GLfloat (*Fspec)[4] = (GLfloat (*)[4]) store->LitSecondary[0].data; |
#if IDX & LIGHT_TWOSIDE |
GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data; |
GLfloat (*Bspec)[4] = (GLfloat (*)[4]) store->LitSecondary[1].data; |
#endif |
const GLuint nr = VB->Count; |
#ifdef TRACE |
fprintf(stderr, "%s\n", __FUNCTION__ ); |
#endif |
VB->AttribPtr[_TNL_ATTRIB_COLOR0] = &store->LitColor[0]; |
VB->AttribPtr[_TNL_ATTRIB_COLOR1] = &store->LitSecondary[0]; |
sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3]; |
#if IDX & LIGHT_TWOSIDE |
VB->BackfaceColorPtr = &store->LitColor[1]; |
VB->BackfaceSecondaryColorPtr = &store->LitSecondary[1]; |
sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3]; |
#endif |
store->LitColor[0].stride = 16; |
store->LitColor[1].stride = 16; |
for (j = 0; j < nr; j++,STRIDE_F(vertex,vstride),STRIDE_F(normal,nstride)) { |
GLfloat sum[2][3], spec[2][3]; |
struct gl_light *light; |
#if IDX & LIGHT_MATERIAL |
update_materials( ctx, store ); |
sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3]; |
#if IDX & LIGHT_TWOSIDE |
sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3]; |
#endif |
#endif |
COPY_3V(sum[0], base[0]); |
ZERO_3V(spec[0]); |
#if IDX & LIGHT_TWOSIDE |
COPY_3V(sum[1], base[1]); |
ZERO_3V(spec[1]); |
#endif |
/* Add contribution from each enabled light source */ |
foreach (light, &ctx->Light.EnabledList) { |
GLfloat n_dot_h; |
GLfloat correction; |
GLint side; |
GLfloat contrib[3]; |
GLfloat attenuation; |
GLfloat VP[3]; /* unit vector from vertex to light */ |
GLfloat n_dot_VP; /* n dot VP */ |
GLfloat *h; |
/* compute VP and attenuation */ |
if (!(light->_Flags & LIGHT_POSITIONAL)) { |
/* directional light */ |
COPY_3V(VP, light->_VP_inf_norm); |
attenuation = light->_VP_inf_spot_attenuation; |
} |
else { |
GLfloat d; /* distance from vertex to light */ |
SUB_3V(VP, light->_Position, vertex); |
d = (GLfloat) LEN_3FV( VP ); |
if (d > 1e-6) { |
GLfloat invd = 1.0F / d; |
SELF_SCALE_SCALAR_3V(VP, invd); |
} |
attenuation = 1.0F / (light->ConstantAttenuation + d * |
(light->LinearAttenuation + d * |
light->QuadraticAttenuation)); |
/* spotlight attenuation */ |
if (light->_Flags & LIGHT_SPOT) { |
GLfloat PV_dot_dir = - DOT3(VP, light->_NormSpotDirection); |
if (PV_dot_dir<light->_CosCutoff) { |
continue; /* this light makes no contribution */ |
} |
else { |
GLdouble x = PV_dot_dir * (EXP_TABLE_SIZE-1); |
GLint k = (GLint) x; |
GLfloat spot = (GLfloat) (light->_SpotExpTable[k][0] |
+ (x-k)*light->_SpotExpTable[k][1]); |
attenuation *= spot; |
} |
} |
} |
if (attenuation < 1e-3) |
continue; /* this light makes no contribution */ |
/* Compute dot product or normal and vector from V to light pos */ |
n_dot_VP = DOT3( normal, VP ); |
/* Which side gets the diffuse & specular terms? */ |
if (n_dot_VP < 0.0F) { |
ACC_SCALE_SCALAR_3V(sum[0], attenuation, light->_MatAmbient[0]); |
#if IDX & LIGHT_TWOSIDE |
side = 1; |
correction = -1; |
n_dot_VP = -n_dot_VP; |
#else |
continue; |
#endif |
} |
else { |
#if IDX & LIGHT_TWOSIDE |
ACC_SCALE_SCALAR_3V( sum[1], attenuation, light->_MatAmbient[1]); |
#endif |
side = 0; |
correction = 1; |
} |
/* diffuse term */ |
COPY_3V(contrib, light->_MatAmbient[side]); |
ACC_SCALE_SCALAR_3V(contrib, n_dot_VP, light->_MatDiffuse[side]); |
ACC_SCALE_SCALAR_3V(sum[side], attenuation, contrib ); |
/* specular term - cannibalize VP... */ |
if (ctx->Light.Model.LocalViewer) { |
GLfloat v[3]; |
COPY_3V(v, vertex); |
NORMALIZE_3FV(v); |
SUB_3V(VP, VP, v); /* h = VP + VPe */ |
h = VP; |
NORMALIZE_3FV(h); |
} |
else if (light->_Flags & LIGHT_POSITIONAL) { |
h = VP; |
ACC_3V(h, ctx->_EyeZDir); |
NORMALIZE_3FV(h); |
} |
else { |
h = light->_h_inf_norm; |
} |
n_dot_h = correction * DOT3(normal, h); |
if (n_dot_h > 0.0F) { |
GLfloat spec_coef; |
struct gl_shine_tab *tab = ctx->_ShineTable[side]; |
GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef ); |
if (spec_coef > 1.0e-10) { |
spec_coef *= attenuation; |
ACC_SCALE_SCALAR_3V( spec[side], spec_coef, |
light->_MatSpecular[side]); |
} |
} |
} /*loop over lights*/ |
COPY_3V( Fcolor[j], sum[0] ); |
COPY_3V( Fspec[j], spec[0] ); |
Fcolor[j][3] = sumA[0]; |
#if IDX & LIGHT_TWOSIDE |
COPY_3V( Bcolor[j], sum[1] ); |
COPY_3V( Bspec[j], spec[1] ); |
Bcolor[j][3] = sumA[1]; |
#endif |
} |
} |
static void TAG(light_rgba)( struct gl_context *ctx, |
struct vertex_buffer *VB, |
struct tnl_pipeline_stage *stage, |
GLvector4f *input ) |
{ |
struct light_stage_data *store = LIGHT_STAGE_DATA(stage); |
GLuint j; |
GLfloat (*base)[3] = ctx->Light._BaseColor; |
GLfloat sumA[2]; |
const GLuint vstride = input->stride; |
const GLfloat *vertex = (GLfloat *) input->data; |
const GLuint nstride = VB->AttribPtr[_TNL_ATTRIB_NORMAL]->stride; |
const GLfloat *normal = (GLfloat *)VB->AttribPtr[_TNL_ATTRIB_NORMAL]->data; |
GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data; |
#if IDX & LIGHT_TWOSIDE |
GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data; |
#endif |
const GLuint nr = VB->Count; |
#ifdef TRACE |
fprintf(stderr, "%s\n", __FUNCTION__ ); |
#endif |
VB->AttribPtr[_TNL_ATTRIB_COLOR0] = &store->LitColor[0]; |
sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3]; |
#if IDX & LIGHT_TWOSIDE |
VB->BackfaceColorPtr = &store->LitColor[1]; |
sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3]; |
#endif |
store->LitColor[0].stride = 16; |
store->LitColor[1].stride = 16; |
for (j = 0; j < nr; j++,STRIDE_F(vertex,vstride),STRIDE_F(normal,nstride)) { |
GLfloat sum[2][3]; |
struct gl_light *light; |
#if IDX & LIGHT_MATERIAL |
update_materials( ctx, store ); |
sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3]; |
#if IDX & LIGHT_TWOSIDE |
sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3]; |
#endif |
#endif |
COPY_3V(sum[0], base[0]); |
#if IDX & LIGHT_TWOSIDE |
COPY_3V(sum[1], base[1]); |
#endif |
/* Add contribution from each enabled light source */ |
foreach (light, &ctx->Light.EnabledList) { |
GLfloat n_dot_h; |
GLfloat correction; |
GLint side; |
GLfloat contrib[3]; |
GLfloat attenuation = 1.0; |
GLfloat VP[3]; /* unit vector from vertex to light */ |
GLfloat n_dot_VP; /* n dot VP */ |
GLfloat *h; |
/* compute VP and attenuation */ |
if (!(light->_Flags & LIGHT_POSITIONAL)) { |
/* directional light */ |
COPY_3V(VP, light->_VP_inf_norm); |
attenuation = light->_VP_inf_spot_attenuation; |
} |
else { |
GLfloat d; /* distance from vertex to light */ |
SUB_3V(VP, light->_Position, vertex); |
d = (GLfloat) LEN_3FV( VP ); |
if ( d > 1e-6) { |
GLfloat invd = 1.0F / d; |
SELF_SCALE_SCALAR_3V(VP, invd); |
} |
attenuation = 1.0F / (light->ConstantAttenuation + d * |
(light->LinearAttenuation + d * |
light->QuadraticAttenuation)); |
/* spotlight attenuation */ |
if (light->_Flags & LIGHT_SPOT) { |
GLfloat PV_dot_dir = - DOT3(VP, light->_NormSpotDirection); |
if (PV_dot_dir<light->_CosCutoff) { |
continue; /* this light makes no contribution */ |
} |
else { |
GLdouble x = PV_dot_dir * (EXP_TABLE_SIZE-1); |
GLint k = (GLint) x; |
GLfloat spot = (GLfloat) (light->_SpotExpTable[k][0] |
+ (x-k)*light->_SpotExpTable[k][1]); |
attenuation *= spot; |
} |
} |
} |
if (attenuation < 1e-3) |
continue; /* this light makes no contribution */ |
/* Compute dot product or normal and vector from V to light pos */ |
n_dot_VP = DOT3( normal, VP ); |
/* which side are we lighting? */ |
if (n_dot_VP < 0.0F) { |
ACC_SCALE_SCALAR_3V(sum[0], attenuation, light->_MatAmbient[0]); |
#if IDX & LIGHT_TWOSIDE |
side = 1; |
correction = -1; |
n_dot_VP = -n_dot_VP; |
#else |
continue; |
#endif |
} |
else { |
#if IDX & LIGHT_TWOSIDE |
ACC_SCALE_SCALAR_3V( sum[1], attenuation, light->_MatAmbient[1]); |
#endif |
side = 0; |
correction = 1; |
} |
COPY_3V(contrib, light->_MatAmbient[side]); |
/* diffuse term */ |
ACC_SCALE_SCALAR_3V(contrib, n_dot_VP, light->_MatDiffuse[side]); |
/* specular term - cannibalize VP... */ |
{ |
if (ctx->Light.Model.LocalViewer) { |
GLfloat v[3]; |
COPY_3V(v, vertex); |
NORMALIZE_3FV(v); |
SUB_3V(VP, VP, v); /* h = VP + VPe */ |
h = VP; |
NORMALIZE_3FV(h); |
} |
else if (light->_Flags & LIGHT_POSITIONAL) { |
h = VP; |
ACC_3V(h, ctx->_EyeZDir); |
NORMALIZE_3FV(h); |
} |
else { |
h = light->_h_inf_norm; |
} |
n_dot_h = correction * DOT3(normal, h); |
if (n_dot_h > 0.0F) |
{ |
GLfloat spec_coef; |
struct gl_shine_tab *tab = ctx->_ShineTable[side]; |
GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef ); |
ACC_SCALE_SCALAR_3V( contrib, spec_coef, |
light->_MatSpecular[side]); |
} |
} |
ACC_SCALE_SCALAR_3V( sum[side], attenuation, contrib ); |
} |
COPY_3V( Fcolor[j], sum[0] ); |
Fcolor[j][3] = sumA[0]; |
#if IDX & LIGHT_TWOSIDE |
COPY_3V( Bcolor[j], sum[1] ); |
Bcolor[j][3] = sumA[1]; |
#endif |
} |
} |
/* As below, but with just a single light. |
*/ |
static void TAG(light_fast_rgba_single)( struct gl_context *ctx, |
struct vertex_buffer *VB, |
struct tnl_pipeline_stage *stage, |
GLvector4f *input ) |
{ |
struct light_stage_data *store = LIGHT_STAGE_DATA(stage); |
const GLuint nstride = VB->AttribPtr[_TNL_ATTRIB_NORMAL]->stride; |
const GLfloat *normal = (GLfloat *)VB->AttribPtr[_TNL_ATTRIB_NORMAL]->data; |
GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data; |
#if IDX & LIGHT_TWOSIDE |
GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data; |
#endif |
const struct gl_light *light = ctx->Light.EnabledList.next; |
GLuint j = 0; |
GLfloat base[2][4]; |
#if IDX & LIGHT_MATERIAL |
const GLuint nr = VB->Count; |
#else |
const GLuint nr = VB->AttribPtr[_TNL_ATTRIB_NORMAL]->count; |
#endif |
#ifdef TRACE |
fprintf(stderr, "%s\n", __FUNCTION__ ); |
#endif |
(void) input; /* doesn't refer to Eye or Obj */ |
VB->AttribPtr[_TNL_ATTRIB_COLOR0] = &store->LitColor[0]; |
#if IDX & LIGHT_TWOSIDE |
VB->BackfaceColorPtr = &store->LitColor[1]; |
#endif |
if (nr > 1) { |
store->LitColor[0].stride = 16; |
store->LitColor[1].stride = 16; |
} |
else { |
store->LitColor[0].stride = 0; |
store->LitColor[1].stride = 0; |
} |
for (j = 0; j < nr; j++, STRIDE_F(normal,nstride)) { |
GLfloat n_dot_VP; |
#if IDX & LIGHT_MATERIAL |
update_materials( ctx, store ); |
#endif |
/* No attenuation, so incoporate _MatAmbient into base color. |
*/ |
#if !(IDX & LIGHT_MATERIAL) |
if ( j == 0 ) |
#endif |
{ |
COPY_3V(base[0], light->_MatAmbient[0]); |
ACC_3V(base[0], ctx->Light._BaseColor[0] ); |
base[0][3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3]; |
#if IDX & LIGHT_TWOSIDE |
COPY_3V(base[1], light->_MatAmbient[1]); |
ACC_3V(base[1], ctx->Light._BaseColor[1]); |
base[1][3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3]; |
#endif |
} |
n_dot_VP = DOT3(normal, light->_VP_inf_norm); |
if (n_dot_VP < 0.0F) { |
#if IDX & LIGHT_TWOSIDE |
GLfloat n_dot_h = -DOT3(normal, light->_h_inf_norm); |
GLfloat sum[3]; |
COPY_3V(sum, base[1]); |
ACC_SCALE_SCALAR_3V(sum, -n_dot_VP, light->_MatDiffuse[1]); |
if (n_dot_h > 0.0F) { |
GLfloat spec; |
GET_SHINE_TAB_ENTRY( ctx->_ShineTable[1], n_dot_h, spec ); |
ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[1]); |
} |
COPY_3V(Bcolor[j], sum ); |
Bcolor[j][3] = base[1][3]; |
#endif |
COPY_4FV(Fcolor[j], base[0]); |
} |
else { |
GLfloat n_dot_h = DOT3(normal, light->_h_inf_norm); |
GLfloat sum[3]; |
COPY_3V(sum, base[0]); |
ACC_SCALE_SCALAR_3V(sum, n_dot_VP, light->_MatDiffuse[0]); |
if (n_dot_h > 0.0F) { |
GLfloat spec; |
GET_SHINE_TAB_ENTRY( ctx->_ShineTable[0], n_dot_h, spec ); |
ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[0]); |
} |
COPY_3V(Fcolor[j], sum ); |
Fcolor[j][3] = base[0][3]; |
#if IDX & LIGHT_TWOSIDE |
COPY_4FV(Bcolor[j], base[1]); |
#endif |
} |
} |
} |
/* Light infinite lights |
*/ |
static void TAG(light_fast_rgba)( struct gl_context *ctx, |
struct vertex_buffer *VB, |
struct tnl_pipeline_stage *stage, |
GLvector4f *input ) |
{ |
struct light_stage_data *store = LIGHT_STAGE_DATA(stage); |
GLfloat sumA[2]; |
const GLuint nstride = VB->AttribPtr[_TNL_ATTRIB_NORMAL]->stride; |
const GLfloat *normal = (GLfloat *)VB->AttribPtr[_TNL_ATTRIB_NORMAL]->data; |
GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data; |
#if IDX & LIGHT_TWOSIDE |
GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data; |
#endif |
GLuint j = 0; |
#if IDX & LIGHT_MATERIAL |
const GLuint nr = VB->Count; |
#else |
const GLuint nr = VB->AttribPtr[_TNL_ATTRIB_NORMAL]->count; |
#endif |
const struct gl_light *light; |
#ifdef TRACE |
fprintf(stderr, "%s %d\n", __FUNCTION__, nr ); |
#endif |
(void) input; |
sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3]; |
sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3]; |
VB->AttribPtr[_TNL_ATTRIB_COLOR0] = &store->LitColor[0]; |
#if IDX & LIGHT_TWOSIDE |
VB->BackfaceColorPtr = &store->LitColor[1]; |
#endif |
if (nr > 1) { |
store->LitColor[0].stride = 16; |
store->LitColor[1].stride = 16; |
} |
else { |
store->LitColor[0].stride = 0; |
store->LitColor[1].stride = 0; |
} |
for (j = 0; j < nr; j++, STRIDE_F(normal,nstride)) { |
GLfloat sum[2][3]; |
#if IDX & LIGHT_MATERIAL |
update_materials( ctx, store ); |
sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3]; |
#if IDX & LIGHT_TWOSIDE |
sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3]; |
#endif |
#endif |
COPY_3V(sum[0], ctx->Light._BaseColor[0]); |
#if IDX & LIGHT_TWOSIDE |
COPY_3V(sum[1], ctx->Light._BaseColor[1]); |
#endif |
foreach (light, &ctx->Light.EnabledList) { |
GLfloat n_dot_h, n_dot_VP, spec; |
ACC_3V(sum[0], light->_MatAmbient[0]); |
#if IDX & LIGHT_TWOSIDE |
ACC_3V(sum[1], light->_MatAmbient[1]); |
#endif |
n_dot_VP = DOT3(normal, light->_VP_inf_norm); |
if (n_dot_VP > 0.0F) { |
ACC_SCALE_SCALAR_3V(sum[0], n_dot_VP, light->_MatDiffuse[0]); |
n_dot_h = DOT3(normal, light->_h_inf_norm); |
if (n_dot_h > 0.0F) { |
struct gl_shine_tab *tab = ctx->_ShineTable[0]; |
GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec ); |
ACC_SCALE_SCALAR_3V( sum[0], spec, light->_MatSpecular[0]); |
} |
} |
#if IDX & LIGHT_TWOSIDE |
else { |
ACC_SCALE_SCALAR_3V(sum[1], -n_dot_VP, light->_MatDiffuse[1]); |
n_dot_h = -DOT3(normal, light->_h_inf_norm); |
if (n_dot_h > 0.0F) { |
struct gl_shine_tab *tab = ctx->_ShineTable[1]; |
GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec ); |
ACC_SCALE_SCALAR_3V( sum[1], spec, light->_MatSpecular[1]); |
} |
} |
#endif |
} |
COPY_3V( Fcolor[j], sum[0] ); |
Fcolor[j][3] = sumA[0]; |
#if IDX & LIGHT_TWOSIDE |
COPY_3V( Bcolor[j], sum[1] ); |
Bcolor[j][3] = sumA[1]; |
#endif |
} |
} |
static void TAG(init_light_tab)( void ) |
{ |
_tnl_light_tab[IDX] = TAG(light_rgba); |
_tnl_light_fast_tab[IDX] = TAG(light_fast_rgba); |
_tnl_light_fast_single_tab[IDX] = TAG(light_fast_rgba_single); |
_tnl_light_spec_tab[IDX] = TAG(light_rgba_spec); |
} |
#undef TAG |
#undef IDX |
#undef NR_SIDES |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_normals.c |
---|
0,0 → 1,187 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/colormac.h" |
#include "main/macros.h" |
#include "main/imports.h" |
#include "main/mtypes.h" |
#include "math/m_xform.h" |
#include "t_context.h" |
#include "t_pipeline.h" |
struct normal_stage_data { |
normal_func NormalTransform; |
GLvector4f normal; |
}; |
#define NORMAL_STAGE_DATA(stage) ((struct normal_stage_data *)stage->privatePtr) |
static GLboolean |
run_normal_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage) |
{ |
struct normal_stage_data *store = NORMAL_STAGE_DATA(stage); |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
const GLfloat *lengths; |
if (!store->NormalTransform) |
return GL_TRUE; |
/* We can only use the display list's saved normal lengths if we've |
* got a transformation matrix with uniform scaling. |
*/ |
if (_math_matrix_is_general_scale(ctx->ModelviewMatrixStack.Top)) |
lengths = NULL; |
else |
lengths = VB->NormalLengthPtr; |
store->NormalTransform( ctx->ModelviewMatrixStack.Top, |
ctx->_ModelViewInvScale, |
VB->AttribPtr[_TNL_ATTRIB_NORMAL], /* input normals */ |
lengths, |
&store->normal ); /* resulting normals */ |
if (VB->AttribPtr[_TNL_ATTRIB_NORMAL]->count > 1) { |
store->normal.stride = 4 * sizeof(GLfloat); |
} |
else { |
store->normal.stride = 0; |
} |
VB->AttribPtr[_TNL_ATTRIB_NORMAL] = &store->normal; |
VB->NormalLengthPtr = NULL; /* no longer valid */ |
return GL_TRUE; |
} |
/** |
* Examine current GL state and set the store->NormalTransform pointer |
* to point to the appropriate normal transformation routine. |
*/ |
static void |
validate_normal_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage) |
{ |
struct normal_stage_data *store = NORMAL_STAGE_DATA(stage); |
if (ctx->VertexProgram._Current || |
(!ctx->Light.Enabled && |
!(ctx->Texture._GenFlags & TEXGEN_NEED_NORMALS))) { |
store->NormalTransform = NULL; |
return; |
} |
if (ctx->_NeedEyeCoords) { |
/* Eye coordinates are needed, for whatever reasons. |
* Do lighting in eye coordinates, as the GL spec says. |
*/ |
GLuint transform = NORM_TRANSFORM_NO_ROT; |
if (_math_matrix_has_rotation(ctx->ModelviewMatrixStack.Top)) { |
/* need to do full (3x3) matrix transform */ |
transform = NORM_TRANSFORM; |
} |
if (ctx->Transform.Normalize) { |
store->NormalTransform = _mesa_normal_tab[transform | NORM_NORMALIZE]; |
} |
else if (ctx->Transform.RescaleNormals && |
ctx->_ModelViewInvScale != 1.0) { |
store->NormalTransform = _mesa_normal_tab[transform | NORM_RESCALE]; |
} |
else { |
store->NormalTransform = _mesa_normal_tab[transform]; |
} |
} |
else { |
/* We don't need eye coordinates. |
* Do lighting in object coordinates. Thus, we don't need to fully |
* transform normal vectors (just leave them in object coordinates) |
* but we still need to do normalization/rescaling if enabled. |
*/ |
if (ctx->Transform.Normalize) { |
store->NormalTransform = _mesa_normal_tab[NORM_NORMALIZE]; |
} |
else if (!ctx->Transform.RescaleNormals && |
ctx->_ModelViewInvScale != 1.0) { |
store->NormalTransform = _mesa_normal_tab[NORM_RESCALE]; |
} |
else { |
store->NormalTransform = NULL; |
} |
} |
} |
/** |
* Allocate stage's private data (storage for transformed normals). |
*/ |
static GLboolean |
alloc_normal_data(struct gl_context *ctx, struct tnl_pipeline_stage *stage) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct normal_stage_data *store; |
stage->privatePtr = malloc(sizeof(*store)); |
store = NORMAL_STAGE_DATA(stage); |
if (!store) |
return GL_FALSE; |
_mesa_vector4f_alloc( &store->normal, 0, tnl->vb.Size, 32 ); |
return GL_TRUE; |
} |
/** |
* Free stage's private data. |
*/ |
static void |
free_normal_data(struct tnl_pipeline_stage *stage) |
{ |
struct normal_stage_data *store = NORMAL_STAGE_DATA(stage); |
if (store) { |
_mesa_vector4f_free( &store->normal ); |
free( store ); |
stage->privatePtr = NULL; |
} |
} |
const struct tnl_pipeline_stage _tnl_normal_transform_stage = |
{ |
"normal transform", /* name */ |
NULL, /* privatePtr */ |
alloc_normal_data, /* create */ |
free_normal_data, /* destroy */ |
validate_normal_stage, /* validate */ |
run_normal_stage /* run */ |
}; |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_points.c |
---|
0,0 → 1,114 |
/* |
* Mesa 3-D graphics library |
* Version: 7.0 |
* |
* Copyright (C) 1999-2007 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. |
* |
* Authors: |
* Brian Paul |
*/ |
#include "main/glheader.h" |
#include "main/mtypes.h" |
#include "main/dd.h" |
#include "main/imports.h" |
#include "t_context.h" |
#include "t_pipeline.h" |
struct point_stage_data { |
GLvector4f PointSize; |
}; |
#define POINT_STAGE_DATA(stage) ((struct point_stage_data *)stage->privatePtr) |
/** |
* Compute point size for each vertex from the vertex eye-space Z |
* coordinate and the point size attenuation factors. |
* Only done when point size attenuation is enabled and vertex program is |
* disabled. |
*/ |
static GLboolean |
run_point_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage) |
{ |
if (ctx->Point._Attenuated && !ctx->VertexProgram._Current) { |
struct point_stage_data *store = POINT_STAGE_DATA(stage); |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
const GLfloat *eyeCoord = (GLfloat *) VB->EyePtr->data + 2; |
const GLint eyeCoordStride = VB->EyePtr->stride / sizeof(GLfloat); |
const GLfloat p0 = ctx->Point.Params[0]; |
const GLfloat p1 = ctx->Point.Params[1]; |
const GLfloat p2 = ctx->Point.Params[2]; |
const GLfloat pointSize = ctx->Point.Size; |
GLfloat (*size)[4] = store->PointSize.data; |
GLuint i; |
for (i = 0; i < VB->Count; i++) { |
const GLfloat dist = FABSF(*eyeCoord); |
const GLfloat q = p0 + dist * (p1 + dist * p2); |
const GLfloat atten = (q != 0.0F) ? SQRTF(1.0F / q) : 1.0F; |
size[i][0] = pointSize * atten; /* clamping done in rasterization */ |
eyeCoord += eyeCoordStride; |
} |
VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->PointSize; |
} |
return GL_TRUE; |
} |
static GLboolean |
alloc_point_data(struct gl_context *ctx, struct tnl_pipeline_stage *stage) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
struct point_stage_data *store; |
stage->privatePtr = malloc(sizeof(*store)); |
store = POINT_STAGE_DATA(stage); |
if (!store) |
return GL_FALSE; |
_mesa_vector4f_alloc( &store->PointSize, 0, VB->Size, 32 ); |
return GL_TRUE; |
} |
static void |
free_point_data(struct tnl_pipeline_stage *stage) |
{ |
struct point_stage_data *store = POINT_STAGE_DATA(stage); |
if (store) { |
_mesa_vector4f_free( &store->PointSize ); |
free( store ); |
stage->privatePtr = NULL; |
} |
} |
const struct tnl_pipeline_stage _tnl_point_attenuation_stage = |
{ |
"point size attenuation", /* name */ |
NULL, /* stage private data */ |
alloc_point_data, /* alloc data */ |
free_point_data, /* destructor */ |
NULL, |
run_point_stage /* run */ |
}; |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_program.c |
---|
0,0 → 1,571 |
/* |
* Mesa 3-D graphics library |
* Version: 7.6 |
* |
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved. |
* Copyright (C) 2009 VMware, Inc. 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. |
*/ |
/** |
* \file tnl/t_vb_program.c |
* \brief Pipeline stage for executing vertex programs. |
* \author Brian Paul, Keith Whitwell |
*/ |
#include "main/glheader.h" |
#include "main/colormac.h" |
#include "main/macros.h" |
#include "main/imports.h" |
#include "math/m_xform.h" |
#include "program/prog_instruction.h" |
#include "program/prog_statevars.h" |
#include "program/prog_execute.h" |
#include "swrast/s_context.h" |
#include "tnl/tnl.h" |
#include "tnl/t_context.h" |
#include "tnl/t_pipeline.h" |
#ifdef NAN_CHECK |
/** Check for NaNs and very large values */ |
static INLINE void |
check_float(float x) |
{ |
assert(!IS_INF_OR_NAN(x)); |
assert(1.0e-15 <= x && x <= 1.0e15); |
} |
#endif |
/*! |
* Private storage for the vertex program pipeline stage. |
*/ |
struct vp_stage_data { |
/** The results of running the vertex program go into these arrays. */ |
GLvector4f results[VERT_RESULT_MAX]; |
GLvector4f ndcCoords; /**< normalized device coords */ |
GLubyte *clipmask; /**< clip flags */ |
GLubyte ormask, andmask; /**< for clipping */ |
struct gl_program_machine machine; |
}; |
#define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr)) |
static void |
userclip( struct gl_context *ctx, |
GLvector4f *clip, |
GLubyte *clipmask, |
GLubyte *clipormask, |
GLubyte *clipandmask ) |
{ |
GLuint p; |
for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { |
if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { |
GLuint nr, i; |
const GLfloat a = ctx->Transform._ClipUserPlane[p][0]; |
const GLfloat b = ctx->Transform._ClipUserPlane[p][1]; |
const GLfloat c = ctx->Transform._ClipUserPlane[p][2]; |
const GLfloat d = ctx->Transform._ClipUserPlane[p][3]; |
GLfloat *coord = (GLfloat *)clip->data; |
GLuint stride = clip->stride; |
GLuint count = clip->count; |
for (nr = 0, i = 0 ; i < count ; i++) { |
GLfloat dp = (coord[0] * a + |
coord[1] * b + |
coord[2] * c + |
coord[3] * d); |
if (dp < 0) { |
nr++; |
clipmask[i] |= CLIP_USER_BIT; |
} |
STRIDE_F(coord, stride); |
} |
if (nr > 0) { |
*clipormask |= CLIP_USER_BIT; |
if (nr == count) { |
*clipandmask |= CLIP_USER_BIT; |
return; |
} |
} |
} |
} |
} |
static GLboolean |
do_ndc_cliptest(struct gl_context *ctx, struct vp_stage_data *store) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
/* Cliptest and perspective divide. Clip functions must clear |
* the clipmask. |
*/ |
store->ormask = 0; |
store->andmask = CLIP_FRUSTUM_BITS; |
tnl_clip_prepare(ctx); |
if (tnl->NeedNdcCoords) { |
VB->NdcPtr = |
_mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr, |
&store->ndcCoords, |
store->clipmask, |
&store->ormask, |
&store->andmask, |
!ctx->Transform.DepthClamp ); |
} |
else { |
VB->NdcPtr = NULL; |
_mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr, |
NULL, |
store->clipmask, |
&store->ormask, |
&store->andmask, |
!ctx->Transform.DepthClamp ); |
} |
if (store->andmask) { |
/* All vertices are outside the frustum */ |
return GL_FALSE; |
} |
/* Test userclip planes. This contributes to VB->ClipMask. |
*/ |
/** XXX NEW_SLANG _Enabled ??? */ |
if (ctx->Transform.ClipPlanesEnabled && (!ctx->VertexProgram._Enabled || |
ctx->VertexProgram.Current->IsPositionInvariant)) { |
userclip( ctx, |
VB->ClipPtr, |
store->clipmask, |
&store->ormask, |
&store->andmask ); |
if (store->andmask) { |
return GL_FALSE; |
} |
} |
VB->ClipAndMask = store->andmask; |
VB->ClipOrMask = store->ormask; |
VB->ClipMask = store->clipmask; |
return GL_TRUE; |
} |
/** |
* XXX the texture sampling code in this module is a bit of a hack. |
* The texture sampling code is in swrast, though it doesn't have any |
* real dependencies on the rest of swrast. It should probably be |
* moved into main/ someday. |
*/ |
static void |
vp_fetch_texel(struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda, |
GLuint unit, GLfloat color[4]) |
{ |
SWcontext *swrast = SWRAST_CONTEXT(ctx); |
/* XXX use a float-valued TextureSample routine here!!! */ |
swrast->TextureSample[unit](ctx, ctx->Texture.Unit[unit]._Current, |
1, (const GLfloat (*)[4]) texcoord, |
&lambda, (GLfloat (*)[4]) color); |
} |
/** |
* Called via ctx->Driver.ProgramStringNotify() after a new vertex program |
* string has been parsed. |
*/ |
GLboolean |
_tnl_program_string(struct gl_context *ctx, GLenum target, struct gl_program *program) |
{ |
/* No-op. |
* If we had derived anything from the program that was private to this |
* stage we'd recompute/validate it here. |
*/ |
return GL_TRUE; |
} |
/** |
* Initialize virtual machine state prior to executing vertex program. |
*/ |
static void |
init_machine(struct gl_context *ctx, struct gl_program_machine *machine) |
{ |
/* Input registers get initialized from the current vertex attribs */ |
memcpy(machine->VertAttribs, ctx->Current.Attrib, |
MAX_VERTEX_GENERIC_ATTRIBS * 4 * sizeof(GLfloat)); |
if (ctx->VertexProgram._Current->IsNVProgram) { |
GLuint i; |
/* Output/result regs are initialized to [0,0,0,1] */ |
for (i = 0; i < MAX_NV_VERTEX_PROGRAM_OUTPUTS; i++) { |
ASSIGN_4V(machine->Outputs[i], 0.0F, 0.0F, 0.0F, 1.0F); |
} |
/* Temp regs are initialized to [0,0,0,0] */ |
for (i = 0; i < MAX_NV_VERTEX_PROGRAM_TEMPS; i++) { |
ASSIGN_4V(machine->Temporaries[i], 0.0F, 0.0F, 0.0F, 0.0F); |
} |
for (i = 0; i < MAX_VERTEX_PROGRAM_ADDRESS_REGS; i++) { |
ASSIGN_4V(machine->AddressReg[i], 0, 0, 0, 0); |
} |
} |
machine->NumDeriv = 0; |
/* init condition codes */ |
machine->CondCodes[0] = COND_EQ; |
machine->CondCodes[1] = COND_EQ; |
machine->CondCodes[2] = COND_EQ; |
machine->CondCodes[3] = COND_EQ; |
/* init call stack */ |
machine->StackDepth = 0; |
machine->FetchTexelLod = vp_fetch_texel; |
machine->FetchTexelDeriv = NULL; /* not used by vertex programs */ |
machine->Samplers = ctx->VertexProgram._Current->Base.SamplerUnits; |
} |
/** |
* Map the texture images which the vertex program will access (if any). |
*/ |
static void |
map_textures(struct gl_context *ctx, const struct gl_vertex_program *vp) |
{ |
GLuint u; |
if (!ctx->Driver.MapTexture) |
return; |
for (u = 0; u < ctx->Const.MaxVertexTextureImageUnits; u++) { |
if (vp->Base.TexturesUsed[u]) { |
/* Note: _Current *should* correspond to the target indicated |
* in TexturesUsed[u]. |
*/ |
ctx->Driver.MapTexture(ctx, ctx->Texture.Unit[u]._Current); |
} |
} |
} |
/** |
* Unmap the texture images which were used by the vertex program (if any). |
*/ |
static void |
unmap_textures(struct gl_context *ctx, const struct gl_vertex_program *vp) |
{ |
GLuint u; |
if (!ctx->Driver.MapTexture) |
return; |
for (u = 0; u < ctx->Const.MaxVertexTextureImageUnits; u++) { |
if (vp->Base.TexturesUsed[u]) { |
/* Note: _Current *should* correspond to the target indicated |
* in TexturesUsed[u]. |
*/ |
ctx->Driver.UnmapTexture(ctx, ctx->Texture.Unit[u]._Current); |
} |
} |
} |
/** |
* This function executes vertex programs |
*/ |
static GLboolean |
run_vp( struct gl_context *ctx, struct tnl_pipeline_stage *stage ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vp_stage_data *store = VP_STAGE_DATA(stage); |
struct vertex_buffer *VB = &tnl->vb; |
struct gl_vertex_program *program = ctx->VertexProgram._Current; |
struct gl_program_machine *machine = &store->machine; |
GLuint outputs[VERT_RESULT_MAX], numOutputs; |
GLuint i, j; |
if (!program) |
return GL_TRUE; |
if (program->IsNVProgram) { |
_mesa_load_tracked_matrices(ctx); |
} |
else { |
/* ARB program or vertex shader */ |
_mesa_load_state_parameters(ctx, program->Base.Parameters); |
} |
/* make list of outputs to save some time below */ |
numOutputs = 0; |
for (i = 0; i < VERT_RESULT_MAX; i++) { |
if (program->Base.OutputsWritten & BITFIELD64_BIT(i)) { |
outputs[numOutputs++] = i; |
} |
} |
map_textures(ctx, program); |
for (i = 0; i < VB->Count; i++) { |
GLuint attr; |
init_machine(ctx, machine); |
#if 0 |
printf("Input %d: %f, %f, %f, %f\n", i, |
VB->AttribPtr[0]->data[i][0], |
VB->AttribPtr[0]->data[i][1], |
VB->AttribPtr[0]->data[i][2], |
VB->AttribPtr[0]->data[i][3]); |
printf(" color: %f, %f, %f, %f\n", |
VB->AttribPtr[3]->data[i][0], |
VB->AttribPtr[3]->data[i][1], |
VB->AttribPtr[3]->data[i][2], |
VB->AttribPtr[3]->data[i][3]); |
printf(" normal: %f, %f, %f, %f\n", |
VB->AttribPtr[2]->data[i][0], |
VB->AttribPtr[2]->data[i][1], |
VB->AttribPtr[2]->data[i][2], |
VB->AttribPtr[2]->data[i][3]); |
#endif |
/* the vertex array case */ |
for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { |
if (program->Base.InputsRead & (1 << attr)) { |
const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data; |
const GLuint size = VB->AttribPtr[attr]->size; |
const GLuint stride = VB->AttribPtr[attr]->stride; |
const GLfloat *data = (GLfloat *) (ptr + stride * i); |
#ifdef NAN_CHECK |
check_float(data[0]); |
check_float(data[1]); |
check_float(data[2]); |
check_float(data[3]); |
#endif |
COPY_CLEAN_4V(machine->VertAttribs[attr], size, data); |
} |
} |
/* execute the program */ |
_mesa_execute_program(ctx, &program->Base, machine); |
/* copy the output registers into the VB->attribs arrays */ |
for (j = 0; j < numOutputs; j++) { |
const GLuint attr = outputs[j]; |
#ifdef NAN_CHECK |
check_float(machine->Outputs[attr][0]); |
check_float(machine->Outputs[attr][1]); |
check_float(machine->Outputs[attr][2]); |
check_float(machine->Outputs[attr][3]); |
#endif |
COPY_4V(store->results[attr].data[i], machine->Outputs[attr]); |
} |
/* FOGC is a special case. Fragment shader expects (f,0,0,1) */ |
if (program->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_FOGC)) { |
store->results[VERT_RESULT_FOGC].data[i][1] = 0.0; |
store->results[VERT_RESULT_FOGC].data[i][2] = 0.0; |
store->results[VERT_RESULT_FOGC].data[i][3] = 1.0; |
} |
#ifdef NAN_CHECK |
ASSERT(machine->Outputs[0][3] != 0.0F); |
#endif |
#if 0 |
printf("HPOS: %f %f %f %f\n", |
machine->Outputs[0][0], |
machine->Outputs[0][1], |
machine->Outputs[0][2], |
machine->Outputs[0][3]); |
#endif |
} |
unmap_textures(ctx, program); |
/* Fixup fog and point size results if needed */ |
if (program->IsNVProgram) { |
if (ctx->Fog.Enabled && |
(program->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_FOGC)) == 0) { |
for (i = 0; i < VB->Count; i++) { |
store->results[VERT_RESULT_FOGC].data[i][0] = 1.0; |
} |
} |
if (ctx->VertexProgram.PointSizeEnabled && |
(program->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_PSIZ)) == 0) { |
for (i = 0; i < VB->Count; i++) { |
store->results[VERT_RESULT_PSIZ].data[i][0] = ctx->Point.Size; |
} |
} |
} |
if (program->IsPositionInvariant) { |
/* We need the exact same transform as in the fixed function path here |
* to guarantee invariance, depending on compiler optimization flags |
* results could be different otherwise. |
*/ |
VB->ClipPtr = TransformRaw( &store->results[0], |
&ctx->_ModelProjectMatrix, |
VB->AttribPtr[0] ); |
/* Drivers expect this to be clean to element 4... |
*/ |
switch (VB->ClipPtr->size) { |
case 1: |
/* impossible */ |
case 2: |
_mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 ); |
/* fall-through */ |
case 3: |
_mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 ); |
/* fall-through */ |
case 4: |
break; |
} |
} |
else { |
/* Setup the VB pointers so that the next pipeline stages get |
* their data from the right place (the program output arrays). |
*/ |
VB->ClipPtr = &store->results[VERT_RESULT_HPOS]; |
VB->ClipPtr->size = 4; |
VB->ClipPtr->count = VB->Count; |
} |
VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->results[VERT_RESULT_COL0]; |
VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->results[VERT_RESULT_COL1]; |
VB->AttribPtr[VERT_ATTRIB_FOG] = &store->results[VERT_RESULT_FOGC]; |
VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->results[VERT_RESULT_PSIZ]; |
VB->BackfaceColorPtr = &store->results[VERT_RESULT_BFC0]; |
VB->BackfaceSecondaryColorPtr = &store->results[VERT_RESULT_BFC1]; |
for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { |
VB->AttribPtr[_TNL_ATTRIB_TEX0 + i] |
= &store->results[VERT_RESULT_TEX0 + i]; |
} |
for (i = 0; i < ctx->Const.MaxVarying; i++) { |
if (program->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_VAR0 + i)) { |
/* Note: varying results get put into the generic attributes */ |
VB->AttribPtr[VERT_ATTRIB_GENERIC0+i] |
= &store->results[VERT_RESULT_VAR0 + i]; |
} |
} |
/* Perform NDC and cliptest operations: |
*/ |
return do_ndc_cliptest(ctx, store); |
} |
/** |
* Called the first time stage->run is called. In effect, don't |
* allocate data until the first time the stage is run. |
*/ |
static GLboolean |
init_vp(struct gl_context *ctx, struct tnl_pipeline_stage *stage) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &(tnl->vb); |
struct vp_stage_data *store; |
const GLuint size = VB->Size; |
GLuint i; |
stage->privatePtr = CALLOC(sizeof(*store)); |
store = VP_STAGE_DATA(stage); |
if (!store) |
return GL_FALSE; |
/* Allocate arrays of vertex output values */ |
for (i = 0; i < VERT_RESULT_MAX; i++) { |
_mesa_vector4f_alloc( &store->results[i], 0, size, 32 ); |
store->results[i].size = 4; |
} |
/* a few other misc allocations */ |
_mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 ); |
store->clipmask = (GLubyte *) _mesa_align_malloc(sizeof(GLubyte)*size, 32 ); |
return GL_TRUE; |
} |
/** |
* Destructor for this pipeline stage. |
*/ |
static void |
dtr(struct tnl_pipeline_stage *stage) |
{ |
struct vp_stage_data *store = VP_STAGE_DATA(stage); |
if (store) { |
GLuint i; |
/* free the vertex program result arrays */ |
for (i = 0; i < VERT_RESULT_MAX; i++) |
_mesa_vector4f_free( &store->results[i] ); |
/* free misc arrays */ |
_mesa_vector4f_free( &store->ndcCoords ); |
_mesa_align_free( store->clipmask ); |
FREE( store ); |
stage->privatePtr = NULL; |
} |
} |
static void |
validate_vp_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage) |
{ |
if (ctx->VertexProgram._Current) { |
_swrast_update_texture_samplers(ctx); |
} |
} |
/** |
* Public description of this pipeline stage. |
*/ |
const struct tnl_pipeline_stage _tnl_vertex_program_stage = |
{ |
"vertex-program", |
NULL, /* private_data */ |
init_vp, /* create */ |
dtr, /* destroy */ |
validate_vp_stage, /* validate */ |
run_vp /* run -- initially set to ctr */ |
}; |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_render.c |
---|
0,0 → 1,348 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2005 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
/* |
* Render whole vertex buffers, including projection of vertices from |
* clip space and clipping of primitives. |
* |
* This file makes calls to project vertices and to the point, line |
* and triangle rasterizers via the function pointers: |
* |
* context->Driver.Render.* |
* |
*/ |
#include "main/glheader.h" |
#include "main/context.h" |
#include "main/enums.h" |
#include "main/macros.h" |
#include "main/imports.h" |
#include "main/mtypes.h" |
#include "math/m_xform.h" |
#include "t_pipeline.h" |
/**********************************************************************/ |
/* Clip single primitives */ |
/**********************************************************************/ |
#define W(i) coord[i][3] |
#define Z(i) coord[i][2] |
#define Y(i) coord[i][1] |
#define X(i) coord[i][0] |
#define SIZE 4 |
#define TAG(x) x##_4 |
#include "t_vb_cliptmp.h" |
/**********************************************************************/ |
/* Clip and render whole begin/end objects */ |
/**********************************************************************/ |
#define NEED_EDGEFLAG_SETUP (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL) |
#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx] |
#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val |
/* This does NOT include the CLIP_USER_BIT! */ |
#define CLIPMASK (CLIP_FRUSTUM_BITS | CLIP_CULL_BIT) |
/* Vertices, with the possibility of clipping. |
*/ |
#define RENDER_POINTS( start, count ) \ |
tnl->Driver.Render.Points( ctx, start, count ) |
#define RENDER_LINE( v1, v2 ) \ |
do { \ |
GLubyte c1 = mask[v1], c2 = mask[v2]; \ |
GLubyte ormask = c1|c2; \ |
if (!ormask) \ |
LineFunc( ctx, v1, v2 ); \ |
else if (!(c1 & c2 & CLIPMASK)) \ |
clip_line_4( ctx, v1, v2, ormask ); \ |
} while (0) |
#define RENDER_TRI( v1, v2, v3 ) \ |
do { \ |
GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \ |
GLubyte ormask = c1|c2|c3; \ |
if (!ormask) \ |
TriangleFunc( ctx, v1, v2, v3 ); \ |
else if (!(c1 & c2 & c3 & CLIPMASK)) \ |
clip_tri_4( ctx, v1, v2, v3, ormask ); \ |
} while (0) |
#define RENDER_QUAD( v1, v2, v3, v4 ) \ |
do { \ |
GLubyte c1 = mask[v1], c2 = mask[v2]; \ |
GLubyte c3 = mask[v3], c4 = mask[v4]; \ |
GLubyte ormask = c1|c2|c3|c4; \ |
if (!ormask) \ |
QuadFunc( ctx, v1, v2, v3, v4 ); \ |
else if (!(c1 & c2 & c3 & c4 & CLIPMASK)) \ |
clip_quad_4( ctx, v1, v2, v3, v4, ormask ); \ |
} while (0) |
#define LOCAL_VARS \ |
TNLcontext *tnl = TNL_CONTEXT(ctx); \ |
struct vertex_buffer *VB = &tnl->vb; \ |
const GLuint * const elt = VB->Elts; \ |
const GLubyte *mask = VB->ClipMask; \ |
const GLuint sz = VB->ClipPtr->size; \ |
const tnl_line_func LineFunc = tnl->Driver.Render.Line; \ |
const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \ |
const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \ |
const GLboolean stipple = ctx->Line.StippleFlag; \ |
(void) (LineFunc && TriangleFunc && QuadFunc); \ |
(void) elt; (void) mask; (void) sz; (void) stipple; |
#define TAG(x) clip_##x##_verts |
#define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x ) |
#define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx ) |
#define PRESERVE_VB_DEFS |
#include "t_vb_rendertmp.h" |
/* Elts, with the possibility of clipping. |
*/ |
#undef ELT |
#undef TAG |
#define ELT(x) elt[x] |
#define TAG(x) clip_##x##_elts |
#include "t_vb_rendertmp.h" |
/* TODO: do this for all primitives, verts and elts: |
*/ |
static void clip_elt_triangles( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
tnl_render_func render_tris = tnl->Driver.Render.PrimTabElts[GL_TRIANGLES]; |
struct vertex_buffer *VB = &tnl->vb; |
const GLuint * const elt = VB->Elts; |
GLubyte *mask = VB->ClipMask; |
GLuint last = count-2; |
GLuint j; |
(void) flags; |
tnl->Driver.Render.PrimitiveNotify( ctx, GL_TRIANGLES ); |
for (j=start; j < last; j+=3 ) { |
GLubyte c1 = mask[elt[j]]; |
GLubyte c2 = mask[elt[j+1]]; |
GLubyte c3 = mask[elt[j+2]]; |
GLubyte ormask = c1|c2|c3; |
if (ormask) { |
if (start < j) |
render_tris( ctx, start, j, 0 ); |
if (!(c1&c2&c3&CLIPMASK)) |
clip_tri_4( ctx, elt[j], elt[j+1], elt[j+2], ormask ); |
start = j+3; |
} |
} |
if (start < j) |
render_tris( ctx, start, j, 0 ); |
} |
/**********************************************************************/ |
/* Render whole begin/end objects */ |
/**********************************************************************/ |
#define NEED_EDGEFLAG_SETUP (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL) |
#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx] |
#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val |
/* Vertices, no clipping. |
*/ |
#define RENDER_POINTS( start, count ) \ |
tnl->Driver.Render.Points( ctx, start, count ) |
#define RENDER_LINE( v1, v2 ) \ |
LineFunc( ctx, v1, v2 ) |
#define RENDER_TRI( v1, v2, v3 ) \ |
TriangleFunc( ctx, v1, v2, v3 ) |
#define RENDER_QUAD( v1, v2, v3, v4 ) \ |
QuadFunc( ctx, v1, v2, v3, v4 ) |
#define TAG(x) _tnl_##x##_verts |
#define LOCAL_VARS \ |
TNLcontext *tnl = TNL_CONTEXT(ctx); \ |
struct vertex_buffer *VB = &tnl->vb; \ |
const GLuint * const elt = VB->Elts; \ |
const tnl_line_func LineFunc = tnl->Driver.Render.Line; \ |
const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \ |
const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \ |
const GLboolean stipple = ctx->Line.StippleFlag; \ |
(void) (LineFunc && TriangleFunc && QuadFunc); \ |
(void) elt; (void) stipple |
#define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx ) |
#define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x ) |
#define RENDER_TAB_QUALIFIER |
#define PRESERVE_VB_DEFS |
#include "t_vb_rendertmp.h" |
/* Elts, no clipping. |
*/ |
#undef ELT |
#define TAG(x) _tnl_##x##_elts |
#define ELT(x) elt[x] |
#include "t_vb_rendertmp.h" |
/**********************************************************************/ |
/* Helper functions for drivers */ |
/**********************************************************************/ |
void _tnl_RenderClippedPolygon( struct gl_context *ctx, const GLuint *elts, GLuint n ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
GLuint *tmp = VB->Elts; |
VB->Elts = (GLuint *)elts; |
tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END ); |
VB->Elts = tmp; |
} |
void _tnl_RenderClippedLine( struct gl_context *ctx, GLuint ii, GLuint jj ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
tnl->Driver.Render.Line( ctx, ii, jj ); |
} |
/**********************************************************************/ |
/* Clip and render whole vertex buffers */ |
/**********************************************************************/ |
static GLboolean run_render( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
tnl_render_func *tab; |
GLint pass = 0; |
/* Allow the drivers to lock before projected verts are built so |
* that window coordinates are guarenteed not to change before |
* rendering. |
*/ |
ASSERT(tnl->Driver.Render.Start); |
tnl->Driver.Render.Start( ctx ); |
ASSERT(tnl->Driver.Render.BuildVertices); |
ASSERT(tnl->Driver.Render.PrimitiveNotify); |
ASSERT(tnl->Driver.Render.Points); |
ASSERT(tnl->Driver.Render.Line); |
ASSERT(tnl->Driver.Render.Triangle); |
ASSERT(tnl->Driver.Render.Quad); |
ASSERT(tnl->Driver.Render.ResetLineStipple); |
ASSERT(tnl->Driver.Render.Interp); |
ASSERT(tnl->Driver.Render.CopyPV); |
ASSERT(tnl->Driver.Render.ClippedLine); |
ASSERT(tnl->Driver.Render.ClippedPolygon); |
ASSERT(tnl->Driver.Render.Finish); |
tnl->Driver.Render.BuildVertices( ctx, 0, VB->Count, ~0 ); |
if (VB->ClipOrMask) { |
tab = VB->Elts ? clip_render_tab_elts : clip_render_tab_verts; |
clip_render_tab_elts[GL_TRIANGLES] = clip_elt_triangles; |
} |
else { |
tab = (VB->Elts ? |
tnl->Driver.Render.PrimTabElts : |
tnl->Driver.Render.PrimTabVerts); |
} |
do |
{ |
GLuint i; |
for (i = 0 ; i < VB->PrimitiveCount ; i++) |
{ |
GLuint prim = _tnl_translate_prim(&VB->Primitive[i]); |
GLuint start = VB->Primitive[i].start; |
GLuint length = VB->Primitive[i].count; |
assert((prim & PRIM_MODE_MASK) <= GL_POLYGON); |
if (MESA_VERBOSE & VERBOSE_PRIMS) |
_mesa_debug(NULL, "MESA prim %s %d..%d\n", |
_mesa_lookup_enum_by_nr(prim & PRIM_MODE_MASK), |
start, start+length); |
if (length) |
tab[prim & PRIM_MODE_MASK]( ctx, start, start + length, prim ); |
} |
} while (tnl->Driver.Render.Multipass && |
tnl->Driver.Render.Multipass( ctx, ++pass )); |
tnl->Driver.Render.Finish( ctx ); |
return GL_FALSE; /* finished the pipe */ |
} |
/**********************************************************************/ |
/* Render pipeline stage */ |
/**********************************************************************/ |
const struct tnl_pipeline_stage _tnl_render_stage = |
{ |
"render", /* name */ |
NULL, /* private data */ |
NULL, /* creator */ |
NULL, /* destructor */ |
NULL, /* validate */ |
run_render /* run */ |
}; |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_rendertmp.h |
---|
0,0 → 1,486 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2005 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#ifndef POSTFIX |
#define POSTFIX |
#endif |
#ifndef INIT |
#define INIT(x) |
#endif |
#ifndef NEED_EDGEFLAG_SETUP |
#define NEED_EDGEFLAG_SETUP 0 |
#define EDGEFLAG_GET(a) 0 |
#define EDGEFLAG_SET(a,b) (void)b |
#endif |
#ifndef RESET_STIPPLE |
#define RESET_STIPPLE |
#endif |
#ifndef TEST_PRIM_END |
#define TEST_PRIM_END(prim) (flags & PRIM_END) |
#define TEST_PRIM_BEGIN(prim) (flags & PRIM_BEGIN) |
#endif |
#ifndef ELT |
#define ELT(x) x |
#endif |
#ifndef RENDER_TAB_QUALIFIER |
#define RENDER_TAB_QUALIFIER static |
#endif |
static void TAG(render_points)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
LOCAL_VARS; |
(void) flags; |
INIT(GL_POINTS); |
RENDER_POINTS( start, count ); |
POSTFIX; |
} |
static void TAG(render_lines)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
GLuint j; |
LOCAL_VARS; |
(void) flags; |
INIT(GL_LINES); |
for (j=start+1; j<count; j+=2 ) { |
RESET_STIPPLE; |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) |
RENDER_LINE( ELT(j-1), ELT(j) ); |
else |
RENDER_LINE( ELT(j), ELT(j-1) ); |
} |
POSTFIX; |
} |
static void TAG(render_line_strip)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
GLuint j; |
LOCAL_VARS; |
(void) flags; |
INIT(GL_LINE_STRIP); |
if (TEST_PRIM_BEGIN(flags)) { |
RESET_STIPPLE; |
} |
for (j=start+1; j<count; j++ ) { |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) |
RENDER_LINE( ELT(j-1), ELT(j) ); |
else |
RENDER_LINE( ELT(j), ELT(j-1) ); |
} |
POSTFIX; |
} |
static void TAG(render_line_loop)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
GLuint i; |
LOCAL_VARS; |
(void) flags; |
INIT(GL_LINE_LOOP); |
if (start+1 < count) { |
if (TEST_PRIM_BEGIN(flags)) { |
RESET_STIPPLE; |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) |
RENDER_LINE( ELT(start), ELT(start+1) ); |
else |
RENDER_LINE( ELT(start+1), ELT(start) ); |
} |
for ( i = start+2 ; i < count ; i++) { |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) |
RENDER_LINE( ELT(i-1), ELT(i) ); |
else |
RENDER_LINE( ELT(i), ELT(i-1) ); |
} |
if ( TEST_PRIM_END(flags)) { |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) |
RENDER_LINE( ELT(count-1), ELT(start) ); |
else |
RENDER_LINE( ELT(start), ELT(count-1) ); |
} |
} |
POSTFIX; |
} |
static void TAG(render_triangles)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
GLuint j; |
LOCAL_VARS; |
(void) flags; |
INIT(GL_TRIANGLES); |
if (NEED_EDGEFLAG_SETUP) { |
for (j=start+2; j<count; j+=3) { |
/* Leave the edgeflags as supplied by the user. |
*/ |
RESET_STIPPLE; |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) |
RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) ); |
else |
RENDER_TRI( ELT(j-1), ELT(j), ELT(j-2) ); |
} |
} else { |
for (j=start+2; j<count; j+=3) { |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) |
RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) ); |
else |
RENDER_TRI( ELT(j-1), ELT(j), ELT(j-2) ); |
} |
} |
POSTFIX; |
} |
static void TAG(render_tri_strip)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
GLuint j; |
GLuint parity = 0; |
LOCAL_VARS; |
INIT(GL_TRIANGLE_STRIP); |
if (NEED_EDGEFLAG_SETUP) { |
for (j=start+2;j<count;j++,parity^=1) { |
GLuint ej2, ej1, ej; |
GLboolean ef2, ef1, ef; |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) { |
ej2 = ELT(j-2+parity); |
ej1 = ELT(j-1-parity); |
ej = ELT(j); |
} |
else { |
ej2 = ELT(j-1+parity); |
ej1 = ELT(j-parity); |
ej = ELT(j-2); |
} |
ef2 = EDGEFLAG_GET( ej2 ); |
ef1 = EDGEFLAG_GET( ej1 ); |
ef = EDGEFLAG_GET( ej ); |
if (TEST_PRIM_BEGIN(flags)) { |
RESET_STIPPLE; |
} |
EDGEFLAG_SET( ej2, GL_TRUE ); |
EDGEFLAG_SET( ej1, GL_TRUE ); |
EDGEFLAG_SET( ej, GL_TRUE ); |
RENDER_TRI( ej2, ej1, ej ); |
EDGEFLAG_SET( ej2, ef2 ); |
EDGEFLAG_SET( ej1, ef1 ); |
EDGEFLAG_SET( ej, ef ); |
} |
} else { |
for (j=start+2; j<count ; j++, parity^=1) { |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) |
RENDER_TRI( ELT(j-2+parity), ELT(j-1-parity), ELT(j) ); |
else |
RENDER_TRI( ELT(j-1+parity), ELT(j-parity), ELT(j-2) ); |
} |
} |
POSTFIX; |
} |
static void TAG(render_tri_fan)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
GLuint j; |
LOCAL_VARS; |
(void) flags; |
INIT(GL_TRIANGLE_FAN); |
if (NEED_EDGEFLAG_SETUP) { |
for (j=start+2;j<count;j++) { |
/* For trifans, all edges are boundary. |
*/ |
GLuint ejs = ELT(start); |
GLuint ej1 = ELT(j-1); |
GLuint ej = ELT(j); |
GLboolean efs = EDGEFLAG_GET( ejs ); |
GLboolean ef1 = EDGEFLAG_GET( ej1 ); |
GLboolean ef = EDGEFLAG_GET( ej ); |
if (TEST_PRIM_BEGIN(flags)) { |
RESET_STIPPLE; |
} |
EDGEFLAG_SET( ejs, GL_TRUE ); |
EDGEFLAG_SET( ej1, GL_TRUE ); |
EDGEFLAG_SET( ej, GL_TRUE ); |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) |
RENDER_TRI( ejs, ej1, ej); |
else |
RENDER_TRI( ej, ejs, ej1); |
EDGEFLAG_SET( ejs, efs ); |
EDGEFLAG_SET( ej1, ef1 ); |
EDGEFLAG_SET( ej, ef ); |
} |
} else { |
for (j=start+2;j<count;j++) { |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) |
RENDER_TRI( ELT(start), ELT(j-1), ELT(j) ); |
else |
RENDER_TRI( ELT(j), ELT(start), ELT(j-1) ); |
} |
} |
POSTFIX; |
} |
static void TAG(render_poly)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
GLuint j = start+2; |
LOCAL_VARS; |
(void) flags; |
INIT(GL_POLYGON); |
if (NEED_EDGEFLAG_SETUP) { |
GLboolean efstart = EDGEFLAG_GET( ELT(start) ); |
GLboolean efcount = EDGEFLAG_GET( ELT(count-1) ); |
/* If the primitive does not begin here, the first edge |
* is non-boundary. |
*/ |
if (!TEST_PRIM_BEGIN(flags)) |
EDGEFLAG_SET( ELT(start), GL_FALSE ); |
else { |
RESET_STIPPLE; |
} |
/* If the primitive does not end here, the final edge is |
* non-boundary. |
*/ |
if (!TEST_PRIM_END(flags)) |
EDGEFLAG_SET( ELT(count-1), GL_FALSE ); |
/* Draw the first triangles (possibly zero) |
*/ |
if (j+1<count) { |
GLboolean ef = EDGEFLAG_GET( ELT(j) ); |
EDGEFLAG_SET( ELT(j), GL_FALSE ); |
RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); |
EDGEFLAG_SET( ELT(j), ef ); |
j++; |
/* Don't render the first edge again: |
*/ |
EDGEFLAG_SET( ELT(start), GL_FALSE ); |
for (;j+1<count;j++) { |
GLboolean efj = EDGEFLAG_GET( ELT(j) ); |
EDGEFLAG_SET( ELT(j), GL_FALSE ); |
RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); |
EDGEFLAG_SET( ELT(j), efj ); |
} |
} |
/* Draw the last or only triangle |
*/ |
if (j < count) |
RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); |
/* Restore the first and last edgeflags: |
*/ |
EDGEFLAG_SET( ELT(count-1), efcount ); |
EDGEFLAG_SET( ELT(start), efstart ); |
} |
else { |
for (j=start+2;j<count;j++) { |
RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); |
} |
} |
POSTFIX; |
} |
static void TAG(render_quads)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
GLuint j; |
LOCAL_VARS; |
(void) flags; |
INIT(GL_QUADS); |
if (NEED_EDGEFLAG_SETUP) { |
for (j=start+3; j<count; j+=4) { |
/* Use user-specified edgeflags for quads. |
*/ |
RESET_STIPPLE; |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || |
!ctx->Const.QuadsFollowProvokingVertexConvention) |
RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) ); |
else |
RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) ); |
} |
} else { |
for (j=start+3; j<count; j+=4) { |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || |
!ctx->Const.QuadsFollowProvokingVertexConvention) |
RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) ); |
else |
RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) ); |
} |
} |
POSTFIX; |
} |
static void TAG(render_quad_strip)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
GLuint j; |
LOCAL_VARS; |
(void) flags; |
INIT(GL_QUAD_STRIP); |
if (NEED_EDGEFLAG_SETUP) { |
for (j=start+3;j<count;j+=2) { |
/* All edges are boundary. Set edgeflags to 1, draw the |
* quad, and restore them to the original values. |
*/ |
GLboolean ef3 = EDGEFLAG_GET( ELT(j-3) ); |
GLboolean ef2 = EDGEFLAG_GET( ELT(j-2) ); |
GLboolean ef1 = EDGEFLAG_GET( ELT(j-1) ); |
GLboolean ef = EDGEFLAG_GET( ELT(j) ); |
if (TEST_PRIM_BEGIN(flags)) { |
RESET_STIPPLE; |
} |
EDGEFLAG_SET( ELT(j-3), GL_TRUE ); |
EDGEFLAG_SET( ELT(j-2), GL_TRUE ); |
EDGEFLAG_SET( ELT(j-1), GL_TRUE ); |
EDGEFLAG_SET( ELT(j), GL_TRUE ); |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || |
!ctx->Const.QuadsFollowProvokingVertexConvention) |
RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) ); |
else |
RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) ); |
EDGEFLAG_SET( ELT(j-3), ef3 ); |
EDGEFLAG_SET( ELT(j-2), ef2 ); |
EDGEFLAG_SET( ELT(j-1), ef1 ); |
EDGEFLAG_SET( ELT(j), ef ); |
} |
} else { |
for (j=start+3;j<count;j+=2) { |
if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || |
!ctx->Const.QuadsFollowProvokingVertexConvention) |
RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) ); |
else |
RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) ); |
} |
} |
POSTFIX; |
} |
static void TAG(render_noop)( struct gl_context *ctx, |
GLuint start, |
GLuint count, |
GLuint flags ) |
{ |
(void)(ctx && start && count && flags); |
} |
RENDER_TAB_QUALIFIER void (*TAG(render_tab)[GL_POLYGON+2])(struct gl_context *, |
GLuint, |
GLuint, |
GLuint) = |
{ |
TAG(render_points), |
TAG(render_lines), |
TAG(render_line_loop), |
TAG(render_line_strip), |
TAG(render_triangles), |
TAG(render_tri_strip), |
TAG(render_tri_fan), |
TAG(render_quads), |
TAG(render_quad_strip), |
TAG(render_poly), |
TAG(render_noop), |
}; |
#ifndef PRESERVE_VB_DEFS |
#undef RENDER_TRI |
#undef RENDER_QUAD |
#undef RENDER_LINE |
#undef RENDER_POINTS |
#undef LOCAL_VARS |
#undef INIT |
#undef POSTFIX |
#undef RESET_STIPPLE |
#undef DBG |
#undef ELT |
#undef RENDER_TAB_QUALIFIER |
#endif |
#ifndef PRESERVE_TAG |
#undef TAG |
#endif |
#undef PRESERVE_VB_DEFS |
#undef PRESERVE_TAG |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_texgen.c |
---|
0,0 → 1,609 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 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. |
* |
* Authors: |
* Brian Paul |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
/* |
* Regarding GL_NV_texgen_reflection: |
* |
* Portions of this software may use or implement intellectual |
* property owned and licensed by NVIDIA Corporation. NVIDIA disclaims |
* any and all warranties with respect to such intellectual property, |
* including any use thereof or modifications thereto. |
*/ |
#include "main/glheader.h" |
#include "main/colormac.h" |
#include "main/macros.h" |
#include "main/imports.h" |
#include "main/mtypes.h" |
#include "math/m_xform.h" |
#include "t_context.h" |
#include "t_pipeline.h" |
/*********************************************************************** |
* Automatic texture coordinate generation (texgen) code. |
*/ |
struct texgen_stage_data; |
typedef void (*texgen_func)( struct gl_context *ctx, |
struct texgen_stage_data *store, |
GLuint unit); |
struct texgen_stage_data { |
/* Per-texunit derived state. |
*/ |
GLuint TexgenSize[MAX_TEXTURE_COORD_UNITS]; |
texgen_func TexgenFunc[MAX_TEXTURE_COORD_UNITS]; |
/* Temporary values used in texgen. |
*/ |
GLfloat (*tmp_f)[3]; |
GLfloat *tmp_m; |
/* Buffered outputs of the stage. |
*/ |
GLvector4f texcoord[MAX_TEXTURE_COORD_UNITS]; |
}; |
#define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->privatePtr) |
static GLuint all_bits[5] = { |
0, |
VEC_SIZE_1, |
VEC_SIZE_2, |
VEC_SIZE_3, |
VEC_SIZE_4, |
}; |
#define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4) |
#define TEXGEN_NEED_M (TEXGEN_SPHERE_MAP) |
#define TEXGEN_NEED_F (TEXGEN_SPHERE_MAP | \ |
TEXGEN_REFLECTION_MAP_NV) |
static void build_m3( GLfloat f[][3], GLfloat m[], |
const GLvector4f *normal, |
const GLvector4f *eye ) |
{ |
GLuint stride = eye->stride; |
GLfloat *coord = (GLfloat *)eye->start; |
GLuint count = eye->count; |
const GLfloat *norm = normal->start; |
GLuint i; |
for (i=0;i<count;i++,STRIDE_F(coord,stride),STRIDE_F(norm,normal->stride)) { |
GLfloat u[3], two_nu, fx, fy, fz; |
COPY_3V( u, coord ); |
NORMALIZE_3FV( u ); |
two_nu = 2.0F * DOT3(norm,u); |
fx = f[i][0] = u[0] - norm[0] * two_nu; |
fy = f[i][1] = u[1] - norm[1] * two_nu; |
fz = f[i][2] = u[2] - norm[2] * two_nu; |
m[i] = fx * fx + fy * fy + (fz + 1.0F) * (fz + 1.0F); |
if (m[i] != 0.0F) { |
m[i] = 0.5F * _mesa_inv_sqrtf(m[i]); |
} |
} |
} |
static void build_m2( GLfloat f[][3], GLfloat m[], |
const GLvector4f *normal, |
const GLvector4f *eye ) |
{ |
GLuint stride = eye->stride; |
GLfloat *coord = eye->start; |
GLuint count = eye->count; |
GLfloat *norm = normal->start; |
GLuint i; |
for (i=0;i<count;i++,STRIDE_F(coord,stride),STRIDE_F(norm,normal->stride)) { |
GLfloat u[3], two_nu, fx, fy, fz; |
COPY_2V( u, coord ); |
u[2] = 0; |
NORMALIZE_3FV( u ); |
two_nu = 2.0F * DOT3(norm,u); |
fx = f[i][0] = u[0] - norm[0] * two_nu; |
fy = f[i][1] = u[1] - norm[1] * two_nu; |
fz = f[i][2] = u[2] - norm[2] * two_nu; |
m[i] = fx * fx + fy * fy + (fz + 1.0F) * (fz + 1.0F); |
if (m[i] != 0.0F) { |
m[i] = 0.5F * _mesa_inv_sqrtf(m[i]); |
} |
} |
} |
typedef void (*build_m_func)( GLfloat f[][3], |
GLfloat m[], |
const GLvector4f *normal, |
const GLvector4f *eye ); |
static build_m_func build_m_tab[5] = { |
NULL, |
NULL, |
build_m2, |
build_m3, |
build_m3 |
}; |
/* This is unusual in that we respect the stride of the output vector |
* (f). This allows us to pass in either a texcoord vector4f, or a |
* temporary vector3f. |
*/ |
static void build_f3( GLfloat *f, |
GLuint fstride, |
const GLvector4f *normal, |
const GLvector4f *eye ) |
{ |
GLuint stride = eye->stride; |
GLfloat *coord = eye->start; |
GLuint count = eye->count; |
GLfloat *norm = normal->start; |
GLuint i; |
for (i=0;i<count;i++) { |
GLfloat u[3], two_nu; |
COPY_3V( u, coord ); |
NORMALIZE_3FV( u ); |
two_nu = 2.0F * DOT3(norm,u); |
f[0] = u[0] - norm[0] * two_nu; |
f[1] = u[1] - norm[1] * two_nu; |
f[2] = u[2] - norm[2] * two_nu; |
STRIDE_F(coord,stride); |
STRIDE_F(f,fstride); |
STRIDE_F(norm, normal->stride); |
} |
} |
static void build_f2( GLfloat *f, |
GLuint fstride, |
const GLvector4f *normal, |
const GLvector4f *eye ) |
{ |
GLuint stride = eye->stride; |
GLfloat *coord = eye->start; |
GLuint count = eye->count; |
GLfloat *norm = normal->start; |
GLuint i; |
for (i=0;i<count;i++) { |
GLfloat u[3], two_nu; |
COPY_2V( u, coord ); |
u[2] = 0; |
NORMALIZE_3FV( u ); |
two_nu = 2.0F * DOT3(norm,u); |
f[0] = u[0] - norm[0] * two_nu; |
f[1] = u[1] - norm[1] * two_nu; |
f[2] = u[2] - norm[2] * two_nu; |
STRIDE_F(coord,stride); |
STRIDE_F(f,fstride); |
STRIDE_F(norm, normal->stride); |
} |
} |
typedef void (*build_f_func)( GLfloat *f, |
GLuint fstride, |
const GLvector4f *normal_vec, |
const GLvector4f *eye ); |
/* Just treat 4-vectors as 3-vectors. |
*/ |
static build_f_func build_f_tab[5] = { |
NULL, |
NULL, |
build_f2, |
build_f3, |
build_f3 |
}; |
/* Special case texgen functions. |
*/ |
static void texgen_reflection_map_nv( struct gl_context *ctx, |
struct texgen_stage_data *store, |
GLuint unit ) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; |
GLvector4f *out = &store->texcoord[unit]; |
build_f_tab[VB->EyePtr->size]( out->start, |
out->stride, |
VB->AttribPtr[_TNL_ATTRIB_NORMAL], |
VB->EyePtr ); |
out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3; |
out->count = VB->Count; |
out->size = MAX2(in->size, 3); |
if (in->size == 4) |
_mesa_copy_tab[0x8]( out, in ); |
} |
static void texgen_normal_map_nv( struct gl_context *ctx, |
struct texgen_stage_data *store, |
GLuint unit ) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; |
GLvector4f *out = &store->texcoord[unit]; |
GLvector4f *normal = VB->AttribPtr[_TNL_ATTRIB_NORMAL]; |
GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->start; |
GLuint count = VB->Count; |
GLuint i; |
const GLfloat *norm = normal->start; |
for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { |
texcoord[i][0] = norm[0]; |
texcoord[i][1] = norm[1]; |
texcoord[i][2] = norm[2]; |
} |
out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3; |
out->count = count; |
out->size = MAX2(in->size, 3); |
if (in->size == 4) |
_mesa_copy_tab[0x8]( out, in ); |
} |
static void texgen_sphere_map( struct gl_context *ctx, |
struct texgen_stage_data *store, |
GLuint unit ) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; |
GLvector4f *out = &store->texcoord[unit]; |
GLfloat (*texcoord)[4] = (GLfloat (*)[4]) out->start; |
GLuint count = VB->Count; |
GLuint i; |
GLfloat (*f)[3] = store->tmp_f; |
GLfloat *m = store->tmp_m; |
(build_m_tab[VB->EyePtr->size])( store->tmp_f, |
store->tmp_m, |
VB->AttribPtr[_TNL_ATTRIB_NORMAL], |
VB->EyePtr ); |
out->size = MAX2(in->size,2); |
for (i=0;i<count;i++) { |
texcoord[i][0] = f[i][0] * m[i] + 0.5F; |
texcoord[i][1] = f[i][1] * m[i] + 0.5F; |
} |
out->count = count; |
out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_2; |
if (in->size > 2) |
_mesa_copy_tab[all_bits[in->size] & ~0x3]( out, in ); |
} |
static void texgen( struct gl_context *ctx, |
struct texgen_stage_data *store, |
GLuint unit ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; |
GLvector4f *out = &store->texcoord[unit]; |
const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; |
const GLvector4f *obj = VB->AttribPtr[_TNL_ATTRIB_POS]; |
const GLvector4f *eye = VB->EyePtr; |
const GLvector4f *normal = VB->AttribPtr[_TNL_ATTRIB_NORMAL]; |
const GLfloat *m = store->tmp_m; |
const GLuint count = VB->Count; |
GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->data; |
GLfloat (*f)[3] = store->tmp_f; |
GLuint copy; |
if (texUnit->_GenFlags & TEXGEN_NEED_M) { |
build_m_tab[eye->size]( store->tmp_f, store->tmp_m, normal, eye ); |
} else if (texUnit->_GenFlags & TEXGEN_NEED_F) { |
build_f_tab[eye->size]( (GLfloat *)store->tmp_f, 3, normal, eye ); |
} |
out->size = MAX2(in->size, store->TexgenSize[unit]); |
out->flags |= (in->flags & VEC_SIZE_FLAGS) | texUnit->TexGenEnabled; |
out->count = count; |
copy = (all_bits[in->size] & ~texUnit->TexGenEnabled); |
if (copy) |
_mesa_copy_tab[copy]( out, in ); |
if (texUnit->TexGenEnabled & S_BIT) { |
GLuint i; |
switch (texUnit->GenS.Mode) { |
case GL_OBJECT_LINEAR: |
_mesa_dotprod_tab[obj->size]( (GLfloat *)out->data, |
sizeof(out->data[0]), obj, |
texUnit->GenS.ObjectPlane ); |
break; |
case GL_EYE_LINEAR: |
_mesa_dotprod_tab[eye->size]( (GLfloat *)out->data, |
sizeof(out->data[0]), eye, |
texUnit->GenS.EyePlane ); |
break; |
case GL_SPHERE_MAP: |
for (i = 0; i < count; i++) |
texcoord[i][0] = f[i][0] * m[i] + 0.5F; |
break; |
case GL_REFLECTION_MAP_NV: |
for (i=0;i<count;i++) |
texcoord[i][0] = f[i][0]; |
break; |
case GL_NORMAL_MAP_NV: { |
const GLfloat *norm = normal->start; |
for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { |
texcoord[i][0] = norm[0]; |
} |
break; |
} |
default: |
_mesa_problem(ctx, "Bad S texgen"); |
} |
} |
if (texUnit->TexGenEnabled & T_BIT) { |
GLuint i; |
switch (texUnit->GenT.Mode) { |
case GL_OBJECT_LINEAR: |
_mesa_dotprod_tab[obj->size]( &(out->data[0][1]), |
sizeof(out->data[0]), obj, |
texUnit->GenT.ObjectPlane ); |
break; |
case GL_EYE_LINEAR: |
_mesa_dotprod_tab[eye->size]( &(out->data[0][1]), |
sizeof(out->data[0]), eye, |
texUnit->GenT.EyePlane ); |
break; |
case GL_SPHERE_MAP: |
for (i = 0; i < count; i++) |
texcoord[i][1] = f[i][1] * m[i] + 0.5F; |
break; |
case GL_REFLECTION_MAP_NV: |
for (i=0;i<count;i++) |
texcoord[i][1] = f[i][1]; |
break; |
case GL_NORMAL_MAP_NV: { |
const GLfloat *norm = normal->start; |
for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { |
texcoord[i][1] = norm[1]; |
} |
break; |
} |
default: |
_mesa_problem(ctx, "Bad T texgen"); |
} |
} |
if (texUnit->TexGenEnabled & R_BIT) { |
GLuint i; |
switch (texUnit->GenR.Mode) { |
case GL_OBJECT_LINEAR: |
_mesa_dotprod_tab[obj->size]( &(out->data[0][2]), |
sizeof(out->data[0]), obj, |
texUnit->GenR.ObjectPlane ); |
break; |
case GL_EYE_LINEAR: |
_mesa_dotprod_tab[eye->size]( &(out->data[0][2]), |
sizeof(out->data[0]), eye, |
texUnit->GenR.EyePlane ); |
break; |
case GL_REFLECTION_MAP_NV: |
for (i=0;i<count;i++) |
texcoord[i][2] = f[i][2]; |
break; |
case GL_NORMAL_MAP_NV: { |
const GLfloat *norm = normal->start; |
for (i=0;i<count;i++,STRIDE_F(norm, normal->stride)) { |
texcoord[i][2] = norm[2]; |
} |
break; |
} |
default: |
_mesa_problem(ctx, "Bad R texgen"); |
} |
} |
if (texUnit->TexGenEnabled & Q_BIT) { |
switch (texUnit->GenQ.Mode) { |
case GL_OBJECT_LINEAR: |
_mesa_dotprod_tab[obj->size]( &(out->data[0][3]), |
sizeof(out->data[0]), obj, |
texUnit->GenQ.ObjectPlane ); |
break; |
case GL_EYE_LINEAR: |
_mesa_dotprod_tab[eye->size]( &(out->data[0][3]), |
sizeof(out->data[0]), eye, |
texUnit->GenQ.EyePlane ); |
break; |
default: |
_mesa_problem(ctx, "Bad Q texgen"); |
} |
} |
} |
static GLboolean run_texgen_stage( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); |
GLuint i; |
if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Current) |
return GL_TRUE; |
for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) { |
struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; |
if (texUnit->TexGenEnabled) { |
store->TexgenFunc[i]( ctx, store, i ); |
VB->AttribPtr[VERT_ATTRIB_TEX0 + i] = &store->texcoord[i]; |
} |
} |
return GL_TRUE; |
} |
static void validate_texgen_stage( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); |
GLuint i; |
if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Current) |
return; |
for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) { |
struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; |
if (texUnit->TexGenEnabled) { |
GLuint sz; |
if (texUnit->TexGenEnabled & Q_BIT) |
sz = 4; |
else if (texUnit->TexGenEnabled & R_BIT) |
sz = 3; |
else if (texUnit->TexGenEnabled & T_BIT) |
sz = 2; |
else |
sz = 1; |
store->TexgenSize[i] = sz; |
store->TexgenFunc[i] = texgen; /* general solution */ |
/* look for special texgen cases */ |
if (texUnit->TexGenEnabled == (S_BIT|T_BIT|R_BIT)) { |
if (texUnit->_GenFlags == TEXGEN_REFLECTION_MAP_NV) { |
store->TexgenFunc[i] = texgen_reflection_map_nv; |
} |
else if (texUnit->_GenFlags == TEXGEN_NORMAL_MAP_NV) { |
store->TexgenFunc[i] = texgen_normal_map_nv; |
} |
} |
else if (texUnit->TexGenEnabled == (S_BIT|T_BIT) && |
texUnit->_GenFlags == TEXGEN_SPHERE_MAP) { |
store->TexgenFunc[i] = texgen_sphere_map; |
} |
} |
} |
} |
/* Called the first time stage->run() is invoked. |
*/ |
static GLboolean alloc_texgen_data( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
struct texgen_stage_data *store; |
GLuint i; |
stage->privatePtr = CALLOC(sizeof(*store)); |
store = TEXGEN_STAGE_DATA(stage); |
if (!store) |
return GL_FALSE; |
for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) |
_mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 ); |
store->tmp_f = (GLfloat (*)[3]) MALLOC(VB->Size * sizeof(GLfloat) * 3); |
store->tmp_m = (GLfloat *) MALLOC(VB->Size * sizeof(GLfloat)); |
return GL_TRUE; |
} |
static void free_texgen_data( struct tnl_pipeline_stage *stage ) |
{ |
struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); |
GLuint i; |
if (store) { |
for (i = 0 ; i < MAX_TEXTURE_COORD_UNITS ; i++) |
if (store->texcoord[i].data) |
_mesa_vector4f_free( &store->texcoord[i] ); |
if (store->tmp_f) FREE( store->tmp_f ); |
if (store->tmp_m) FREE( store->tmp_m ); |
FREE( store ); |
stage->privatePtr = NULL; |
} |
} |
const struct tnl_pipeline_stage _tnl_texgen_stage = |
{ |
"texgen", /* name */ |
NULL, /* private data */ |
alloc_texgen_data, /* destructor */ |
free_texgen_data, /* destructor */ |
validate_texgen_stage, /* check */ |
run_texgen_stage /* run -- initially set to alloc data */ |
}; |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_texmat.c |
---|
0,0 → 1,128 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/colormac.h" |
#include "main/macros.h" |
#include "main/imports.h" |
#include "main/mtypes.h" |
#include "math/m_xform.h" |
#include "t_context.h" |
#include "t_pipeline.h" |
/* Is there any real benefit seperating texmat from texgen? It means |
* we need two lots of intermediate storage. Any changes to |
* _NEW_TEXTURE will invalidate both sets -- it's only on changes to |
* *only* _NEW_TEXTURE_MATRIX that texgen survives but texmat doesn't. |
* |
* However, the seperation of this code from the complex texgen stuff |
* is very appealing. |
*/ |
struct texmat_stage_data { |
GLvector4f texcoord[MAX_TEXTURE_COORD_UNITS]; |
}; |
#define TEXMAT_STAGE_DATA(stage) ((struct texmat_stage_data *)stage->privatePtr) |
static GLboolean run_texmat_stage( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
struct texmat_stage_data *store = TEXMAT_STAGE_DATA(stage); |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
GLuint i; |
if (!ctx->Texture._TexMatEnabled || ctx->VertexProgram._Current) |
return GL_TRUE; |
/* ENABLE_TEXMAT implies that the texture matrix is not the |
* identity, so we don't have to check that here. |
*/ |
for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) { |
if (ctx->Texture._TexMatEnabled & ENABLE_TEXMAT(i)) { |
(void) TransformRaw( &store->texcoord[i], |
ctx->TextureMatrixStack[i].Top, |
VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]); |
VB->AttribPtr[VERT_ATTRIB_TEX0+i] = &store->texcoord[i]; |
} |
} |
return GL_TRUE; |
} |
/* Called the first time stage->run() is invoked. |
*/ |
static GLboolean alloc_texmat_data( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
struct texmat_stage_data *store; |
GLuint i; |
stage->privatePtr = CALLOC(sizeof(*store)); |
store = TEXMAT_STAGE_DATA(stage); |
if (!store) |
return GL_FALSE; |
for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) |
_mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 ); |
return GL_TRUE; |
} |
static void free_texmat_data( struct tnl_pipeline_stage *stage ) |
{ |
struct texmat_stage_data *store = TEXMAT_STAGE_DATA(stage); |
GLuint i; |
if (store) { |
for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) |
if (store->texcoord[i].data) |
_mesa_vector4f_free( &store->texcoord[i] ); |
FREE( store ); |
stage->privatePtr = NULL; |
} |
} |
const struct tnl_pipeline_stage _tnl_texture_transform_stage = |
{ |
"texture transform", /* name */ |
NULL, /* private data */ |
alloc_texmat_data, |
free_texmat_data, /* destructor */ |
NULL, |
run_texmat_stage, |
}; |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vb_vertex.c |
---|
0,0 → 1,283 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/colormac.h" |
#include "main/macros.h" |
#include "main/imports.h" |
#include "main/mtypes.h" |
#include "math/m_xform.h" |
#include "t_context.h" |
#include "t_pipeline.h" |
struct vertex_stage_data { |
GLvector4f eye; |
GLvector4f clip; |
GLvector4f proj; |
GLubyte *clipmask; |
GLubyte ormask; |
GLubyte andmask; |
}; |
#define VERTEX_STAGE_DATA(stage) ((struct vertex_stage_data *)stage->privatePtr) |
/* This function implements cliptesting for user-defined clip planes. |
* The clipping of primitives to these planes is implemented in |
* t_render_clip.h. |
*/ |
#define USER_CLIPTEST(NAME, SZ) \ |
static void NAME( struct gl_context *ctx, \ |
GLvector4f *clip, \ |
GLubyte *clipmask, \ |
GLubyte *clipormask, \ |
GLubyte *clipandmask ) \ |
{ \ |
GLuint p; \ |
\ |
for (p = 0; p < ctx->Const.MaxClipPlanes; p++) \ |
if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { \ |
GLuint nr, i; \ |
const GLfloat a = ctx->Transform._ClipUserPlane[p][0]; \ |
const GLfloat b = ctx->Transform._ClipUserPlane[p][1]; \ |
const GLfloat c = ctx->Transform._ClipUserPlane[p][2]; \ |
const GLfloat d = ctx->Transform._ClipUserPlane[p][3]; \ |
GLfloat *coord = (GLfloat *)clip->data; \ |
GLuint stride = clip->stride; \ |
GLuint count = clip->count; \ |
\ |
for (nr = 0, i = 0 ; i < count ; i++) { \ |
GLfloat dp = coord[0] * a + coord[1] * b; \ |
if (SZ > 2) dp += coord[2] * c; \ |
if (SZ > 3) dp += coord[3] * d; else dp += d; \ |
\ |
if (dp < 0) { \ |
nr++; \ |
clipmask[i] |= CLIP_USER_BIT; \ |
} \ |
\ |
STRIDE_F(coord, stride); \ |
} \ |
\ |
if (nr > 0) { \ |
*clipormask |= CLIP_USER_BIT; \ |
if (nr == count) { \ |
*clipandmask |= CLIP_USER_BIT; \ |
return; \ |
} \ |
} \ |
} \ |
} |
USER_CLIPTEST(userclip2, 2) |
USER_CLIPTEST(userclip3, 3) |
USER_CLIPTEST(userclip4, 4) |
static void (*(usercliptab[5]))( struct gl_context *, |
GLvector4f *, GLubyte *, |
GLubyte *, GLubyte * ) = |
{ |
NULL, |
NULL, |
userclip2, |
userclip3, |
userclip4 |
}; |
void |
tnl_clip_prepare(struct gl_context *ctx) |
{ |
/* Neither the x86 nor sparc asm cliptest functions have been updated |
* for ARB_depth_clamp, so force the C paths. |
*/ |
if (ctx->Transform.DepthClamp) { |
static GLboolean c_funcs_installed = GL_FALSE; |
if (!c_funcs_installed) { |
init_c_cliptest(); |
c_funcs_installed = GL_TRUE; |
} |
} |
} |
static GLboolean run_vertex_stage( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
struct vertex_stage_data *store = (struct vertex_stage_data *)stage->privatePtr; |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
if (ctx->VertexProgram._Current) |
return GL_TRUE; |
tnl_clip_prepare(ctx); |
if (ctx->_NeedEyeCoords) { |
/* Separate modelview transformation: |
* Use combined ModelProject to avoid some depth artifacts |
*/ |
if (ctx->ModelviewMatrixStack.Top->type == MATRIX_IDENTITY) |
VB->EyePtr = VB->AttribPtr[_TNL_ATTRIB_POS]; |
else |
VB->EyePtr = TransformRaw( &store->eye, |
ctx->ModelviewMatrixStack.Top, |
VB->AttribPtr[_TNL_ATTRIB_POS]); |
} |
VB->ClipPtr = TransformRaw( &store->clip, |
&ctx->_ModelProjectMatrix, |
VB->AttribPtr[_TNL_ATTRIB_POS] ); |
/* Drivers expect this to be clean to element 4... |
*/ |
switch (VB->ClipPtr->size) { |
case 1: |
/* impossible */ |
case 2: |
_mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 ); |
/* fall-through */ |
case 3: |
_mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 ); |
/* fall-through */ |
case 4: |
break; |
} |
/* Cliptest and perspective divide. Clip functions must clear |
* the clipmask. |
*/ |
store->ormask = 0; |
store->andmask = CLIP_FRUSTUM_BITS; |
if (tnl->NeedNdcCoords) { |
VB->NdcPtr = |
_mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr, |
&store->proj, |
store->clipmask, |
&store->ormask, |
&store->andmask, |
!ctx->Transform.DepthClamp ); |
} |
else { |
VB->NdcPtr = NULL; |
_mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr, |
NULL, |
store->clipmask, |
&store->ormask, |
&store->andmask, |
!ctx->Transform.DepthClamp ); |
} |
if (store->andmask) |
return GL_FALSE; |
/* Test userclip planes. This contributes to VB->ClipMask, so |
* is essentially required to be in this stage. |
*/ |
if (ctx->Transform.ClipPlanesEnabled) { |
usercliptab[VB->ClipPtr->size]( ctx, |
VB->ClipPtr, |
store->clipmask, |
&store->ormask, |
&store->andmask ); |
if (store->andmask) |
return GL_FALSE; |
} |
VB->ClipAndMask = store->andmask; |
VB->ClipOrMask = store->ormask; |
VB->ClipMask = store->clipmask; |
return GL_TRUE; |
} |
static GLboolean init_vertex_stage( struct gl_context *ctx, |
struct tnl_pipeline_stage *stage ) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
struct vertex_stage_data *store; |
GLuint size = VB->Size; |
stage->privatePtr = CALLOC(sizeof(*store)); |
store = VERTEX_STAGE_DATA(stage); |
if (!store) |
return GL_FALSE; |
_mesa_vector4f_alloc( &store->eye, 0, size, 32 ); |
_mesa_vector4f_alloc( &store->clip, 0, size, 32 ); |
_mesa_vector4f_alloc( &store->proj, 0, size, 32 ); |
store->clipmask = (GLubyte *) _mesa_align_malloc(sizeof(GLubyte)*size, 32 ); |
if (!store->clipmask || |
!store->eye.data || |
!store->clip.data || |
!store->proj.data) |
return GL_FALSE; |
return GL_TRUE; |
} |
static void dtr( struct tnl_pipeline_stage *stage ) |
{ |
struct vertex_stage_data *store = VERTEX_STAGE_DATA(stage); |
if (store) { |
_mesa_vector4f_free( &store->eye ); |
_mesa_vector4f_free( &store->clip ); |
_mesa_vector4f_free( &store->proj ); |
_mesa_align_free( store->clipmask ); |
FREE(store); |
stage->privatePtr = NULL; |
stage->run = init_vertex_stage; |
} |
} |
const struct tnl_pipeline_stage _tnl_vertex_transform_stage = |
{ |
"modelview/project/cliptest/divide", |
NULL, /* private data */ |
init_vertex_stage, |
dtr, /* destructor */ |
NULL, |
run_vertex_stage /* run -- initially set to init */ |
}; |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vertex.c |
---|
0,0 → 1,564 |
/* |
* Copyright 2003 Tungsten Graphics, inc. |
* 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 |
* on the rights to use, copy, modify, merge, publish, distribute, sub |
* license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL |
* TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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: |
* Keith Whitwell <keithw@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/context.h" |
#include "main/colormac.h" |
#include "t_context.h" |
#include "t_vertex.h" |
#define DBG 0 |
/* Build and manage clipspace/ndc/window vertices. |
*/ |
static GLboolean match_fastpath( struct tnl_clipspace *vtx, |
const struct tnl_clipspace_fastpath *fp) |
{ |
GLuint j; |
if (vtx->attr_count != fp->attr_count) |
return GL_FALSE; |
for (j = 0; j < vtx->attr_count; j++) |
if (vtx->attr[j].format != fp->attr[j].format || |
vtx->attr[j].inputsize != fp->attr[j].size || |
vtx->attr[j].vertoffset != fp->attr[j].offset) |
return GL_FALSE; |
if (fp->match_strides) { |
if (vtx->vertex_size != fp->vertex_size) |
return GL_FALSE; |
for (j = 0; j < vtx->attr_count; j++) |
if (vtx->attr[j].inputstride != fp->attr[j].stride) |
return GL_FALSE; |
} |
return GL_TRUE; |
} |
static GLboolean search_fastpath_emit( struct tnl_clipspace *vtx ) |
{ |
struct tnl_clipspace_fastpath *fp = vtx->fastpath; |
for ( ; fp ; fp = fp->next) { |
if (match_fastpath(vtx, fp)) { |
vtx->emit = fp->func; |
return GL_TRUE; |
} |
} |
return GL_FALSE; |
} |
void _tnl_register_fastpath( struct tnl_clipspace *vtx, |
GLboolean match_strides ) |
{ |
struct tnl_clipspace_fastpath *fastpath = CALLOC_STRUCT(tnl_clipspace_fastpath); |
GLuint i; |
fastpath->vertex_size = vtx->vertex_size; |
fastpath->attr_count = vtx->attr_count; |
fastpath->match_strides = match_strides; |
fastpath->func = vtx->emit; |
fastpath->attr = (struct tnl_attr_type *) |
malloc(vtx->attr_count * sizeof(fastpath->attr[0])); |
for (i = 0; i < vtx->attr_count; i++) { |
fastpath->attr[i].format = vtx->attr[i].format; |
fastpath->attr[i].stride = vtx->attr[i].inputstride; |
fastpath->attr[i].size = vtx->attr[i].inputsize; |
fastpath->attr[i].offset = vtx->attr[i].vertoffset; |
} |
fastpath->next = vtx->fastpath; |
vtx->fastpath = fastpath; |
} |
/*********************************************************************** |
* Build codegen functions or return generic ones: |
*/ |
static void choose_emit_func( struct gl_context *ctx, GLuint count, GLubyte *dest) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
struct tnl_clipspace_attr *a = vtx->attr; |
const GLuint attr_count = vtx->attr_count; |
GLuint j; |
for (j = 0; j < attr_count; j++) { |
GLvector4f *vptr = VB->AttribPtr[a[j].attrib]; |
a[j].inputstride = vptr->stride; |
a[j].inputsize = vptr->size; |
a[j].emit = a[j].insert[vptr->size - 1]; /* not always used */ |
} |
vtx->emit = NULL; |
/* Does this match an existing (hardwired, codegen or known-bad) |
* fastpath? |
*/ |
if (search_fastpath_emit(vtx)) { |
/* Use this result. If it is null, then it is already known |
* that the current state will fail for codegen and there is no |
* point trying again. |
*/ |
} |
else if (vtx->codegen_emit) { |
vtx->codegen_emit(ctx); |
} |
if (!vtx->emit) { |
_tnl_generate_hardwired_emit(ctx); |
} |
/* Otherwise use the generic version: |
*/ |
if (!vtx->emit) |
vtx->emit = _tnl_generic_emit; |
vtx->emit( ctx, count, dest ); |
} |
static void choose_interp_func( struct gl_context *ctx, |
GLfloat t, |
GLuint edst, GLuint eout, GLuint ein, |
GLboolean force_boundary ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
if (vtx->need_extras && |
(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) { |
vtx->interp = _tnl_generic_interp_extras; |
} else { |
vtx->interp = _tnl_generic_interp; |
} |
vtx->interp( ctx, t, edst, eout, ein, force_boundary ); |
} |
static void choose_copy_pv_func( struct gl_context *ctx, GLuint edst, GLuint esrc ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
if (vtx->need_extras && |
(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) { |
vtx->copy_pv = _tnl_generic_copy_pv_extras; |
} else { |
vtx->copy_pv = _tnl_generic_copy_pv; |
} |
vtx->copy_pv( ctx, edst, esrc ); |
} |
/*********************************************************************** |
* Public entrypoints, mostly dispatch to the above: |
*/ |
/* Interpolate between two vertices to produce a third: |
*/ |
void _tnl_interp( struct gl_context *ctx, |
GLfloat t, |
GLuint edst, GLuint eout, GLuint ein, |
GLboolean force_boundary ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
vtx->interp( ctx, t, edst, eout, ein, force_boundary ); |
} |
/* Copy colors from one vertex to another: |
*/ |
void _tnl_copy_pv( struct gl_context *ctx, GLuint edst, GLuint esrc ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
vtx->copy_pv( ctx, edst, esrc ); |
} |
/* Extract a named attribute from a hardware vertex. Will have to |
* reverse any viewport transformation, swizzling or other conversions |
* which may have been applied: |
*/ |
void _tnl_get_attr( struct gl_context *ctx, const void *vin, |
GLenum attr, GLfloat *dest ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
const struct tnl_clipspace_attr *a = vtx->attr; |
const GLuint attr_count = vtx->attr_count; |
GLuint j; |
for (j = 0; j < attr_count; j++) { |
if (a[j].attrib == attr) { |
a[j].extract( &a[j], dest, (GLubyte *)vin + a[j].vertoffset ); |
return; |
} |
} |
/* Else return the value from ctx->Current. |
*/ |
if (attr == _TNL_ATTRIB_POINTSIZE) { |
/* If the hardware vertex doesn't have point size then use size from |
* struct gl_context. XXX this will be wrong if drawing attenuated points! |
*/ |
dest[0] = ctx->Point.Size; |
} |
else { |
memcpy( dest, ctx->Current.Attrib[attr], 4*sizeof(GLfloat)); |
} |
} |
/* Complementary operation to the above. |
*/ |
void _tnl_set_attr( struct gl_context *ctx, void *vout, |
GLenum attr, const GLfloat *src ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
const struct tnl_clipspace_attr *a = vtx->attr; |
const GLuint attr_count = vtx->attr_count; |
GLuint j; |
for (j = 0; j < attr_count; j++) { |
if (a[j].attrib == attr) { |
a[j].insert[4-1]( &a[j], (GLubyte *)vout + a[j].vertoffset, src ); |
return; |
} |
} |
} |
void *_tnl_get_vertex( struct gl_context *ctx, GLuint nr ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
return vtx->vertex_buf + nr * vtx->vertex_size; |
} |
void _tnl_invalidate_vertex_state( struct gl_context *ctx, GLuint new_state ) |
{ |
if (new_state & (_DD_NEW_TRI_LIGHT_TWOSIDE|_DD_NEW_TRI_UNFILLED) ) { |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
vtx->new_inputs = ~0; |
vtx->interp = choose_interp_func; |
vtx->copy_pv = choose_copy_pv_func; |
} |
} |
static void invalidate_funcs( struct tnl_clipspace *vtx ) |
{ |
vtx->emit = choose_emit_func; |
vtx->interp = choose_interp_func; |
vtx->copy_pv = choose_copy_pv_func; |
vtx->new_inputs = ~0; |
} |
GLuint _tnl_install_attrs( struct gl_context *ctx, const struct tnl_attr_map *map, |
GLuint nr, const GLfloat *vp, |
GLuint unpacked_size ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
GLuint offset = 0; |
GLuint i, j; |
assert(nr < _TNL_ATTRIB_MAX); |
assert(nr == 0 || map[0].attrib == VERT_ATTRIB_POS); |
vtx->new_inputs = ~0; |
vtx->need_viewport = GL_FALSE; |
if (vp) { |
vtx->need_viewport = GL_TRUE; |
} |
for (j = 0, i = 0; i < nr; i++) { |
const GLuint format = map[i].format; |
if (format == EMIT_PAD) { |
if (DBG) |
printf("%d: pad %d, offset %d\n", i, |
map[i].offset, offset); |
offset += map[i].offset; |
} |
else { |
GLuint tmpoffset; |
if (unpacked_size) |
tmpoffset = map[i].offset; |
else |
tmpoffset = offset; |
if (vtx->attr_count != j || |
vtx->attr[j].attrib != map[i].attrib || |
vtx->attr[j].format != format || |
vtx->attr[j].vertoffset != tmpoffset) { |
invalidate_funcs(vtx); |
vtx->attr[j].attrib = map[i].attrib; |
vtx->attr[j].format = format; |
vtx->attr[j].vp = vp; |
vtx->attr[j].insert = _tnl_format_info[format].insert; |
vtx->attr[j].extract = _tnl_format_info[format].extract; |
vtx->attr[j].vertattrsize = _tnl_format_info[format].attrsize; |
vtx->attr[j].vertoffset = tmpoffset; |
} |
if (DBG) |
printf("%d: %s, vp %p, offset %d\n", i, |
_tnl_format_info[format].name, (void *)vp, |
vtx->attr[j].vertoffset); |
offset += _tnl_format_info[format].attrsize; |
j++; |
} |
} |
vtx->attr_count = j; |
if (unpacked_size) |
vtx->vertex_size = unpacked_size; |
else |
vtx->vertex_size = offset; |
assert(vtx->vertex_size <= vtx->max_vertex_size); |
return vtx->vertex_size; |
} |
void _tnl_invalidate_vertices( struct gl_context *ctx, GLuint newinputs ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
vtx->new_inputs |= newinputs; |
} |
/* This event has broader use beyond this file - will move elsewhere |
* and probably invoke a driver callback. |
*/ |
void _tnl_notify_pipeline_output_change( struct gl_context *ctx ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
invalidate_funcs(vtx); |
} |
static void adjust_input_ptrs( struct gl_context *ctx, GLint diff) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
struct tnl_clipspace_attr *a = vtx->attr; |
const GLuint count = vtx->attr_count; |
GLuint j; |
diff -= 1; |
for (j=0; j<count; ++j) { |
register GLvector4f *vptr = VB->AttribPtr[a->attrib]; |
(a++)->inputptr += diff*vptr->stride; |
} |
} |
static void update_input_ptrs( struct gl_context *ctx, GLuint start ) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
struct tnl_clipspace_attr *a = vtx->attr; |
const GLuint count = vtx->attr_count; |
GLuint j; |
for (j = 0; j < count; j++) { |
GLvector4f *vptr = VB->AttribPtr[a[j].attrib]; |
if (vtx->emit != choose_emit_func) { |
assert(a[j].inputstride == vptr->stride); |
assert(a[j].inputsize == vptr->size); |
} |
a[j].inputptr = ((GLubyte *)vptr->data) + start * vptr->stride; |
} |
if (a->vp) { |
vtx->vp_scale[0] = a->vp[MAT_SX]; |
vtx->vp_scale[1] = a->vp[MAT_SY]; |
vtx->vp_scale[2] = a->vp[MAT_SZ]; |
vtx->vp_scale[3] = 1.0; |
vtx->vp_xlate[0] = a->vp[MAT_TX]; |
vtx->vp_xlate[1] = a->vp[MAT_TY]; |
vtx->vp_xlate[2] = a->vp[MAT_TZ]; |
vtx->vp_xlate[3] = 0.0; |
} |
} |
void _tnl_build_vertices( struct gl_context *ctx, |
GLuint start, |
GLuint end, |
GLuint newinputs ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
update_input_ptrs( ctx, start ); |
vtx->emit( ctx, end - start, |
(GLubyte *)(vtx->vertex_buf + |
start * vtx->vertex_size)); |
} |
/* Emit VB vertices start..end to dest. Note that VB vertex at |
* postion start will be emitted to dest at position zero. |
*/ |
void *_tnl_emit_vertices_to_buffer( struct gl_context *ctx, |
GLuint start, |
GLuint end, |
void *dest ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
update_input_ptrs(ctx, start); |
/* Note: dest should not be adjusted for non-zero 'start' values: |
*/ |
vtx->emit( ctx, end - start, (GLubyte*) dest ); |
return (void *)((GLubyte *)dest + vtx->vertex_size * (end - start)); |
} |
/* Emit indexed VB vertices start..end to dest. Note that VB vertex at |
* postion start will be emitted to dest at position zero. |
*/ |
void *_tnl_emit_indexed_vertices_to_buffer( struct gl_context *ctx, |
const GLuint *elts, |
GLuint start, |
GLuint end, |
void *dest ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
GLuint oldIndex; |
GLubyte *cdest = dest; |
update_input_ptrs(ctx, oldIndex = elts[start++]); |
vtx->emit( ctx, 1, cdest ); |
cdest += vtx->vertex_size; |
for (; start < end; ++start) { |
adjust_input_ptrs(ctx, elts[start] - oldIndex); |
oldIndex = elts[start]; |
vtx->emit( ctx, 1, cdest); |
cdest += vtx->vertex_size; |
} |
return (void *) cdest; |
} |
void _tnl_init_vertices( struct gl_context *ctx, |
GLuint vb_size, |
GLuint max_vertex_size ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
_tnl_install_attrs( ctx, NULL, 0, NULL, 0 ); |
vtx->need_extras = GL_TRUE; |
if (max_vertex_size > vtx->max_vertex_size) { |
_tnl_free_vertices( ctx ); |
vtx->max_vertex_size = max_vertex_size; |
vtx->vertex_buf = (GLubyte *)_mesa_align_calloc(vb_size * max_vertex_size, 32 ); |
invalidate_funcs(vtx); |
} |
switch(CHAN_TYPE) { |
case GL_UNSIGNED_BYTE: |
vtx->chan_scale[0] = 255.0; |
vtx->chan_scale[1] = 255.0; |
vtx->chan_scale[2] = 255.0; |
vtx->chan_scale[3] = 255.0; |
break; |
case GL_UNSIGNED_SHORT: |
vtx->chan_scale[0] = 65535.0; |
vtx->chan_scale[1] = 65535.0; |
vtx->chan_scale[2] = 65535.0; |
vtx->chan_scale[3] = 65535.0; |
break; |
default: |
vtx->chan_scale[0] = 1.0; |
vtx->chan_scale[1] = 1.0; |
vtx->chan_scale[2] = 1.0; |
vtx->chan_scale[3] = 1.0; |
break; |
} |
vtx->identity[0] = 0.0; |
vtx->identity[1] = 0.0; |
vtx->identity[2] = 0.0; |
vtx->identity[3] = 1.0; |
vtx->codegen_emit = NULL; |
#ifdef USE_SSE_ASM |
if (!_mesa_getenv("MESA_NO_CODEGEN")) |
vtx->codegen_emit = _tnl_generate_sse_emit; |
#endif |
} |
void _tnl_free_vertices( struct gl_context *ctx ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
if (tnl) { |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
struct tnl_clipspace_fastpath *fp, *tmp; |
if (vtx->vertex_buf) { |
_mesa_align_free(vtx->vertex_buf); |
vtx->vertex_buf = NULL; |
} |
for (fp = vtx->fastpath ; fp ; fp = tmp) { |
tmp = fp->next; |
FREE(fp->attr); |
/* KW: At the moment, fp->func is constrained to be allocated by |
* _mesa_exec_alloc(), as the hardwired fastpaths in |
* t_vertex_generic.c are handled specially. It would be nice |
* to unify them, but this probably won't change until this |
* module gets another overhaul. |
*/ |
_mesa_exec_free((void *) fp->func); |
FREE(fp); |
} |
vtx->fastpath = NULL; |
} |
} |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vertex.h |
---|
0,0 → 1,181 |
/* |
* Copyright 2003 Tungsten Graphics, inc. |
* 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 |
* on the rights to use, copy, modify, merge, publish, distribute, sub |
* license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL |
* TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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: |
* Keith Whitwell <keithw@tungstengraphics.com> |
*/ |
#ifndef _TNL_VERTEX_H |
#define _TNL_VERTEX_H |
#include "main/mtypes.h" |
#include "t_context.h" |
/* New mechanism to specify hardware vertices so that tnl can build |
* and manipulate them directly. |
*/ |
/* It will probably be necessary to allow drivers to specify new |
* emit-styles to cover all the wierd and wacky things out there. |
*/ |
enum tnl_attr_format { |
EMIT_1F, |
EMIT_2F, |
EMIT_3F, |
EMIT_4F, |
EMIT_2F_VIEWPORT, /* do viewport transform and emit */ |
EMIT_3F_VIEWPORT, /* do viewport transform and emit */ |
EMIT_4F_VIEWPORT, /* do viewport transform and emit */ |
EMIT_3F_XYW, /* for projective texture */ |
EMIT_1UB_1F, /* for fog coordinate */ |
EMIT_3UB_3F_RGB, /* for specular color */ |
EMIT_3UB_3F_BGR, /* for specular color */ |
EMIT_4UB_4F_RGBA, /* for color */ |
EMIT_4UB_4F_BGRA, /* for color */ |
EMIT_4UB_4F_ARGB, /* for color */ |
EMIT_4UB_4F_ABGR, /* for color */ |
EMIT_4CHAN_4F_RGBA, /* for swrast color */ |
EMIT_PAD, /* leave a hole of 'offset' bytes */ |
EMIT_MAX |
}; |
struct tnl_attr_map { |
GLuint attrib; /* _TNL_ATTRIB_ enum */ |
enum tnl_attr_format format; |
GLuint offset; |
}; |
struct tnl_format_info { |
const char *name; |
tnl_extract_func extract; |
tnl_insert_func insert[4]; |
const GLuint attrsize; |
}; |
extern const struct tnl_format_info _tnl_format_info[EMIT_MAX]; |
/* Interpolate between two vertices to produce a third: |
*/ |
extern void _tnl_interp( struct gl_context *ctx, |
GLfloat t, |
GLuint edst, GLuint eout, GLuint ein, |
GLboolean force_boundary ); |
/* Copy colors from one vertex to another: |
*/ |
extern void _tnl_copy_pv( struct gl_context *ctx, GLuint edst, GLuint esrc ); |
/* Extract a named attribute from a hardware vertex. Will have to |
* reverse any viewport transformation, swizzling or other conversions |
* which may have been applied: |
*/ |
extern void _tnl_get_attr( struct gl_context *ctx, const void *vertex, GLenum attrib, |
GLfloat *dest ); |
/* Complementary to the above. |
*/ |
extern void _tnl_set_attr( struct gl_context *ctx, void *vout, GLenum attrib, |
const GLfloat *src ); |
extern void *_tnl_get_vertex( struct gl_context *ctx, GLuint nr ); |
extern GLuint _tnl_install_attrs( struct gl_context *ctx, |
const struct tnl_attr_map *map, |
GLuint nr, const GLfloat *vp, |
GLuint unpacked_size ); |
extern void _tnl_free_vertices( struct gl_context *ctx ); |
extern void _tnl_init_vertices( struct gl_context *ctx, |
GLuint vb_size, |
GLuint max_vertex_size ); |
extern void *_tnl_emit_vertices_to_buffer( struct gl_context *ctx, |
GLuint start, |
GLuint end, |
void *dest ); |
/* This function isn't optimal. Check out |
* gallium/auxilary/translate for a more comprehensive implementation of |
* the same functionality. |
*/ |
extern void *_tnl_emit_indexed_vertices_to_buffer( struct gl_context *ctx, |
const GLuint *elts, |
GLuint start, |
GLuint end, |
void *dest ); |
extern void _tnl_build_vertices( struct gl_context *ctx, |
GLuint start, |
GLuint end, |
GLuint newinputs ); |
extern void _tnl_invalidate_vertices( struct gl_context *ctx, GLuint newinputs ); |
extern void _tnl_invalidate_vertex_state( struct gl_context *ctx, GLuint new_state ); |
extern void _tnl_notify_pipeline_output_change( struct gl_context *ctx ); |
#define GET_VERTEX_STATE(ctx) &(TNL_CONTEXT(ctx)->clipspace) |
/* Internal function: |
*/ |
void _tnl_register_fastpath( struct tnl_clipspace *vtx, |
GLboolean match_strides ); |
/* t_vertex_generic.c -- Internal functions for t_vertex.c |
*/ |
void _tnl_generic_copy_pv_extras( struct gl_context *ctx, |
GLuint dst, GLuint src ); |
void _tnl_generic_interp_extras( struct gl_context *ctx, |
GLfloat t, |
GLuint dst, GLuint out, GLuint in, |
GLboolean force_boundary ); |
void _tnl_generic_copy_pv( struct gl_context *ctx, GLuint edst, GLuint esrc ); |
void _tnl_generic_interp( struct gl_context *ctx, |
GLfloat t, |
GLuint edst, GLuint eout, GLuint ein, |
GLboolean force_boundary ); |
void _tnl_generic_emit( struct gl_context *ctx, |
GLuint count, |
GLubyte *v ); |
void _tnl_generate_hardwired_emit( struct gl_context *ctx ); |
/* t_vertex_sse.c -- Internal functions for t_vertex.c |
*/ |
void _tnl_generate_sse_emit( struct gl_context *ctx ); |
#endif |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vertex_generic.c |
---|
0,0 → 1,1155 |
/* |
* Copyright 2003 Tungsten Graphics, inc. |
* 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 |
* on the rights to use, copy, modify, merge, publish, distribute, sub |
* license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL |
* TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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: |
* Keith Whitwell <keithw@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/context.h" |
#include "main/colormac.h" |
#include "main/simple_list.h" |
#include "t_context.h" |
#include "t_vertex.h" |
#if 0 |
#define DEBUG_INSERT printf("%s\n", __FUNCTION__) |
#else |
#define DEBUG_INSERT |
#endif |
/* |
* These functions take the NDC coordinates pointed to by 'in', apply the |
* NDC->Viewport mapping and store the results at 'v'. |
*/ |
static INLINE void insert_4f_viewport_4( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = vp[0] * in[0] + vp[12]; |
out[1] = vp[5] * in[1] + vp[13]; |
out[2] = vp[10] * in[2] + vp[14]; |
out[3] = in[3]; |
} |
static INLINE void insert_4f_viewport_3( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = vp[0] * in[0] + vp[12]; |
out[1] = vp[5] * in[1] + vp[13]; |
out[2] = vp[10] * in[2] + vp[14]; |
out[3] = 1; |
} |
static INLINE void insert_4f_viewport_2( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = vp[0] * in[0] + vp[12]; |
out[1] = vp[5] * in[1] + vp[13]; |
out[2] = vp[14]; |
out[3] = 1; |
} |
static INLINE void insert_4f_viewport_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = vp[0] * in[0] + vp[12]; |
out[1] = vp[13]; |
out[2] = vp[14]; |
out[3] = 1; |
} |
static INLINE void insert_3f_viewport_3( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = vp[0] * in[0] + vp[12]; |
out[1] = vp[5] * in[1] + vp[13]; |
out[2] = vp[10] * in[2] + vp[14]; |
} |
static INLINE void insert_3f_viewport_2( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = vp[0] * in[0] + vp[12]; |
out[1] = vp[5] * in[1] + vp[13]; |
out[2] = vp[14]; |
} |
static INLINE void insert_3f_viewport_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = vp[0] * in[0] + vp[12]; |
out[1] = vp[13]; |
out[2] = vp[14]; |
} |
static INLINE void insert_2f_viewport_2( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = vp[0] * in[0] + vp[12]; |
out[1] = vp[5] * in[1] + vp[13]; |
} |
static INLINE void insert_2f_viewport_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = vp[0] * in[0] + vp[12]; |
out[1] = vp[13]; |
} |
/* |
* These functions do the same as above, except for the viewport mapping. |
*/ |
static INLINE void insert_4f_4( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
out[1] = in[1]; |
out[2] = in[2]; |
out[3] = in[3]; |
} |
static INLINE void insert_4f_3( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
out[1] = in[1]; |
out[2] = in[2]; |
out[3] = 1; |
} |
static INLINE void insert_4f_2( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
out[1] = in[1]; |
out[2] = 0; |
out[3] = 1; |
} |
static INLINE void insert_4f_1( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
out[1] = 0; |
out[2] = 0; |
out[3] = 1; |
} |
static INLINE void insert_3f_xyw_4( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
out[1] = in[1]; |
out[2] = in[3]; |
} |
static INLINE void insert_3f_xyw_err( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
(void) a; (void) v; (void) in; |
DEBUG_INSERT; |
exit(1); |
} |
static INLINE void insert_3f_3( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
out[1] = in[1]; |
out[2] = in[2]; |
} |
static INLINE void insert_3f_2( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
out[1] = in[1]; |
out[2] = 0; |
} |
static INLINE void insert_3f_1( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
out[1] = 0; |
out[2] = 0; |
} |
static INLINE void insert_2f_2( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
out[1] = in[1]; |
} |
static INLINE void insert_2f_1( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
out[1] = 0; |
} |
static INLINE void insert_1f_1( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
GLfloat *out = (GLfloat *)(v); |
(void) a; |
DEBUG_INSERT; |
out[0] = in[0]; |
} |
static INLINE void insert_null( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; (void) v; (void) in; |
} |
static INLINE void insert_4chan_4f_rgba_4( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLchan *c = (GLchan *)v; |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]); |
UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]); |
UNCLAMPED_FLOAT_TO_CHAN(c[2], in[2]); |
UNCLAMPED_FLOAT_TO_CHAN(c[3], in[3]); |
} |
static INLINE void insert_4chan_4f_rgba_3( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLchan *c = (GLchan *)v; |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]); |
UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]); |
UNCLAMPED_FLOAT_TO_CHAN(c[2], in[2]); |
c[3] = CHAN_MAX; |
} |
static INLINE void insert_4chan_4f_rgba_2( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLchan *c = (GLchan *)v; |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]); |
UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]); |
c[2] = 0; |
c[3] = CHAN_MAX; |
} |
static INLINE void insert_4chan_4f_rgba_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
GLchan *c = (GLchan *)v; |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]); |
c[1] = 0; |
c[2] = 0; |
c[3] = CHAN_MAX; |
} |
static INLINE void insert_4ub_4f_rgba_4( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]); |
} |
static INLINE void insert_4ub_4f_rgba_3( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]); |
v[3] = 0xff; |
} |
static INLINE void insert_4ub_4f_rgba_2( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); |
v[2] = 0; |
v[3] = 0xff; |
} |
static INLINE void insert_4ub_4f_rgba_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); |
v[1] = 0; |
v[2] = 0; |
v[3] = 0xff; |
} |
static INLINE void insert_4ub_4f_bgra_4( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]); |
} |
static INLINE void insert_4ub_4f_bgra_3( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]); |
v[3] = 0xff; |
} |
static INLINE void insert_4ub_4f_bgra_2( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); |
v[0] = 0; |
v[3] = 0xff; |
} |
static INLINE void insert_4ub_4f_bgra_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); |
v[1] = 0; |
v[0] = 0; |
v[3] = 0xff; |
} |
static INLINE void insert_4ub_4f_argb_4( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[2]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[3]); |
} |
static INLINE void insert_4ub_4f_argb_3( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[2]); |
v[0] = 0xff; |
} |
static INLINE void insert_4ub_4f_argb_2( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); |
v[3] = 0x00; |
v[0] = 0xff; |
} |
static INLINE void insert_4ub_4f_argb_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); |
v[2] = 0x00; |
v[3] = 0x00; |
v[0] = 0xff; |
} |
static INLINE void insert_4ub_4f_abgr_4( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[2]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[3]); |
} |
static INLINE void insert_4ub_4f_abgr_3( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[2]); |
v[0] = 0xff; |
} |
static INLINE void insert_4ub_4f_abgr_2( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); |
v[1] = 0x00; |
v[0] = 0xff; |
} |
static INLINE void insert_4ub_4f_abgr_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); |
v[2] = 0x00; |
v[1] = 0x00; |
v[0] = 0xff; |
} |
static INLINE void insert_3ub_3f_rgb_3( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]); |
} |
static INLINE void insert_3ub_3f_rgb_2( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); |
v[2] = 0; |
} |
static INLINE void insert_3ub_3f_rgb_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); |
v[1] = 0; |
v[2] = 0; |
} |
static INLINE void insert_3ub_3f_bgr_3( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]); |
} |
static INLINE void insert_3ub_3f_bgr_2( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); |
UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); |
v[0] = 0; |
} |
static INLINE void insert_3ub_3f_bgr_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); |
v[1] = 0; |
v[0] = 0; |
} |
static INLINE void insert_1ub_1f_1( const struct tnl_clipspace_attr *a, GLubyte *v, |
const GLfloat *in ) |
{ |
DEBUG_INSERT; |
(void) a; |
UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); |
} |
/*********************************************************************** |
* Functions to perform the reverse operations to the above, for |
* swrast translation and clip-interpolation. |
* |
* Currently always extracts a full 4 floats. |
*/ |
static void extract_4f_viewport( const struct tnl_clipspace_attr *a, GLfloat *out, |
const GLubyte *v ) |
{ |
const GLfloat *in = (const GLfloat *)v; |
const GLfloat * const vp = a->vp; |
/* Although included for completeness, the position coordinate is |
* usually handled differently during clipping. |
*/ |
DEBUG_INSERT; |
out[0] = (in[0] - vp[12]) / vp[0]; |
out[1] = (in[1] - vp[13]) / vp[5]; |
out[2] = (in[2] - vp[14]) / vp[10]; |
out[3] = in[3]; |
} |
static void extract_3f_viewport( const struct tnl_clipspace_attr *a, GLfloat *out, |
const GLubyte *v ) |
{ |
const GLfloat *in = (const GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = (in[0] - vp[12]) / vp[0]; |
out[1] = (in[1] - vp[13]) / vp[5]; |
out[2] = (in[2] - vp[14]) / vp[10]; |
out[3] = 1; |
} |
static void extract_2f_viewport( const struct tnl_clipspace_attr *a, GLfloat *out, |
const GLubyte *v ) |
{ |
const GLfloat *in = (const GLfloat *)v; |
const GLfloat * const vp = a->vp; |
DEBUG_INSERT; |
out[0] = (in[0] - vp[12]) / vp[0]; |
out[1] = (in[1] - vp[13]) / vp[5]; |
out[2] = 0; |
out[3] = 1; |
} |
static void extract_4f( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v ) |
{ |
const GLfloat *in = (const GLfloat *)v; |
(void) a; |
out[0] = in[0]; |
out[1] = in[1]; |
out[2] = in[2]; |
out[3] = in[3]; |
} |
static void extract_3f_xyw( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v ) |
{ |
const GLfloat *in = (const GLfloat *)v; |
(void) a; |
out[0] = in[0]; |
out[1] = in[1]; |
out[2] = 0; |
out[3] = in[2]; |
} |
static void extract_3f( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v ) |
{ |
const GLfloat *in = (const GLfloat *)v; |
(void) a; |
out[0] = in[0]; |
out[1] = in[1]; |
out[2] = in[2]; |
out[3] = 1; |
} |
static void extract_2f( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v ) |
{ |
const GLfloat *in = (const GLfloat *)v; |
(void) a; |
out[0] = in[0]; |
out[1] = in[1]; |
out[2] = 0; |
out[3] = 1; |
} |
static void extract_1f( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v ) |
{ |
const GLfloat *in = (const GLfloat *)v; |
(void) a; |
out[0] = in[0]; |
out[1] = 0; |
out[2] = 0; |
out[3] = 1; |
} |
static void extract_4chan_4f_rgba( const struct tnl_clipspace_attr *a, GLfloat *out, |
const GLubyte *v ) |
{ |
GLchan *c = (GLchan *)v; |
(void) a; |
out[0] = CHAN_TO_FLOAT(c[0]); |
out[1] = CHAN_TO_FLOAT(c[1]); |
out[2] = CHAN_TO_FLOAT(c[2]); |
out[3] = CHAN_TO_FLOAT(c[3]); |
} |
static void extract_4ub_4f_rgba( const struct tnl_clipspace_attr *a, GLfloat *out, |
const GLubyte *v ) |
{ |
(void) a; |
out[0] = UBYTE_TO_FLOAT(v[0]); |
out[1] = UBYTE_TO_FLOAT(v[1]); |
out[2] = UBYTE_TO_FLOAT(v[2]); |
out[3] = UBYTE_TO_FLOAT(v[3]); |
} |
static void extract_4ub_4f_bgra( const struct tnl_clipspace_attr *a, GLfloat *out, |
const GLubyte *v ) |
{ |
(void) a; |
out[2] = UBYTE_TO_FLOAT(v[0]); |
out[1] = UBYTE_TO_FLOAT(v[1]); |
out[0] = UBYTE_TO_FLOAT(v[2]); |
out[3] = UBYTE_TO_FLOAT(v[3]); |
} |
static void extract_4ub_4f_argb( const struct tnl_clipspace_attr *a, GLfloat *out, |
const GLubyte *v ) |
{ |
(void) a; |
out[3] = UBYTE_TO_FLOAT(v[0]); |
out[0] = UBYTE_TO_FLOAT(v[1]); |
out[1] = UBYTE_TO_FLOAT(v[2]); |
out[2] = UBYTE_TO_FLOAT(v[3]); |
} |
static void extract_4ub_4f_abgr( const struct tnl_clipspace_attr *a, GLfloat *out, |
const GLubyte *v ) |
{ |
(void) a; |
out[3] = UBYTE_TO_FLOAT(v[0]); |
out[2] = UBYTE_TO_FLOAT(v[1]); |
out[1] = UBYTE_TO_FLOAT(v[2]); |
out[0] = UBYTE_TO_FLOAT(v[3]); |
} |
static void extract_3ub_3f_rgb( const struct tnl_clipspace_attr *a, GLfloat *out, |
const GLubyte *v ) |
{ |
(void) a; |
out[0] = UBYTE_TO_FLOAT(v[0]); |
out[1] = UBYTE_TO_FLOAT(v[1]); |
out[2] = UBYTE_TO_FLOAT(v[2]); |
out[3] = 1; |
} |
static void extract_3ub_3f_bgr( const struct tnl_clipspace_attr *a, GLfloat *out, |
const GLubyte *v ) |
{ |
(void) a; |
out[2] = UBYTE_TO_FLOAT(v[0]); |
out[1] = UBYTE_TO_FLOAT(v[1]); |
out[0] = UBYTE_TO_FLOAT(v[2]); |
out[3] = 1; |
} |
static void extract_1ub_1f( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v ) |
{ |
(void) a; |
out[0] = UBYTE_TO_FLOAT(v[0]); |
out[1] = 0; |
out[2] = 0; |
out[3] = 1; |
} |
const struct tnl_format_info _tnl_format_info[EMIT_MAX] = |
{ |
{ "1f", |
extract_1f, |
{ insert_1f_1, insert_1f_1, insert_1f_1, insert_1f_1 }, |
sizeof(GLfloat) }, |
{ "2f", |
extract_2f, |
{ insert_2f_1, insert_2f_2, insert_2f_2, insert_2f_2 }, |
2 * sizeof(GLfloat) }, |
{ "3f", |
extract_3f, |
{ insert_3f_1, insert_3f_2, insert_3f_3, insert_3f_3 }, |
3 * sizeof(GLfloat) }, |
{ "4f", |
extract_4f, |
{ insert_4f_1, insert_4f_2, insert_4f_3, insert_4f_4 }, |
4 * sizeof(GLfloat) }, |
{ "2f_viewport", |
extract_2f_viewport, |
{ insert_2f_viewport_1, insert_2f_viewport_2, insert_2f_viewport_2, |
insert_2f_viewport_2 }, |
2 * sizeof(GLfloat) }, |
{ "3f_viewport", |
extract_3f_viewport, |
{ insert_3f_viewport_1, insert_3f_viewport_2, insert_3f_viewport_3, |
insert_3f_viewport_3 }, |
3 * sizeof(GLfloat) }, |
{ "4f_viewport", |
extract_4f_viewport, |
{ insert_4f_viewport_1, insert_4f_viewport_2, insert_4f_viewport_3, |
insert_4f_viewport_4 }, |
4 * sizeof(GLfloat) }, |
{ "3f_xyw", |
extract_3f_xyw, |
{ insert_3f_xyw_err, insert_3f_xyw_err, insert_3f_xyw_err, |
insert_3f_xyw_4 }, |
3 * sizeof(GLfloat) }, |
{ "1ub_1f", |
extract_1ub_1f, |
{ insert_1ub_1f_1, insert_1ub_1f_1, insert_1ub_1f_1, insert_1ub_1f_1 }, |
sizeof(GLubyte) }, |
{ "3ub_3f_rgb", |
extract_3ub_3f_rgb, |
{ insert_3ub_3f_rgb_1, insert_3ub_3f_rgb_2, insert_3ub_3f_rgb_3, |
insert_3ub_3f_rgb_3 }, |
3 * sizeof(GLubyte) }, |
{ "3ub_3f_bgr", |
extract_3ub_3f_bgr, |
{ insert_3ub_3f_bgr_1, insert_3ub_3f_bgr_2, insert_3ub_3f_bgr_3, |
insert_3ub_3f_bgr_3 }, |
3 * sizeof(GLubyte) }, |
{ "4ub_4f_rgba", |
extract_4ub_4f_rgba, |
{ insert_4ub_4f_rgba_1, insert_4ub_4f_rgba_2, insert_4ub_4f_rgba_3, |
insert_4ub_4f_rgba_4 }, |
4 * sizeof(GLubyte) }, |
{ "4ub_4f_bgra", |
extract_4ub_4f_bgra, |
{ insert_4ub_4f_bgra_1, insert_4ub_4f_bgra_2, insert_4ub_4f_bgra_3, |
insert_4ub_4f_bgra_4 }, |
4 * sizeof(GLubyte) }, |
{ "4ub_4f_argb", |
extract_4ub_4f_argb, |
{ insert_4ub_4f_argb_1, insert_4ub_4f_argb_2, insert_4ub_4f_argb_3, |
insert_4ub_4f_argb_4 }, |
4 * sizeof(GLubyte) }, |
{ "4ub_4f_abgr", |
extract_4ub_4f_abgr, |
{ insert_4ub_4f_abgr_1, insert_4ub_4f_abgr_2, insert_4ub_4f_abgr_3, |
insert_4ub_4f_abgr_4 }, |
4 * sizeof(GLubyte) }, |
{ "4chan_4f_rgba", |
extract_4chan_4f_rgba, |
{ insert_4chan_4f_rgba_1, insert_4chan_4f_rgba_2, insert_4chan_4f_rgba_3, |
insert_4chan_4f_rgba_4 }, |
4 * sizeof(GLchan) }, |
{ "pad", |
NULL, |
{ NULL, NULL, NULL, NULL }, |
0 } |
}; |
/*********************************************************************** |
* Hardwired fastpaths for emitting whole vertices or groups of |
* vertices |
*/ |
#define EMIT5(NR, F0, F1, F2, F3, F4, NAME) \ |
static void NAME( struct gl_context *ctx, \ |
GLuint count, \ |
GLubyte *v ) \ |
{ \ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); \ |
struct tnl_clipspace_attr *a = vtx->attr; \ |
GLuint i; \ |
\ |
for (i = 0 ; i < count ; i++, v += vtx->vertex_size) { \ |
if (NR > 0) { \ |
F0( &a[0], v + a[0].vertoffset, (GLfloat *)a[0].inputptr ); \ |
a[0].inputptr += a[0].inputstride; \ |
} \ |
\ |
if (NR > 1) { \ |
F1( &a[1], v + a[1].vertoffset, (GLfloat *)a[1].inputptr ); \ |
a[1].inputptr += a[1].inputstride; \ |
} \ |
\ |
if (NR > 2) { \ |
F2( &a[2], v + a[2].vertoffset, (GLfloat *)a[2].inputptr ); \ |
a[2].inputptr += a[2].inputstride; \ |
} \ |
\ |
if (NR > 3) { \ |
F3( &a[3], v + a[3].vertoffset, (GLfloat *)a[3].inputptr ); \ |
a[3].inputptr += a[3].inputstride; \ |
} \ |
\ |
if (NR > 4) { \ |
F4( &a[4], v + a[4].vertoffset, (GLfloat *)a[4].inputptr ); \ |
a[4].inputptr += a[4].inputstride; \ |
} \ |
} \ |
} |
#define EMIT2(F0, F1, NAME) EMIT5(2, F0, F1, insert_null, \ |
insert_null, insert_null, NAME) |
#define EMIT3(F0, F1, F2, NAME) EMIT5(3, F0, F1, F2, insert_null, \ |
insert_null, NAME) |
#define EMIT4(F0, F1, F2, F3, NAME) EMIT5(4, F0, F1, F2, F3, \ |
insert_null, NAME) |
EMIT2(insert_3f_viewport_3, insert_4ub_4f_rgba_4, emit_viewport3_rgba4) |
EMIT2(insert_3f_viewport_3, insert_4ub_4f_bgra_4, emit_viewport3_bgra4) |
EMIT2(insert_3f_3, insert_4ub_4f_rgba_4, emit_xyz3_rgba4) |
EMIT3(insert_4f_viewport_4, insert_4ub_4f_rgba_4, insert_2f_2, emit_viewport4_rgba4_st2) |
EMIT3(insert_4f_viewport_4, insert_4ub_4f_bgra_4, insert_2f_2, emit_viewport4_bgra4_st2) |
EMIT3(insert_4f_4, insert_4ub_4f_rgba_4, insert_2f_2, emit_xyzw4_rgba4_st2) |
EMIT4(insert_4f_viewport_4, insert_4ub_4f_rgba_4, insert_2f_2, insert_2f_2, emit_viewport4_rgba4_st2_st2) |
EMIT4(insert_4f_viewport_4, insert_4ub_4f_bgra_4, insert_2f_2, insert_2f_2, emit_viewport4_bgra4_st2_st2) |
EMIT4(insert_4f_4, insert_4ub_4f_rgba_4, insert_2f_2, insert_2f_2, emit_xyzw4_rgba4_st2_st2) |
/* Use the codegen paths to select one of a number of hardwired |
* fastpaths. |
*/ |
void _tnl_generate_hardwired_emit( struct gl_context *ctx ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
tnl_emit_func func = NULL; |
/* Does it fit a hardwired fastpath? Help! this is growing out of |
* control! |
*/ |
switch (vtx->attr_count) { |
case 2: |
if (vtx->attr[0].emit == insert_3f_viewport_3) { |
if (vtx->attr[1].emit == insert_4ub_4f_bgra_4) |
func = emit_viewport3_bgra4; |
else if (vtx->attr[1].emit == insert_4ub_4f_rgba_4) |
func = emit_viewport3_rgba4; |
} |
else if (vtx->attr[0].emit == insert_3f_3 && |
vtx->attr[1].emit == insert_4ub_4f_rgba_4) { |
func = emit_xyz3_rgba4; |
} |
break; |
case 3: |
if (vtx->attr[2].emit == insert_2f_2) { |
if (vtx->attr[1].emit == insert_4ub_4f_rgba_4) { |
if (vtx->attr[0].emit == insert_4f_viewport_4) |
func = emit_viewport4_rgba4_st2; |
else if (vtx->attr[0].emit == insert_4f_4) |
func = emit_xyzw4_rgba4_st2; |
} |
else if (vtx->attr[1].emit == insert_4ub_4f_bgra_4 && |
vtx->attr[0].emit == insert_4f_viewport_4) |
func = emit_viewport4_bgra4_st2; |
} |
break; |
case 4: |
if (vtx->attr[2].emit == insert_2f_2 && |
vtx->attr[3].emit == insert_2f_2) { |
if (vtx->attr[1].emit == insert_4ub_4f_rgba_4) { |
if (vtx->attr[0].emit == insert_4f_viewport_4) |
func = emit_viewport4_rgba4_st2_st2; |
else if (vtx->attr[0].emit == insert_4f_4) |
func = emit_xyzw4_rgba4_st2_st2; |
} |
else if (vtx->attr[1].emit == insert_4ub_4f_bgra_4 && |
vtx->attr[0].emit == insert_4f_viewport_4) |
func = emit_viewport4_bgra4_st2_st2; |
} |
break; |
} |
vtx->emit = func; |
} |
/*********************************************************************** |
* Generic (non-codegen) functions for whole vertices or groups of |
* vertices |
*/ |
void _tnl_generic_emit( struct gl_context *ctx, |
GLuint count, |
GLubyte *v ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
struct tnl_clipspace_attr *a = vtx->attr; |
const GLuint attr_count = vtx->attr_count; |
const GLuint stride = vtx->vertex_size; |
GLuint i, j; |
for (i = 0 ; i < count ; i++, v += stride) { |
for (j = 0; j < attr_count; j++) { |
GLfloat *in = (GLfloat *)a[j].inputptr; |
a[j].inputptr += a[j].inputstride; |
a[j].emit( &a[j], v + a[j].vertoffset, in ); |
} |
} |
} |
void _tnl_generic_interp( struct gl_context *ctx, |
GLfloat t, |
GLuint edst, GLuint eout, GLuint ein, |
GLboolean force_boundary ) |
{ |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct vertex_buffer *VB = &tnl->vb; |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
const GLubyte *vin = vtx->vertex_buf + ein * vtx->vertex_size; |
const GLubyte *vout = vtx->vertex_buf + eout * vtx->vertex_size; |
GLubyte *vdst = vtx->vertex_buf + edst * vtx->vertex_size; |
const struct tnl_clipspace_attr *a = vtx->attr; |
const GLuint attr_count = vtx->attr_count; |
GLuint j; |
(void) force_boundary; |
if (tnl->NeedNdcCoords) { |
const GLfloat *dstclip = VB->ClipPtr->data[edst]; |
if (dstclip[3] != 0.0) { |
const GLfloat w = 1.0f / dstclip[3]; |
GLfloat pos[4]; |
pos[0] = dstclip[0] * w; |
pos[1] = dstclip[1] * w; |
pos[2] = dstclip[2] * w; |
pos[3] = w; |
a[0].insert[4-1]( &a[0], vdst, pos ); |
} |
} |
else { |
a[0].insert[4-1]( &a[0], vdst, VB->ClipPtr->data[edst] ); |
} |
for (j = 1; j < attr_count; j++) { |
GLfloat fin[4], fout[4], fdst[4]; |
a[j].extract( &a[j], fin, vin + a[j].vertoffset ); |
a[j].extract( &a[j], fout, vout + a[j].vertoffset ); |
INTERP_F( t, fdst[3], fout[3], fin[3] ); |
INTERP_F( t, fdst[2], fout[2], fin[2] ); |
INTERP_F( t, fdst[1], fout[1], fin[1] ); |
INTERP_F( t, fdst[0], fout[0], fin[0] ); |
a[j].insert[4-1]( &a[j], vdst + a[j].vertoffset, fdst ); |
} |
} |
/* Extract color attributes from one vertex and insert them into |
* another. (Shortcircuit extract/insert with memcpy). |
*/ |
void _tnl_generic_copy_pv( struct gl_context *ctx, GLuint edst, GLuint esrc ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
GLubyte *vsrc = vtx->vertex_buf + esrc * vtx->vertex_size; |
GLubyte *vdst = vtx->vertex_buf + edst * vtx->vertex_size; |
const struct tnl_clipspace_attr *a = vtx->attr; |
const GLuint attr_count = vtx->attr_count; |
GLuint j; |
for (j = 0; j < attr_count; j++) { |
if (a[j].attrib == VERT_ATTRIB_COLOR0 || |
a[j].attrib == VERT_ATTRIB_COLOR1) { |
memcpy( vdst + a[j].vertoffset, |
vsrc + a[j].vertoffset, |
a[j].vertattrsize ); |
} |
} |
} |
/* Helper functions for hardware which doesn't put back colors and/or |
* edgeflags into vertices. |
*/ |
void _tnl_generic_interp_extras( struct gl_context *ctx, |
GLfloat t, |
GLuint dst, GLuint out, GLuint in, |
GLboolean force_boundary ) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
/* If stride is zero, BackfaceColorPtr is constant across the VB, so |
* there is no point interpolating between two values as they will |
* be identical. In all other cases, this value is generated by |
* t_vb_lighttmp.h and has a stride of 4 dwords. |
*/ |
if (VB->BackfaceColorPtr && VB->BackfaceColorPtr->stride) { |
assert(VB->BackfaceColorPtr->stride == 4 * sizeof(GLfloat)); |
INTERP_4F( t, |
VB->BackfaceColorPtr->data[dst], |
VB->BackfaceColorPtr->data[out], |
VB->BackfaceColorPtr->data[in] ); |
} |
if (VB->BackfaceSecondaryColorPtr) { |
assert(VB->BackfaceSecondaryColorPtr->stride == 4 * sizeof(GLfloat)); |
INTERP_3F( t, |
VB->BackfaceSecondaryColorPtr->data[dst], |
VB->BackfaceSecondaryColorPtr->data[out], |
VB->BackfaceSecondaryColorPtr->data[in] ); |
} |
if (VB->BackfaceIndexPtr) { |
VB->BackfaceIndexPtr->data[dst][0] = LINTERP( t, |
VB->BackfaceIndexPtr->data[out][0], |
VB->BackfaceIndexPtr->data[in][0] ); |
} |
if (VB->EdgeFlag) { |
VB->EdgeFlag[dst] = VB->EdgeFlag[out] || force_boundary; |
} |
_tnl_generic_interp(ctx, t, dst, out, in, force_boundary); |
} |
void _tnl_generic_copy_pv_extras( struct gl_context *ctx, |
GLuint dst, GLuint src ) |
{ |
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; |
/* See above comment: |
*/ |
if (VB->BackfaceColorPtr && VB->BackfaceColorPtr->stride) { |
COPY_4FV( VB->BackfaceColorPtr->data[dst], |
VB->BackfaceColorPtr->data[src] ); |
} |
if (VB->BackfaceSecondaryColorPtr) { |
COPY_4FV( VB->BackfaceSecondaryColorPtr->data[dst], |
VB->BackfaceSecondaryColorPtr->data[src] ); |
} |
if (VB->BackfaceIndexPtr) { |
VB->BackfaceIndexPtr->data[dst][0] = VB->BackfaceIndexPtr->data[src][0]; |
} |
_tnl_generic_copy_pv(ctx, dst, src); |
} |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vertex_sse.c |
---|
0,0 → 1,684 |
/* |
* Copyright 2003 Tungsten Graphics, inc. |
* 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 |
* on the rights to use, copy, modify, merge, publish, distribute, sub |
* license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL |
* TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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: |
* Keith Whitwell <keithw@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/context.h" |
#include "main/colormac.h" |
#include "main/simple_list.h" |
#include "main/enums.h" |
#include "t_context.h" |
#include "t_vertex.h" |
#if defined(USE_SSE_ASM) |
#include "x86/rtasm/x86sse.h" |
#include "x86/common_x86_asm.h" |
/** |
* Number of bytes to allocate for generated SSE functions |
*/ |
#define MAX_SSE_CODE_SIZE 1024 |
#define X 0 |
#define Y 1 |
#define Z 2 |
#define W 3 |
struct x86_program { |
struct x86_function func; |
struct gl_context *ctx; |
GLboolean inputs_safe; |
GLboolean outputs_safe; |
GLboolean have_sse2; |
struct x86_reg identity; |
struct x86_reg chan0; |
}; |
static struct x86_reg get_identity( struct x86_program *p ) |
{ |
return p->identity; |
} |
static void emit_load4f_4( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
sse_movups(&p->func, dest, arg0); |
} |
static void emit_load4f_3( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
/* Have to jump through some hoops: |
* |
* c 0 0 0 |
* c 0 0 1 |
* 0 0 c 1 |
* a b c 1 |
*/ |
sse_movss(&p->func, dest, x86_make_disp(arg0, 8)); |
sse_shufps(&p->func, dest, get_identity(p), SHUF(X,Y,Z,W) ); |
sse_shufps(&p->func, dest, dest, SHUF(Y,Z,X,W) ); |
sse_movlps(&p->func, dest, arg0); |
} |
static void emit_load4f_2( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
/* Initialize from identity, then pull in low two words: |
*/ |
sse_movups(&p->func, dest, get_identity(p)); |
sse_movlps(&p->func, dest, arg0); |
} |
static void emit_load4f_1( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
/* Pull in low word, then swizzle in identity */ |
sse_movss(&p->func, dest, arg0); |
sse_shufps(&p->func, dest, get_identity(p), SHUF(X,Y,Z,W) ); |
} |
static void emit_load3f_3( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
/* Over-reads by 1 dword - potential SEGV if input is a vertex |
* array. |
*/ |
if (p->inputs_safe) { |
sse_movups(&p->func, dest, arg0); |
} |
else { |
/* c 0 0 0 |
* c c c c |
* a b c c |
*/ |
sse_movss(&p->func, dest, x86_make_disp(arg0, 8)); |
sse_shufps(&p->func, dest, dest, SHUF(X,X,X,X)); |
sse_movlps(&p->func, dest, arg0); |
} |
} |
static void emit_load3f_2( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
emit_load4f_2(p, dest, arg0); |
} |
static void emit_load3f_1( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
/* Loading from memory erases the upper bits. */ |
sse_movss(&p->func, dest, arg0); |
} |
static void emit_load2f_2( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
sse_movlps(&p->func, dest, arg0); |
} |
static void emit_load2f_1( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
/* Loading from memory erases the upper bits. */ |
sse_movss(&p->func, dest, arg0); |
} |
static void emit_load1f_1( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
sse_movss(&p->func, dest, arg0); |
} |
static void (*load[4][4])( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) = { |
{ emit_load1f_1, |
emit_load1f_1, |
emit_load1f_1, |
emit_load1f_1 }, |
{ emit_load2f_1, |
emit_load2f_2, |
emit_load2f_2, |
emit_load2f_2 }, |
{ emit_load3f_1, |
emit_load3f_2, |
emit_load3f_3, |
emit_load3f_3 }, |
{ emit_load4f_1, |
emit_load4f_2, |
emit_load4f_3, |
emit_load4f_4 } |
}; |
static void emit_load( struct x86_program *p, |
struct x86_reg dest, |
GLuint sz, |
struct x86_reg src, |
GLuint src_sz) |
{ |
load[sz-1][src_sz-1](p, dest, src); |
} |
static void emit_store4f( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
sse_movups(&p->func, dest, arg0); |
} |
static void emit_store3f( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
if (p->outputs_safe) { |
/* Emit the extra dword anyway. This may hurt writecombining, |
* may cause other problems. |
*/ |
sse_movups(&p->func, dest, arg0); |
} |
else { |
/* Alternate strategy - emit two, shuffle, emit one. |
*/ |
sse_movlps(&p->func, dest, arg0); |
sse_shufps(&p->func, arg0, arg0, SHUF(Z,Z,Z,Z) ); /* NOTE! destructive */ |
sse_movss(&p->func, x86_make_disp(dest,8), arg0); |
} |
} |
static void emit_store2f( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
sse_movlps(&p->func, dest, arg0); |
} |
static void emit_store1f( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) |
{ |
sse_movss(&p->func, dest, arg0); |
} |
static void (*store[4])( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg arg0 ) = |
{ |
emit_store1f, |
emit_store2f, |
emit_store3f, |
emit_store4f |
}; |
static void emit_store( struct x86_program *p, |
struct x86_reg dest, |
GLuint sz, |
struct x86_reg temp ) |
{ |
store[sz-1](p, dest, temp); |
} |
static void emit_pack_store_4ub( struct x86_program *p, |
struct x86_reg dest, |
struct x86_reg temp ) |
{ |
/* Scale by 255.0 |
*/ |
sse_mulps(&p->func, temp, p->chan0); |
if (p->have_sse2) { |
sse2_cvtps2dq(&p->func, temp, temp); |
sse2_packssdw(&p->func, temp, temp); |
sse2_packuswb(&p->func, temp, temp); |
sse_movss(&p->func, dest, temp); |
} |
else { |
struct x86_reg mmx0 = x86_make_reg(file_MMX, 0); |
struct x86_reg mmx1 = x86_make_reg(file_MMX, 1); |
sse_cvtps2pi(&p->func, mmx0, temp); |
sse_movhlps(&p->func, temp, temp); |
sse_cvtps2pi(&p->func, mmx1, temp); |
mmx_packssdw(&p->func, mmx0, mmx1); |
mmx_packuswb(&p->func, mmx0, mmx0); |
mmx_movd(&p->func, dest, mmx0); |
} |
} |
static GLint get_offset( const void *a, const void *b ) |
{ |
return (const char *)b - (const char *)a; |
} |
/* Not much happens here. Eventually use this function to try and |
* avoid saving/reloading the source pointers each vertex (if some of |
* them can fit in registers). |
*/ |
static void get_src_ptr( struct x86_program *p, |
struct x86_reg srcREG, |
struct x86_reg vtxREG, |
struct tnl_clipspace_attr *a ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(p->ctx); |
struct x86_reg ptr_to_src = x86_make_disp(vtxREG, get_offset(vtx, &a->inputptr)); |
/* Load current a[j].inputptr |
*/ |
x86_mov(&p->func, srcREG, ptr_to_src); |
} |
static void update_src_ptr( struct x86_program *p, |
struct x86_reg srcREG, |
struct x86_reg vtxREG, |
struct tnl_clipspace_attr *a ) |
{ |
if (a->inputstride) { |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(p->ctx); |
struct x86_reg ptr_to_src = x86_make_disp(vtxREG, get_offset(vtx, &a->inputptr)); |
/* add a[j].inputstride (hardcoded value - could just as easily |
* pull the stride value from memory each time). |
*/ |
x86_lea(&p->func, srcREG, x86_make_disp(srcREG, a->inputstride)); |
/* save new value of a[j].inputptr |
*/ |
x86_mov(&p->func, ptr_to_src, srcREG); |
} |
} |
/* Lots of hardcoding |
* |
* EAX -- pointer to current output vertex |
* ECX -- pointer to current attribute |
* |
*/ |
static GLboolean build_vertex_emit( struct x86_program *p ) |
{ |
struct gl_context *ctx = p->ctx; |
TNLcontext *tnl = TNL_CONTEXT(ctx); |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
GLuint j = 0; |
struct x86_reg vertexEAX = x86_make_reg(file_REG32, reg_AX); |
struct x86_reg srcECX = x86_make_reg(file_REG32, reg_CX); |
struct x86_reg countEBP = x86_make_reg(file_REG32, reg_BP); |
struct x86_reg vtxESI = x86_make_reg(file_REG32, reg_SI); |
struct x86_reg temp = x86_make_reg(file_XMM, 0); |
struct x86_reg vp0 = x86_make_reg(file_XMM, 1); |
struct x86_reg vp1 = x86_make_reg(file_XMM, 2); |
struct x86_reg temp2 = x86_make_reg(file_XMM, 3); |
GLubyte *fixup, *label; |
/* Push a few regs? |
*/ |
x86_push(&p->func, countEBP); |
x86_push(&p->func, vtxESI); |
/* Get vertex count, compare to zero |
*/ |
x86_xor(&p->func, srcECX, srcECX); |
x86_mov(&p->func, countEBP, x86_fn_arg(&p->func, 2)); |
x86_cmp(&p->func, countEBP, srcECX); |
fixup = x86_jcc_forward(&p->func, cc_E); |
/* Initialize destination register. |
*/ |
x86_mov(&p->func, vertexEAX, x86_fn_arg(&p->func, 3)); |
/* Dereference ctx to get tnl, then vtx: |
*/ |
x86_mov(&p->func, vtxESI, x86_fn_arg(&p->func, 1)); |
x86_mov(&p->func, vtxESI, x86_make_disp(vtxESI, get_offset(ctx, &ctx->swtnl_context))); |
vtxESI = x86_make_disp(vtxESI, get_offset(tnl, &tnl->clipspace)); |
/* Possibly load vp0, vp1 for viewport calcs: |
*/ |
if (vtx->need_viewport) { |
sse_movups(&p->func, vp0, x86_make_disp(vtxESI, get_offset(vtx, &vtx->vp_scale[0]))); |
sse_movups(&p->func, vp1, x86_make_disp(vtxESI, get_offset(vtx, &vtx->vp_xlate[0]))); |
} |
/* always load, needed or not: |
*/ |
sse_movups(&p->func, p->chan0, x86_make_disp(vtxESI, get_offset(vtx, &vtx->chan_scale[0]))); |
sse_movups(&p->func, p->identity, x86_make_disp(vtxESI, get_offset(vtx, &vtx->identity[0]))); |
/* Note address for loop jump */ |
label = x86_get_label(&p->func); |
/* Emit code for each of the attributes. Currently routes |
* everything through SSE registers, even when it might be more |
* efficient to stick with regular old x86. No optimization or |
* other tricks - enough new ground to cover here just getting |
* things working. |
*/ |
while (j < vtx->attr_count) { |
struct tnl_clipspace_attr *a = &vtx->attr[j]; |
struct x86_reg dest = x86_make_disp(vertexEAX, a->vertoffset); |
/* Now, load an XMM reg from src, perhaps transform, then save. |
* Could be shortcircuited in specific cases: |
*/ |
switch (a->format) { |
case EMIT_1F: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 1, x86_deref(srcECX), a->inputsize); |
emit_store(p, dest, 1, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_2F: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize); |
emit_store(p, dest, 2, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_3F: |
/* Potentially the worst case - hardcode 2+1 copying: |
*/ |
if (0) { |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); |
emit_store(p, dest, 3, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
} |
else { |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize); |
emit_store(p, dest, 2, temp); |
if (a->inputsize > 2) { |
emit_load(p, temp, 1, x86_make_disp(srcECX, 8), 1); |
emit_store(p, x86_make_disp(dest,8), 1, temp); |
} |
else { |
sse_movss(&p->func, x86_make_disp(dest,8), get_identity(p)); |
} |
update_src_ptr(p, srcECX, vtxESI, a); |
} |
break; |
case EMIT_4F: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); |
emit_store(p, dest, 4, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_2F_VIEWPORT: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize); |
sse_mulps(&p->func, temp, vp0); |
sse_addps(&p->func, temp, vp1); |
emit_store(p, dest, 2, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_3F_VIEWPORT: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); |
sse_mulps(&p->func, temp, vp0); |
sse_addps(&p->func, temp, vp1); |
emit_store(p, dest, 3, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_4F_VIEWPORT: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); |
sse_mulps(&p->func, temp, vp0); |
sse_addps(&p->func, temp, vp1); |
emit_store(p, dest, 4, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_3F_XYW: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); |
sse_shufps(&p->func, temp, temp, SHUF(X,Y,W,Z)); |
emit_store(p, dest, 3, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_1UB_1F: |
/* Test for PAD3 + 1UB: |
*/ |
if (j > 0 && |
a[-1].vertoffset + a[-1].vertattrsize <= a->vertoffset - 3) |
{ |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 1, x86_deref(srcECX), a->inputsize); |
sse_shufps(&p->func, temp, temp, SHUF(X,X,X,X)); |
emit_pack_store_4ub(p, x86_make_disp(dest, -3), temp); /* overkill! */ |
update_src_ptr(p, srcECX, vtxESI, a); |
} |
else { |
printf("Can't emit 1ub %x %x %d\n", a->vertoffset, a[-1].vertoffset, a[-1].vertattrsize ); |
return GL_FALSE; |
} |
break; |
case EMIT_3UB_3F_RGB: |
case EMIT_3UB_3F_BGR: |
/* Test for 3UB + PAD1: |
*/ |
if (j == vtx->attr_count - 1 || |
a[1].vertoffset >= a->vertoffset + 4) { |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); |
if (a->format == EMIT_3UB_3F_BGR) |
sse_shufps(&p->func, temp, temp, SHUF(Z,Y,X,W)); |
emit_pack_store_4ub(p, dest, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
} |
/* Test for 3UB + 1UB: |
*/ |
else if (j < vtx->attr_count - 1 && |
a[1].format == EMIT_1UB_1F && |
a[1].vertoffset == a->vertoffset + 3) { |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); |
update_src_ptr(p, srcECX, vtxESI, a); |
/* Make room for incoming value: |
*/ |
sse_shufps(&p->func, temp, temp, SHUF(W,X,Y,Z)); |
get_src_ptr(p, srcECX, vtxESI, &a[1]); |
emit_load(p, temp2, 1, x86_deref(srcECX), a[1].inputsize); |
sse_movss(&p->func, temp, temp2); |
update_src_ptr(p, srcECX, vtxESI, &a[1]); |
/* Rearrange and possibly do BGR conversion: |
*/ |
if (a->format == EMIT_3UB_3F_BGR) |
sse_shufps(&p->func, temp, temp, SHUF(W,Z,Y,X)); |
else |
sse_shufps(&p->func, temp, temp, SHUF(Y,Z,W,X)); |
emit_pack_store_4ub(p, dest, temp); |
j++; /* NOTE: two attrs consumed */ |
} |
else { |
printf("Can't emit 3ub\n"); |
return GL_FALSE; /* add this later */ |
} |
break; |
case EMIT_4UB_4F_RGBA: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); |
emit_pack_store_4ub(p, dest, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_4UB_4F_BGRA: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); |
sse_shufps(&p->func, temp, temp, SHUF(Z,Y,X,W)); |
emit_pack_store_4ub(p, dest, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_4UB_4F_ARGB: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); |
sse_shufps(&p->func, temp, temp, SHUF(W,X,Y,Z)); |
emit_pack_store_4ub(p, dest, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_4UB_4F_ABGR: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); |
sse_shufps(&p->func, temp, temp, SHUF(W,Z,Y,X)); |
emit_pack_store_4ub(p, dest, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case EMIT_4CHAN_4F_RGBA: |
switch (CHAN_TYPE) { |
case GL_UNSIGNED_BYTE: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); |
emit_pack_store_4ub(p, dest, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case GL_FLOAT: |
get_src_ptr(p, srcECX, vtxESI, a); |
emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); |
emit_store(p, dest, 4, temp); |
update_src_ptr(p, srcECX, vtxESI, a); |
break; |
case GL_UNSIGNED_SHORT: |
default: |
printf("unknown CHAN_TYPE %s\n", _mesa_lookup_enum_by_nr(CHAN_TYPE)); |
return GL_FALSE; |
} |
break; |
default: |
printf("unknown a[%d].format %d\n", j, a->format); |
return GL_FALSE; /* catch any new opcodes */ |
} |
/* Increment j by at least 1 - may have been incremented above also: |
*/ |
j++; |
} |
/* Next vertex: |
*/ |
x86_lea(&p->func, vertexEAX, x86_make_disp(vertexEAX, vtx->vertex_size)); |
/* decr count, loop if not zero |
*/ |
x86_dec(&p->func, countEBP); |
x86_test(&p->func, countEBP, countEBP); |
x86_jcc(&p->func, cc_NZ, label); |
/* Exit mmx state? |
*/ |
if (p->func.need_emms) |
mmx_emms(&p->func); |
/* Land forward jump here: |
*/ |
x86_fixup_fwd_jump(&p->func, fixup); |
/* Pop regs and return |
*/ |
x86_pop(&p->func, x86_get_base_reg(vtxESI)); |
x86_pop(&p->func, countEBP); |
x86_ret(&p->func); |
assert(!vtx->emit); |
vtx->emit = (tnl_emit_func)x86_get_func(&p->func); |
assert( (char *) p->func.csr - (char *) p->func.store <= MAX_SSE_CODE_SIZE ); |
return GL_TRUE; |
} |
void _tnl_generate_sse_emit( struct gl_context *ctx ) |
{ |
struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx); |
struct x86_program p; |
if (!cpu_has_xmm) { |
vtx->codegen_emit = NULL; |
return; |
} |
memset(&p, 0, sizeof(p)); |
p.ctx = ctx; |
p.inputs_safe = 0; /* for now */ |
p.outputs_safe = 0; /* for now */ |
p.have_sse2 = cpu_has_xmm2; |
p.identity = x86_make_reg(file_XMM, 6); |
p.chan0 = x86_make_reg(file_XMM, 7); |
if (!x86_init_func_size(&p.func, MAX_SSE_CODE_SIZE)) { |
vtx->emit = NULL; |
return; |
} |
if (build_vertex_emit(&p)) { |
_tnl_register_fastpath( vtx, GL_TRUE ); |
} |
else { |
/* Note the failure so that we don't keep trying to codegen an |
* impossible state: |
*/ |
_tnl_register_fastpath( vtx, GL_FALSE ); |
x86_release_func(&p.func); |
} |
} |
#else |
void _tnl_generate_sse_emit( struct gl_context *ctx ) |
{ |
/* Dummy version for when USE_SSE_ASM not defined */ |
} |
#endif |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vp_build.c |
---|
0,0 → 1,60 |
/* |
* Mesa 3-D graphics library |
* Version: 7.1 |
* |
* Copyright (C) 2007 Tungsten Graphics 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 |
* TUNGSTEN GRAPHICS 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. |
*/ |
/** |
* \file t_vp_build.c |
* Create a vertex program to execute the current fixed function T&L pipeline. |
* \author Keith Whitwell |
*/ |
#include "main/glheader.h" |
#include "main/ffvertex_prog.h" |
#include "main/dd.h" |
#include "t_vp_build.h" |
/** |
* XXX This should go away someday, but still referenced by some drivers... |
*/ |
void _tnl_UpdateFixedFunctionProgram( struct gl_context *ctx ) |
{ |
const struct gl_vertex_program *prev = ctx->VertexProgram._Current; |
if (!ctx->VertexProgram._Current || |
ctx->VertexProgram._Current == ctx->VertexProgram._TnlProgram) { |
ctx->VertexProgram._Current |
= ctx->VertexProgram._TnlProgram |
= _mesa_get_fixed_func_vertex_program(ctx); |
} |
/* Tell the driver about the change. Could define a new target for |
* this? |
*/ |
if (ctx->VertexProgram._Current != prev && ctx->Driver.BindProgram) { |
ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB, |
(struct gl_program *) ctx->VertexProgram._Current); |
} |
} |
/programs/develop/libraries/Mesa/src/mesa/tnl/t_vp_build.h |
---|
0,0 → 1,42 |
/* |
* Mesa 3-D graphics library |
* Version: 6.3 |
* |
* Copyright (C) 2005 Tungsten Graphics 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 |
* TUNGSTEN GRAPHICS 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 T_VP_BUILD_H |
#define T_VP_BUILD_H |
#include "main/mtypes.h" |
#define TNL_FIXED_FUNCTION_STATE_FLAGS (_NEW_PROGRAM | \ |
_NEW_LIGHT | \ |
_NEW_TEXTURE | \ |
_NEW_TEXTURE_MATRIX | \ |
_NEW_TRANSFORM | \ |
_NEW_FOG | \ |
_NEW_POINT) |
extern void _tnl_UpdateFixedFunctionProgram( struct gl_context *ctx ); |
#endif |
/programs/develop/libraries/Mesa/src/mesa/tnl/tnl.h |
---|
0,0 → 1,100 |
/* |
* Mesa 3-D graphics library |
* Version: 7.1 |
* |
* Copyright (C) 1999-2007 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. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#ifndef _TNL_H |
#define _TNL_H |
#include "main/mtypes.h" |
/* These are the public-access functions exported from tnl. (A few |
* more are currently hooked into dispatch directly by the module |
* itself.) |
*/ |
extern GLboolean |
_tnl_CreateContext( struct gl_context *ctx ); |
extern void |
_tnl_DestroyContext( struct gl_context *ctx ); |
extern void |
_tnl_InvalidateState( struct gl_context *ctx, GLuint new_state ); |
/* Functions to revive the tnl module after being unhooked from |
* dispatch and/or driver callbacks. |
*/ |
extern void |
_tnl_wakeup( struct gl_context *ctx ); |
/* Driver configuration options: |
*/ |
extern void |
_tnl_need_projected_coords( struct gl_context *ctx, GLboolean flag ); |
/* Control whether T&L does per-vertex fog |
*/ |
extern void |
_tnl_allow_vertex_fog( struct gl_context *ctx, GLboolean value ); |
extern void |
_tnl_allow_pixel_fog( struct gl_context *ctx, GLboolean value ); |
extern GLboolean |
_tnl_program_string(struct gl_context *ctx, GLenum target, struct gl_program *program); |
struct _mesa_prim; |
struct _mesa_index_buffer; |
void |
_tnl_draw_prims( struct gl_context *ctx, |
const struct gl_client_array *arrays[], |
const struct _mesa_prim *prim, |
GLuint nr_prims, |
const struct _mesa_index_buffer *ib, |
GLuint min_index, |
GLuint max_index); |
void |
_tnl_vbo_draw_prims( struct gl_context *ctx, |
const struct gl_client_array *arrays[], |
const struct _mesa_prim *prim, |
GLuint nr_prims, |
const struct _mesa_index_buffer *ib, |
GLboolean index_bounds_valid, |
GLuint min_index, |
GLuint max_index); |
extern void |
_mesa_load_tracked_matrices(struct gl_context *ctx); |
extern void |
_tnl_RasterPos(struct gl_context *ctx, const GLfloat vObj[4]); |
#endif |
/programs/develop/libraries/Mesa/src/mesa/tnl/. |
---|
Property changes: |
Added: tsvn:logminsize |
+5 |
\ No newline at end of property |