D:\cygwin\wf_fusion_src_r8\CVSROOT\ref_gl\r_mesh.c

/*
===============
R_DrawPortalSurface
===============
*/
static meshlist_t r_portallist;

void R_DrawPortalSurface ( meshbuffer_t *mb )
{
    int i;
    float dist, d;
    meshlist_t *prevlist;
    refdef_t r;
    mat4x4_t worldviewm, projectionm, modelviewm;
    vec3_t v[3], prev_vpn, prev_vright, prev_vup, entity_rotation[3];
    entity_t *ent;
    mesh_t *mesh;
    model_t *model;
    msurface_t *surf;
    cplane_t *portal_plane = &r_clipplane, original_plane;

    if( !(ent = mb->entity) || !(model = ent->model) || !model->bmodel )
        return;

    surf = mb->infokey > 0 ? &model->bmodel->surfaces[mb->infokey-1] : NULL;
    if( !surf || !(mesh = surf->mesh) || !mesh->xyz_array )
        return;
    
    VectorCopy( mesh->xyz_array[mesh->indexes[0]], v[0] );
    VectorCopy( mesh->xyz_array[mesh->indexes[1]], v[1] );
    VectorCopy( mesh->xyz_array[mesh->indexes[2]], v[2] );
    PlaneFromPoints( v, &original_plane );
    original_plane.dist += DotProduct( ent->origin, original_plane.normal );
    CategorizePlane( &original_plane );

    Matrix_Transpose( ent->axis, entity_rotation );
    Matrix_TransformVector( entity_rotation, mesh->xyz_array[mesh->indexes[0]], v[0] ); VectorMA( ent->origin, ent->scale, v[0], v[0] );
    Matrix_TransformVector( entity_rotation, mesh->xyz_array[mesh->indexes[1]], v[1] ); VectorMA( ent->origin, ent->scale, v[1], v[1] );
    Matrix_TransformVector( entity_rotation, mesh->xyz_array[mesh->indexes[2]], v[2] ); VectorMA( ent->origin, ent->scale, v[2], v[2] );
    PlaneFromPoints ( v, portal_plane );
    CategorizePlane ( portal_plane );

    if( ( dist = PlaneDiff( r_origin, portal_plane ) ) <= BACKFACE_EPSILON )
        return;

    ent = r_newrefdef.entities;
    for ( i = 0; i < r_newrefdef.num_entities; i++, ent++ ) {
        if ( ent->rtype == RT_PORTALSURFACE || ent->rtype == RT_SKYPORTALSURFACE) {
            d = PlaneDiff( ent->origin, &original_plane );
            if ( (d >= -64) && (d <= 64) ) {
                ent->rtype = -1;
                break;
            }
        }
    }

    if( i == r_newrefdef.num_entities )
        return;

    prevlist = r_currentlist;
    memcpy ( &r, &r_newrefdef, sizeof (refdef_t) );
    VectorCopy ( vpn, prev_vpn );
    VectorCopy ( vright, prev_vright );
    VectorCopy ( vup, prev_vup );

    Matrix4_Copy ( r_worldview_matrix, worldviewm );
    Matrix4_Copy ( r_projection_matrix, projectionm );
    Matrix4_Copy( r_modelview_matrix, modelviewm );

    r_portallist.skyDrawn = qfalse;
    r_portallist.num_meshes = 0;
    r_portallist.num_additive_meshes = 0;

    if( VectorCompare( ent->origin, ent->oldorigin ) ) {    // mirror or distorted glass
        vec3_t M[3];

        d = -2 * (DotProduct (r_origin, portal_plane->normal) - portal_plane->dist);
        VectorMA (r_origin, d, portal_plane->normal, r_newrefdef.vieworg);

        d = -2 * DotProduct ( vpn, portal_plane->normal );
        VectorMA ( vpn, d, portal_plane->normal, M[0] );
        VectorNormalize ( M[0] );

        d = -2 * DotProduct ( vright, portal_plane->normal );
        VectorMA ( vright, d, portal_plane->normal, M[1] );
        VectorNormalize ( M[1] );

        d = -2 * DotProduct ( vup, portal_plane->normal );
        VectorMA ( vup, d, portal_plane->normal, M[2] );
        VectorNormalize ( M[2] );

        Matrix_EulerAngles ( M, r_newrefdef.viewangles );
        r_newrefdef.viewangles[ROLL] = -r_newrefdef.viewangles[ROLL]; 

        r_mirrorview = qtrue;
    } 
    else if (ent->rtype != RT_SKYPORTALSURFACE) // regular still/scripted camera
    {
        vec3_t tvec;
        vec3_t A[3], B[3], Bt[3], rot[3], tmp[3], D[3];

        if( mb->shader->flags & SHADER_AGEN_PORTAL ) {
            VectorSubtract( mesh->xyz_array[0], r_origin, tvec );

            for( i = 0; i < mb->shader->numpasses; i++ ) {
                if( mb->shader->passes[i].alphagen.type != ALPHA_GEN_PORTAL )
                    continue;
                if( !r_fastsky->integer && (VectorLength(tvec) > (1.0/mb->shader->passes[i].alphagen.args[0])) )
                    return;
            }
        }

        // build world-to-portal rotation matrix
        VectorNegate ( portal_plane->normal, A[0] );
        if( A[0][0] || A[0][1] ) 
        {
            VectorSet ( A[1], A[0][1], -A[0][0], 0 );
            VectorNormalize( A[1] );
            CrossProduct ( A[0], A[1], A[2] );
        } 
        else 
        {
            VectorSet ( A[1], 1, 0, 0 );
            VectorSet ( A[2], 0, 1, 0 );
        }

        // build portal_dest-to-world rotation matrix
        ByteToDir ( ent->skinnum, portal_plane->normal );

        VectorCopy ( portal_plane->normal, B[0] );
        if( B[0][0] || B[0][1] ) 
        {
            VectorSet ( B[1], B[0][1], -B[0][0], 0 );
            VectorNormalize( B[1] );
            CrossProduct ( B[0], B[1], B[2] );
        } 
        else 
        {
            VectorSet ( B[1], 1, 0, 0 );
            VectorSet ( B[2], 0, 1, 0 );
        }

        Matrix_Transpose ( B, Bt );

        // multiply to get world-to-world rotation matrix
        Matrix_Multiply ( Bt, A, rot );

        if ( ent->frame ) {
            Matrix_TransformVector( A, vpn, tmp[0] );
            Matrix_TransformVector( A, vright, tmp[1] );
            Matrix_TransformVector( A, vup, tmp[2] );
            Matrix_Rotate( tmp, 5*R_FastSin ( ent->scale + r_newrefdef.time * ent->frame * 0.01f ), 1, 0, 0);
            Matrix_TransformVector( Bt, tmp[0], D[0] );
            Matrix_TransformVector( Bt, tmp[1], D[1] );
            Matrix_TransformVector( Bt, tmp[2], D[2] );
        } else {
            Matrix_TransformVector( rot, vpn, D[0] );
            Matrix_TransformVector( rot, vright, D[1] );
            Matrix_TransformVector( rot, vup, D[2] );
        }

        // calculate Euler angles for our rotation matrix
        Matrix_EulerAngles( D, r_newrefdef.viewangles );

        VectorCopy ( D[0], vpn );
        VectorCopy ( D[1], vright );
        VectorCopy ( D[2], vup );

        // translate view origin
        VectorSubtract ( r_newrefdef.vieworg, ent->origin, tvec );
        Matrix_TransformVector ( rot, tvec, r_newrefdef.vieworg );
        VectorAdd ( r_newrefdef.vieworg, ent->oldorigin, r_newrefdef.vieworg );

        // set up portal_plane
        portal_plane->dist = DotProduct ( ent->oldorigin, portal_plane->normal );
        CategorizePlane ( portal_plane );

        // for portals, vis data is taken from portal origin, not
        // view origin, because the view point moves around and
        // might fly into (or behind) a wall
        r_portalview = qtrue;
        VectorCopy ( ent->oldorigin, r_portalorg );
    }
    else // skyportal
    {
        vec3_t tvec;
        vec3_t A[3], B[3], Bt[3], rot[3], tmp[3], D[3];

        if( mb->shader->flags & SHADER_AGEN_PORTAL ) {
            VectorSubtract( mesh->xyz_array[0], r_origin, tvec );

            for( i = 0; i < mb->shader->numpasses; i++ ) {
                if( mb->shader->passes[i].alphagen.type != ALPHA_GEN_PORTAL )
                    continue;
                if( !r_fastsky->integer && (VectorLength(tvec) > (1.0/mb->shader->passes[i].alphagen.args[0])) )
                    return;
            }
        }

        // build world-to-portal rotation matrix
        VectorNegate ( portal_plane->normal, A[0] );
        if( A[0][0] || A[0][1] ) 
        {
            VectorSet ( A[1], 0, 0, 0 );
            VectorNormalize( A[1] );
            CrossProduct ( A[0], A[1], A[2] );
        } 
        else 
        {
            VectorSet ( A[1], 1, 0, 0 );
            VectorSet ( A[2], 0, 1, 0 );
        }

        // build portal_dest-to-world rotation matrix
        ByteToDir ( ent->skinnum, portal_plane->normal );

        VectorCopy ( portal_plane->normal, B[0] );
        if( B[0][0] || B[0][1] ) 
        {
            VectorSet ( B[1], B[0][1], -B[0][0], 0 );
            VectorNormalize( B[1] );
            CrossProduct ( B[0], B[1], B[2] );
        } 
        else 
        {
            VectorSet ( B[1], 1, 0, 0 );
            VectorSet ( B[2], 0, 1, 0 );
        }

        Matrix_Transpose ( B, Bt );

        // multiply to get world-to-world rotation matrix
        Matrix_Multiply ( Bt, A, rot );

        if ( ent->frame ) {
            Matrix_TransformVector( A, vpn, tmp[0] );
            Matrix_TransformVector( A, vright, tmp[1] );
            Matrix_TransformVector( A, vup, tmp[2] );
            Matrix_Rotate( tmp, 5*R_FastSin ( ent->scale + r_newrefdef.time * ent->frame * 0.01f ), 1, 0, 0);
            Matrix_TransformVector( Bt, tmp[0], D[0] );
            Matrix_TransformVector( Bt, tmp[1], D[1] );
            Matrix_TransformVector( Bt, tmp[2], D[2] );
        } else {
            Matrix_TransformVector( rot, vpn, D[0] );
            Matrix_TransformVector( rot, vright, D[1] );
            Matrix_TransformVector( rot, vup, D[2] );
        }

        // calculate Euler angles for our rotation matrix
        Matrix_EulerAngles( D, r_newrefdef.viewangles );

        VectorCopy ( D[0], vpn );
        VectorCopy ( D[1], vright );
        VectorCopy ( D[2], vup );

        // translate view origin
        VectorSubtract ( r_newrefdef.vieworg, ent->origin, tvec );
        Matrix_TransformVector ( rot, tvec, r_newrefdef.vieworg );
        VectorCopy (ent->oldorigin, r_newrefdef.vieworg);

        // set up portal_plane
        portal_plane->dist = DotProduct ( ent->oldorigin, portal_plane->normal );
        CategorizePlane ( portal_plane );

        // for portals, vis data is taken from portal origin, not
        // view origin, because the view point moves around and
        // might fly into (or behind) a wall
        r_portalview = qtrue;
        VectorCopy ( ent->oldorigin, r_portalorg );
    }

    qglDepthMask ( GL_TRUE );
    qglDepthFunc ( GL_LEQUAL );
    qglDisable ( GL_POLYGON_OFFSET_FILL );
    qglDisable ( GL_BLEND );
    if( r_mirrorview )
        qglFrontFace( GL_CW );

    R_RenderView ( &r_newrefdef, &r_portallist );

    qglMatrixMode ( GL_PROJECTION );
    qglLoadMatrixf ( projectionm );
    if( r_mirrorview )
        qglFrontFace( GL_CCW );

    qglMatrixMode ( GL_MODELVIEW );
    qglLoadMatrixf ( worldviewm );

    qglDepthMask( GL_TRUE );
    if( !r_fastsky->integer )
        qglClear ( GL_DEPTH_BUFFER_BIT );

    Matrix4_Copy ( worldviewm, r_worldview_matrix );
    Matrix4_Copy ( projectionm, r_projection_matrix );
    Matrix4_Copy( modelviewm, r_modelview_matrix );

    memcpy ( &r_newrefdef, &r, sizeof (refdef_t) );
    r_currentlist = prevlist;

    VectorCopy ( r_newrefdef.vieworg, r_origin );
    VectorCopy ( prev_vpn, vpn );
    VectorCopy ( prev_vright, vright );
    VectorCopy ( prev_vup, vup );

    if( r_portalview )
        r_oldviewcluster = r_viewcluster = -1;  // force markleafs next frame

    r_mirrorview = qfalse;
    r_portalview = qfalse;
}