summaryrefslogtreecommitdiffstats
path: root/src/mesa/main/rastpos.c
diff options
context:
space:
mode:
authorBrian Paul <[email protected]>2015-10-21 13:39:15 -0600
committerBrian Paul <[email protected]>2015-10-22 17:19:20 -0600
commit614a74376702b9f49343c9d71339cbb002971e6b (patch)
tree3698ae0e962ba1763264180e738808464cdea503 /src/mesa/main/rastpos.c
parent9919f560996cc0014df757cc542bf477c5402c00 (diff)
mesa: copy rasterpos evaluation code into core Mesa
We'll remove it from the tnl module next. By lifting this code into core Mesa we can use it from the gallium state tracker. Reviewed-by: Roland Scheidegger <[email protected]>
Diffstat (limited to 'src/mesa/main/rastpos.c')
-rw-r--r--src/mesa/main/rastpos.c441
1 files changed, 441 insertions, 0 deletions
diff --git a/src/mesa/main/rastpos.c b/src/mesa/main/rastpos.c
index 54b2125a80f..b468219e688 100644
--- a/src/mesa/main/rastpos.c
+++ b/src/mesa/main/rastpos.c
@@ -36,6 +36,447 @@
#include "rastpos.h"
#include "state.h"
#include "main/dispatch.h"
+#include "main/viewport.h"
+#include "util/simple_list.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. RGB 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)
+ */
+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 */
+
+ 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-6F) {
+ /* 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 {
+ GLfloat spot = powf(PV_dot_dir, light->SpotExponent);
+ attenuation *= spot;
+ }
+ }
+ }
+
+ if (attenuation < 1e-3F)
+ 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]);
+
+ /* 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 shine;
+ GLfloat spec_coef;
+
+ shine = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SHININESS][0];
+ spec_coef = powf(n_dot_h, shine);
+
+ if (spec_coef > 1.0e-10F) {
+ 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]);
+ }
+ }
+ }
+ }
+
+ 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 * (1.0f / 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().
+ *
+ * \param vObj vertex position in object space
+ */
+void
+_mesa_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];
+ float scale[3], translate[3];
+
+ /* 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) */
+ _mesa_get_viewport_xform(ctx, 0, scale, translate);
+ ctx->Current.RasterPos[0] = ndc[0] * scale[0] + translate[0];
+ ctx->Current.RasterPos[1] = ndc[1] * scale[1] + translate[1];
+ ctx->Current.RasterPos[2] = ndc[2] * scale[2] + translate[2];
+ ctx->Current.RasterPos[3] = clip[3];
+
+ if (ctx->Transform.DepthClamp) {
+ ctx->Current.RasterPos[3] = CLAMP(ctx->Current.RasterPos[3],
+ ctx->ViewportArray[0].Near,
+ ctx->ViewportArray[0].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] );
+ }
+}
/**