/** * Given the coordinates of the two opposite corners of a bounding box * in object space (x1,y1,z1) and (x2,y2,z2), use the given modelview * and projection matrices to transform the coordinates to NDC space. * Find the 3D bounding bounding box of those eight coordinates and * return the min/max in (x1,y1,x1) and (x2,y2,z2). */ void crProjectBBox(const GLfloat modl[16], const GLfloat proj[16], GLfloat *x1, GLfloat *y1, GLfloat *z1, GLfloat *x2, GLfloat *y2, GLfloat *z2) { CRmatrix m; /* compute product of modl and proj matrices */ m.m00 = proj[0] * modl[0] + proj[4] * modl[1] + proj[8] * modl[2] + proj[12] * modl[3]; m.m01 = proj[1] * modl[0] + proj[5] * modl[1] + proj[9] * modl[2] + proj[13] * modl[3]; m.m02 = proj[2] * modl[0] + proj[6] * modl[1] + proj[10] * modl[2] + proj[14] * modl[3]; m.m03 = proj[3] * modl[0] + proj[7] * modl[1] + proj[11] * modl[2] + proj[15] * modl[3]; m.m10 = proj[0] * modl[4] + proj[4] * modl[5] + proj[8] * modl[6] + proj[12] * modl[7]; m.m11 = proj[1] * modl[4] + proj[5] * modl[5] + proj[9] * modl[6] + proj[13] * modl[7]; m.m12 = proj[2] * modl[4] + proj[6] * modl[5] + proj[10] * modl[6] + proj[14] * modl[7]; m.m13 = proj[3] * modl[4] + proj[7] * modl[5] + proj[11] * modl[6] + proj[15] * modl[7]; m.m20 = proj[0] * modl[8] + proj[4] * modl[9] + proj[8] * modl[10] + proj[12] * modl[11]; m.m21 = proj[1] * modl[8] + proj[5] * modl[9] + proj[9] * modl[10] + proj[13] * modl[11]; m.m22 = proj[2] * modl[8] + proj[6] * modl[9] + proj[10] * modl[10] + proj[14] * modl[11]; m.m23 = proj[3] * modl[8] + proj[7] * modl[9] + proj[11] * modl[10] + proj[15] * modl[11]; m.m30 = proj[0] * modl[12] + proj[4] * modl[13] + proj[8] * modl[14] + proj[12] * modl[15]; m.m31 = proj[1] * modl[12] + proj[5] * modl[13] + proj[9] * modl[14] + proj[13] * modl[15]; m.m32 = proj[2] * modl[12] + proj[6] * modl[13] + proj[10] * modl[14] + proj[14] * modl[15]; m.m33 = proj[3] * modl[12] + proj[7] * modl[13] + proj[11] * modl[14] + proj[15] * modl[15]; crTransformBBox( *x1, *y1, *z1, *x2, *y2, *z2, &m, x1, y1, z1, x2, y2, z2 ); }
/** * Transform a bounding box from object space to NDC space. * This routine is used by most of the bucketing algorithms. * \param winInfo - which window/mural * \param server - which server (usually not needed) * \param objMin, objMax - bounds in object space * \param xmin, ymin, zmin, xmax, ymax, zmax - bounds in NDC * \param ibounds - bounds in screen coords * \return GL_TRUE if the resulting screen-space NDC bbox is visible, * GL_FALSE if the resulting screen-space NDC bbox is not visible. */ static GLboolean TransformBBox(const WindowInfo *winInfo, int server, const GLvectorf *objMin, const GLvectorf *objMax, float *xmin, float *ymin, float *zmin, float *xmax, float *ymax, float *zmax, CRrecti *ibounds) { GET_THREAD(thread); CRContext *g = thread->currentContext->State; CRTransformState *t = &(g->transform); if (thread->currentContext->providedBBOX == GL_SCREEN_BBOX_CR) { /* objMin, objMax are in NDC screen coords already */ *xmin = objMin->x; *ymin = objMin->y; *zmin = objMin->z; *xmax = objMax->x; *ymax = objMax->y; *zmax = objMax->z; } else if (winInfo->matrixSource == MATRIX_SOURCE_SERVERS) { /* Use matrices obtained from the servers */ const ServerWindowInfo *servWinInfo = winInfo->server + server; CRmatrix pv, pvm; int eye = (thread->currentContext->stereoDestFlags & EYE_RIGHT) ? 1:0; /* XXX \todo we could multiply this earlier! */ /* pv = proj matrix * view matrix */ crMatrixMultiply(&pv, &servWinInfo->projectionMatrix[eye], &servWinInfo->viewMatrix[eye]); /* pvm = pv * model matrix */ crMatrixMultiply(&pvm, &pv, t->modelViewStack.top); /* Transform bbox by modelview * projection, and project to screen */ crTransformBBox( objMin->x, objMin->y, objMin->z, objMax->x, objMax->y, objMax->z, &pvm, xmin, ymin, zmin, xmax, ymax, zmax ); } else if (winInfo->matrixSource == MATRIX_SOURCE_CONFIG && thread->currentContext->stereoDestFlags != (EYE_LEFT | EYE_RIGHT)) { /* use special left or right eye matrices (set via config options) */ const int curEye = thread->currentContext->stereoDestFlags - 1; CRmatrix pv, pvm; CRASSERT(curEye == 0 || curEye == 1); /* XXX \todo we could multiply this earlier! */ /* pv = proj matrix * view matrix */ crMatrixMultiply(&pv, &tilesort_spu.stereoProjMatrices[curEye], &tilesort_spu.stereoViewMatrices[curEye]); /* pvm = pv * model matrix */ crMatrixMultiply(&pvm, &pv, t->modelViewStack.top); /* Transform bbox by modelview * projection, and project to screen */ crTransformBBox( objMin->x, objMin->y, objMin->z, objMax->x, objMax->y, objMax->z, &pvm, xmin, ymin, zmin, xmax, ymax, zmax ); } else { const CRmatrix *mvp = &(t->modelViewProjection); CRASSERT(winInfo->matrixSource == MATRIX_SOURCE_APP || thread->currentContext->stereoDestFlags == (EYE_LEFT | EYE_RIGHT)); /* Check to make sure the transform is valid */ if (!t->modelViewProjectionValid) { /* I'm pretty sure this is always the case, but I'll leave it. */ crStateTransformUpdateTransform(t); } /* Transform bbox by modelview * projection, and project to screen */ crTransformBBox( objMin->x, objMin->y, objMin->z, objMax->x, objMax->y, objMax->z, mvp, xmin, ymin, zmin, xmax, ymax, zmax ); } /* trivial rejection test */ if (*xmin > 1.0f || *ymin > 1.0f || *xmax < -1.0f || *ymax < -1.0f) { /* bbox doesn't intersect screen */ return GL_FALSE; } /* clamp */ if (*xmin < -1.0f) *xmin = -1.0f; if (*ymin < -1.0f) *ymin = -1.0f; if (*xmax > 1.0f) *xmax = 1.0f; if (*ymax > 1.0f) *ymax = 1.0f; if (ibounds) { /* return screen pixel coords too */ ibounds->x1 = (int) (winInfo->halfViewportWidth * *xmin + winInfo->viewportCenterX); ibounds->x2 = (int) (winInfo->halfViewportWidth * *xmax + winInfo->viewportCenterX); ibounds->y1 = (int) (winInfo->halfViewportHeight * *ymin + winInfo->viewportCenterY); ibounds->y2 = (int) (winInfo->halfViewportHeight * *ymax + winInfo->viewportCenterY); } return GL_TRUE; }