static inline int findIntersectionInternal(struct OBJ_Model * obj,Face triangle, Vertex p1, Vertex p2, Vector * new_normal, Vector * intersection_point) { Vector e1, e2, p, s, q; Vector bcoords; float t,u,v, tmp, e=0.000001; double l, new_normal_length; Vector v0,v1,v2,dir; Vector origin, end; origin.n1 = p1.x; origin.n2 = p1.y; origin.n3 = p1.z; end.n1 = p2.x; end.n2 = p2.y; end.n3 = p2.z; Subtraction(dir,end,origin); l = VectorLength(dir); dir.n1/=(float)l; dir.n2/=(float)l; dir.n3/=(float)l; v0.n1 = obj->vertexList[ triangle.v[0]].x; v0.n2 = obj->vertexList[ triangle.v[0]].y; v0.n3 = obj->vertexList[ triangle.v[0]].z; v1.n1 = obj->vertexList[ triangle.v[1]].x; v1.n2 = obj->vertexList[ triangle.v[1]].y; v1.n3 = obj->vertexList[ triangle.v[1]].z; v2.n1 = obj->vertexList[ triangle.v[2]].x; v2.n2 = obj->vertexList[ triangle.v[2]].y; v2.n3 = obj->vertexList[ triangle.v[2]].z; Subtraction(e1, v1, v0); Subtraction(e2, v2, v0); CrossProduct(p, dir, e2); tmp = DotProduct(p, e1); if (tmp > -e && tmp < e) return 0; tmp = 1.0/tmp; Subtraction(s, origin, v0); u = tmp * DotProduct(s, p); if (u<0 || u>1) return 0; CrossProduct(q, s, e1); v = tmp * DotProduct(dir, q); if (v<0 || v>1) return 0; if ( u+v >1) return 0; t = tmp * DotProduct(e2, q); bcoords.n2 = u; bcoords.n3 = v; bcoords.n1 = 1 - u - v; new_normal->n1 = bcoords.n1 * obj->normalList[ triangle.n[0]].n1 + bcoords.n2 * obj->normalList[ triangle.n[1]].n1 + bcoords.n3 * obj->normalList[ triangle.n[2]].n1; new_normal->n2 = bcoords.n1 * obj->normalList[ triangle.n[0]].n2 + bcoords.n2 * obj->normalList[ triangle.n[1]].n2 + bcoords.n3 * obj->normalList[ triangle.n[2]].n2; new_normal->n3 = bcoords.n1 * obj->normalList[ triangle.n[0]].n3 + bcoords.n2 * obj->normalList[ triangle.n[1]].n3 + bcoords.n3 * obj->normalList[ triangle.n[2]].n3; Vector tmpVec = *new_normal; new_normal_length = VectorLength(tmpVec); new_normal->n1 /=new_normal_length; new_normal->n2 /=new_normal_length; new_normal->n3 /=new_normal_length; intersection_point->n1 = dir.n1 * t + origin.n1; intersection_point->n2 = dir.n2 * t + origin.n2; intersection_point->n3 = dir.n3 * t + origin.n3; return 1; }
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, float orientation, float red, float green, float blue, float alpha, qboolean alphaFade, float radius, qboolean temporary ) { vec3_t axis[3]; float texCoordScale; vec3_t originalPoints[4]; byte colors[4]; int i, j; int numFragments; markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf; vec3_t markPoints[MAX_MARK_POINTS]; vec3_t projection; if(markShader == 0) return; assert(markShader); if ( !cg_addMarks.integer ) { return; } else if (cg_addMarks.integer == 2) { trap_R_AddDecalToScene(markShader, origin, dir, orientation, red, green, blue, alpha, alphaFade, radius, temporary); return; } if ( radius <= 0 ) { CG_Error( "CG_ImpactMark called with <= 0 radius" ); } //if ( markTotal >= MAX_MARK_POLYS ) { // return; //} // create the texture axis VectorNormalize2( dir, axis[0] ); PerpendicularVector( axis[1], axis[0] ); RotatePointAroundVector( axis[2], axis[0], axis[1], orientation ); CrossProduct( axis[0], axis[2], axis[1] ); texCoordScale = 0.5 * 1.0 / radius; // create the full polygon for ( i = 0 ; i < 3 ; i++ ) { originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i]; originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i]; originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i]; originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i]; } // get the fragments VectorScale( dir, -20, projection ); numFragments = trap_CM_MarkFragments( 4, (const vec3_t *) originalPoints, projection, MAX_MARK_POINTS, markPoints[0], MAX_MARK_FRAGMENTS, markFragments ); colors[0] = red * 255; colors[1] = green * 255; colors[2] = blue * 255; colors[3] = alpha * 255; for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) { polyVert_t *v; polyVert_t verts[MAX_VERTS_ON_POLY]; markPoly_t *mark; // we have an upper limit on the complexity of polygons // that we store persistantly if ( mf->numPoints > MAX_VERTS_ON_POLY ) { mf->numPoints = MAX_VERTS_ON_POLY; } for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) { vec3_t delta; VectorCopy( markPoints[mf->firstPoint + j], v->xyz ); VectorSubtract( v->xyz, origin, delta ); v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale; v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale; *(int *)v->modulate = *(int *)colors; } // if it is a temporary (shadow) mark, add it immediately and forget about it if ( temporary ) { trap_R_AddPolyToScene( markShader, mf->numPoints, verts ); continue; } // otherwise save it persistantly mark = CG_AllocMark(); mark->time = cg.time; mark->alphaFade = alphaFade; mark->markShader = markShader; mark->poly.numVerts = mf->numPoints; mark->color[0] = red; mark->color[1] = green; mark->color[2] = blue; mark->color[3] = alpha; memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); markTotal++; } }
void CM_AddFacetBevels( facet_t *facet ) { int i, j, k, l; int axis, dir, order, flipped; float plane[4], d, newplane[4]; winding_t *w, *w2; vec3_t mins, maxs, vec, vec2; #ifndef ADDBEVELS return; #endif Vector4Copy( planes[ facet->surfacePlane ].plane, plane ); w = BaseWindingForPlane( plane, plane[3] ); for ( j = 0 ; j < facet->numBorders && w ; j++ ) { if (facet->borderPlanes[j] == facet->surfacePlane) continue; Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane ); if ( !facet->borderInward[j] ) { VectorSubtract( vec3_origin, plane, plane ); plane[3] = -plane[3]; } ChopWindingInPlace( &w, plane, plane[3], 0.1f ); } if ( !w ) { return; } WindingBounds(w, mins, maxs); // add the axial planes order = 0; for ( axis = 0 ; axis < 3 ; axis++ ) { for ( dir = -1 ; dir <= 1 ; dir += 2, order++ ) { VectorClear(plane); plane[axis] = dir; if (dir == 1) { plane[3] = maxs[axis]; } else { plane[3] = -mins[axis]; } //if it's the surface plane if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) { continue; } // see if the plane is allready present for ( i = 0 ; i < facet->numBorders ; i++ ) { if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) break; } if ( i == facet->numBorders ) { if (facet->numBorders > 4 + 6 + 16) { Com_Printf("ERROR: too many bevels\n"); continue; } facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped); facet->borderNoAdjust[facet->numBorders] = qfalse; facet->borderInward[facet->numBorders] = flipped; facet->numBorders++; } } } // // add the edge bevels // // test the non-axial plane edges for ( j = 0 ; j < w->numpoints ; j++ ) { k = (j+1)%w->numpoints; VectorSubtract (w->p[j], w->p[k], vec); //if it's a degenerate edge if (VectorNormalize (vec) < 0.5f) continue; CM_SnapVector(vec); for ( k = 0; k < 3 ; k++ ) if ( vec[k] == -1 || vec[k] == 1 ) break; // axial if ( k < 3 ) continue; // only test non-axial edges // try the six possible slanted axials from this edge for ( axis = 0 ; axis < 3 ; axis++ ) { for ( dir = -1 ; dir <= 1 ; dir += 2 ) { // construct a plane VectorClear (vec2); vec2[axis] = dir; CrossProduct (vec, vec2, plane); if (VectorNormalize (plane) < 0.5f) continue; plane[3] = DotProduct (w->p[j], plane); // if all the points of the facet winding are // behind this plane, it is a proper edge bevel for ( l = 0 ; l < w->numpoints ; l++ ) { d = DotProduct (w->p[l], plane) - plane[3]; if (d > 0.1f) break; // point in front } if ( l < w->numpoints ) continue; //if it's the surface plane if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) { continue; } // see if the plane is allready present for ( i = 0 ; i < facet->numBorders ; i++ ) { if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) { break; } } if ( i == facet->numBorders ) { if (facet->numBorders > 4 + 6 + 16) { Com_Printf("ERROR: too many bevels\n"); continue; } facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped); for ( k = 0 ; k < facet->numBorders ; k++ ) { if (facet->borderPlanes[facet->numBorders] == facet->borderPlanes[k]) Com_Printf("WARNING: bevel plane already used\n"); } facet->borderNoAdjust[facet->numBorders] = qfalse; facet->borderInward[facet->numBorders] = flipped; // w2 = CopyWinding(w); Vector4Copy(planes[facet->borderPlanes[facet->numBorders]].plane, newplane); if (!facet->borderInward[facet->numBorders]) { VectorNegate(newplane, newplane); newplane[3] = -newplane[3]; } //end if ChopWindingInPlace( &w2, newplane, newplane[3], 0.1f ); if (!w2) { Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n"); continue; } else { FreeWinding(w2); } // facet->numBorders++; //already got a bevel // break; } } } } FreeWinding( w ); #ifndef BSPC //add opposite plane if (facet->numBorders > 4 + 6 + 16) { Com_Printf("ERROR: too many bevels\n"); return; } facet->borderPlanes[facet->numBorders] = facet->surfacePlane; facet->borderNoAdjust[facet->numBorders] = qfalse; facet->borderInward[facet->numBorders] = qtrue; facet->numBorders++; #endif //BSPC }
qboolean PM_SlideMove( qboolean gravity ) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity; vec3_t clipVelocity; int i, j, k; trace_t trace; vec3_t end; float time_left; float into; vec3_t endVelocity; vec3_t endClipVelocity; numbumps = 4; VectorCopy (pm->ps->velocity, primal_velocity); if ( gravity ) { VectorCopy( pm->ps->velocity, endVelocity ); endVelocity[2] -= pm->ps->gravity * pml.frametime; pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; primal_velocity[2] = endVelocity[2]; if ( pml.groundPlane ) { // slide along the ground plane PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); } } time_left = pml.frametime; // never turn against the ground plane if ( pml.groundPlane ) { numplanes = 1; VectorCopy( pml.groundTrace.plane.normal, planes[0] ); } else { numplanes = 0; } // never turn against original velocity VectorNormalize2( pm->ps->velocity, planes[numplanes] ); numplanes++; for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) { // calculate position we are trying to move to VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); // see if we can make it there pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask); if (trace.allsolid) { // entity is completely trapped in another solid pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration return qtrue; } if (trace.fraction > 0) { // actually covered some distance VectorCopy (trace.endpos, pm->ps->origin); } if (trace.fraction == 1) { break; // moved the entire distance } // save entity for contact PM_AddTouchEnt( trace.entityNum ); time_left -= time_left * trace.fraction; if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen VectorClear( pm->ps->velocity ); return qtrue; } // // if this is the same plane we hit before, nudge velocity // out along it, which fixes some epsilon issues with // non-axial planes // for ( i = 0 ; i < numplanes ; i++ ) { if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) { VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity ); break; } } if ( i < numplanes ) { continue; } VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // // modify velocity so it parallels all of the clip planes // // find a plane that it enters for ( i = 0 ; i < numplanes ; i++ ) { into = DotProduct( pm->ps->velocity, planes[i] ); if ( into >= 0.1 ) { continue; // move doesn't interact with the plane } // see how hard we are hitting things if ( -into > pml.impactSpeed ) { pml.impactSpeed = -into; } // slide along the plane PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); // slide along the plane PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); // see if there is a second plane that the new move enters for ( j = 0 ; j < numplanes ; j++ ) { if ( j == i ) { continue; } if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) { continue; // move doesn't interact with the plane } // try clipping the move to the plane PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); // see if it goes back into the first clip plane if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) { continue; } // slide the original velocity along the crease CrossProduct (planes[i], planes[j], dir); VectorNormalize( dir ); d = DotProduct( dir, pm->ps->velocity ); VectorScale( dir, d, clipVelocity ); CrossProduct (planes[i], planes[j], dir); VectorNormalize( dir ); d = DotProduct( dir, endVelocity ); VectorScale( dir, d, endClipVelocity ); // see if there is a third plane the the new move enters for ( k = 0 ; k < numplanes ; k++ ) { if ( k == i || k == j ) { continue; } if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) { continue; // move doesn't interact with the plane } // stop dead at a tripple plane interaction VectorClear( pm->ps->velocity ); return qtrue; } } // if we have fixed all interactions, try another move VectorCopy( clipVelocity, pm->ps->velocity ); VectorCopy( endClipVelocity, endVelocity ); break; } } if ( gravity ) { VectorCopy( endVelocity, pm->ps->velocity ); } // don't change velocity if in a timer (FIXME: is this correct?) if ( pm->ps->pm_time ) { VectorCopy( primal_velocity, pm->ps->velocity ); } return ( bumpcount != 0 ); }
/* ================= R_GetPortalOrientation entityNum is the entity that the portal surface is a part of, which may be moving and rotating. Returns qtrue if it should be mirrored ================= */ qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum, orientation_t *surface, orientation_t *camera, vec3_t pvsOrigin, qboolean *mirror ) { int i; cplane_t originalPlane, plane; trRefEntity_t *e; float d; vec3_t transformed; // create plane axis for the portal we are seeing R_PlaneForSurface( drawSurf->surface, &originalPlane ); // rotate the plane if necessary if ( entityNum != REFENTITYNUM_WORLD ) { tr.currentEntityNum = entityNum; tr.currentEntity = &tr.refdef.entities[entityNum]; // get the orientation of the entity R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); // rotate the plane, but keep the non-rotated version for matching // against the portalSurface entities R_LocalNormalToWorld( originalPlane.normal, plane.normal ); plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); // translate the original plane originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); } else { plane = originalPlane; } VectorCopy( plane.normal, surface->axis[0] ); PerpendicularVector( surface->axis[1], surface->axis[0] ); CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] ); // locate the portal entity closest to this plane. // origin will be the origin of the portal, origin2 will be // the origin of the camera for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) { e = &tr.refdef.entities[i]; if ( e->e.reType != RT_PORTALSURFACE ) { continue; } d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; if ( d > 64 || d < -64) { continue; } // get the pvsOrigin from the entity VectorCopy( e->e.oldorigin, pvsOrigin ); // if the entity is just a mirror, don't use as a camera point if ( e->e.oldorigin[0] == e->e.origin[0] && e->e.oldorigin[1] == e->e.origin[1] && e->e.oldorigin[2] == e->e.origin[2] ) { VectorScale( plane.normal, plane.dist, surface->origin ); VectorCopy( surface->origin, camera->origin ); VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] ); VectorCopy( surface->axis[1], camera->axis[1] ); VectorCopy( surface->axis[2], camera->axis[2] ); *mirror = qtrue; return qtrue; } // project the origin onto the surface plane to get // an origin point we can rotate around d = DotProduct( e->e.origin, plane.normal ) - plane.dist; VectorMA( e->e.origin, -d, surface->axis[0], surface->origin ); // now get the camera origin and orientation VectorCopy( e->e.oldorigin, camera->origin ); AxisCopy( e->e.axis, camera->axis ); VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] ); VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] ); // optionally rotate if ( e->e.oldframe ) { // if a speed is specified if ( e->e.frame ) { // continuous rotate d = (tr.refdef.time/1000.0f) * e->e.frame; VectorCopy( camera->axis[1], transformed ); RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); } else { // bobbing rotate, with skinNum being the rotation offset d = sin( tr.refdef.time * 0.003f ); d = e->e.skinNum + d * 4; VectorCopy( camera->axis[1], transformed ); RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); } } else if ( e->e.skinNum ) { d = e->e.skinNum; VectorCopy( camera->axis[1], transformed ); RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); } *mirror = qfalse; return qtrue; } // if we didn't locate a portal entity, don't render anything. // We don't want to just treat it as a mirror, because without a // portal entity the server won't have communicated a proper entity set // in the snapshot // unfortunately, with local movement prediction it is easily possible // to see a surface before the server has communicated the matching // portal surface entity, so we don't want to print anything here... //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" ); return qfalse; }
Model* GenerateTerrain(TextureData *tex) { int vertexCount = tex->width * tex->height; int triangleCount = (tex->width-1) * (tex->height-1) * 2; int x, z; GLfloat *vertexArray = malloc(sizeof(GLfloat) * 3 * vertexCount); GLfloat *normalArray = malloc(sizeof(GLfloat) * 3 * vertexCount); GLfloat *texCoordArray = malloc(sizeof(GLfloat) * 2 * vertexCount); GLuint *indexArray = malloc(sizeof(GLuint) * triangleCount*3); vec3 u, v; printf("bpp %d\n", tex->bpp); for (x = 0; x < tex->width; x++) for (z = 0; z < tex->height; z++) { // Vertex array. You need to scale this properly vertexArray[(x + z * tex->width)*3 + 0] = x / 5.0; vertexArray[(x + z * tex->width)*3 + 1] = tex->imageData[(x + z * tex->width) * (tex->bpp/8)] / 100.0; vertexArray[(x + z * tex->width)*3 + 2] = z / 5.0; // Normal vectors. You need to calculate these. normalArray[(x + z * tex->width)*3 + 0] = 0.0; normalArray[(x + z * tex->width)*3 + 1] = 1.0; normalArray[(x + z * tex->width)*3 + 2] = 0.0; // Texture coordinates. You may want to scale them. texCoordArray[(x + z * tex->width)*2 + 0] = x; // (float)x / tex->width; texCoordArray[(x + z * tex->width)*2 + 1] = z; // (float)z / tex->height; } for (x = 0; x < tex->width-1; x++) for (z = 0; z < tex->height-1; z++) { // Triangle 1 indexArray[(x + z * (tex->width-1))*6 + 0] = x + z * tex->width; indexArray[(x + z * (tex->width-1))*6 + 1] = x + (z+1) * tex->width; indexArray[(x + z * (tex->width-1))*6 + 2] = x+1 + z * tex->width; // Triangle 2 indexArray[(x + z * (tex->width-1))*6 + 3] = x+1 + z * tex->width; indexArray[(x + z * (tex->width-1))*6 + 4] = x + (z+1) * tex->width; indexArray[(x + z * (tex->width-1))*6 + 5] = x+1 + (z+1) * tex->width; // beräkna normalvectorer if(x>=1 && z>= 1){ u.x =vertexArray[(x+1 + z * tex->width)*3+0] - vertexArray[(x-1 + (z-1) * tex->width)*3+0]; u.y = vertexArray[(x+1 + z * tex->width)*3+1] - vertexArray[(x-1 + (z-1) * tex->width)*3+1]; u.z =vertexArray[(x+1 + z * tex->width)*3+2] - vertexArray[(x-1 + (z-1) * tex->width)*3+2]; v.x= vertexArray[(x + (z+1) * tex->width)*3+0] - vertexArray[(x-1 + (z-1) * tex->width)*3+0]; v.y=vertexArray[(x + (z+1) * tex->width)*3+1] - vertexArray[(x-1 + (z-1) * tex->width)*3+1]; v.z=vertexArray[(x + (z+1) * tex->width)*3+2] - vertexArray[(x-1 + (z-1) * tex->width)*3+2]; vec3 normal= CrossProduct(v,u); normalArray[(x + z * tex->width)*3+ 0] = normal.x; normalArray[(x + z * tex->width)*3+ 1] = normal.y; normalArray[(x + z * tex->width)*3+ 2] = normal.z; } } // End of terrain generation // Create Model and upload to GPU: Model* model = LoadDataToModel( vertexArray, normalArray, texCoordArray, NULL, indexArray, vertexCount, triangleCount*3); return model; }
/* ================= RB_ShadowTessEnd triangleFromEdge[ v1 ][ v2 ] set triangle from edge( v1, v2, tri ) if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { } ================= */ void RB_ShadowTessEnd( void ) { int i; int numTris; vec3_t lightDir; GLboolean rgba[4]; // we can only do this if we have enough space in the vertex buffers if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } VectorCopy( backEnd.currentEntity->lightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); } // decide which triangles face the light Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes ); numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; v1 = tess.xyz[ i1 ]; v2 = tess.xyz[ i2 ]; v3 = tess.xyz[ i3 ]; VectorSubtract( v2, v1, d1 ); VectorSubtract( v3, v1, d2 ); CrossProduct( d1, d2, normal ); d = DotProduct( normal, lightDir ); if ( d > 0 ) { facing[ i ] = 1; } else { facing[ i ] = 0; } // create the edges R_AddEdgeDef( i1, i2, facing[ i ] ); R_AddEdgeDef( i2, i3, facing[ i ] ); R_AddEdgeDef( i3, i1, facing[ i ] ); } // draw the silhouette edges GL_Bind( tr.whiteImage ); qglEnable( GL_CULL_FACE ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor3f( 0.2f, 0.2f, 0.2f ); // don't write to the color buffer qglGetBooleanv(GL_COLOR_WRITEMASK, rgba); qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_ALWAYS, 1, 255 ); // mirrors have the culling order reversed if ( backEnd.viewParms.isMirror ) { qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } else { qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } // reenable writing to the color buffer qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); }
void AbsoluteToLocal(plane_t normal2, face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3) { vec3_t ex,ey,ez; #ifdef _DEBUG if (g_qeglobals.m_bBrushPrimitMode) Sys_Printf("Warning : illegal call of AbsoluteToLocal in brush primitive mode\n"); #endif // computing new local axis base TextureAxisFromPlane(&normal2, ex, ey); CrossProduct(ex, ey, ez); // projecting back on (ex,ey) Back(ez,p1); Back(ez,p2); Back(ez,p3); vec3_t aux; // rotation VectorCopy(p2, aux); VectorSubtract(aux, p1,aux); float x = DotProduct(aux,ex); float y = DotProduct(aux,ey); f->texdef.rotate = 180 * atan2(y,x) / Q_PI; vec3_t rex,rey; // computing rotated local axis base VectorCopy(ez, aux); VectorScale(aux, f->texdef.rotate, aux); VectorCopy(ex, rex); VectorRotate(rex, aux, rex); VectorCopy(ey, rey); VectorRotate(rey, aux, rey); // scale VectorCopy(p2, aux); VectorSubtract(aux, p1, aux); f->texdef.scale[0] = DotProduct(aux, rex); VectorCopy(p3, aux); VectorSubtract(aux, p1, aux); f->texdef.scale[1] = DotProduct(aux, rey); // shift // only using p1 x = DotProduct(rex,p1); y = DotProduct(rey,p1); x /= f->texdef.scale[0]; y /= f->texdef.scale[1]; VectorCopy(rex, p1); VectorScale(p1, x, p1); VectorCopy(rey, aux); VectorScale(aux, y, aux); VectorAdd(p1, aux, p1); VectorCopy(ez, aux); VectorScale(aux, -f->texdef.rotate, aux); VectorRotate(p1, aux, p1); f->texdef.shift[0] = -DotProduct(p1, ex); f->texdef.shift[1] = -DotProduct(p1, ey); // stored rot is good considering local axis base // change it if necessary f->texdef.rotate = -f->texdef.rotate; Clamp(f->texdef.shift[0], f->d_texture->width); Clamp(f->texdef.shift[1], f->d_texture->height); Clamp(f->texdef.rotate, 360); }
void FVMesh3D::complete_data() { // initialize the list of cell for each vertex for(size_t i=0;i<_nb_vertex;i++) { _vertex[i].nb_cell=0; } // we have to determine the list of neighbor cell for each vertex further // compute the centroid and length of edge for(size_t i=0;i<_nb_edge;i++) { _edge[i].centroid=(_edge[i].firstVertex->coord+_edge[i].secondVertex->coord)*(double)0.5; FVPoint3D<double> u; u=_edge[i].firstVertex->coord-_edge[i].secondVertex->coord; _edge[i].length=Norm(u); } // We have completly finish with the edge // compute geometric stuff for the face for(size_t i=0;i<_nb_face;i++) { _face[i].perimeter=0.; _face[i].area=0.; _face[i].centroid=0.; // conpute perimeter or the face for(size_t j=0;j<_face[i].nb_edge;j++) { _face[i].perimeter+=_face[i].edge[j]->length; _face[i].centroid+=_face[i].edge[j]->centroid*_face[i].edge[j]->length; } // compute the centroid of the face _face[i].centroid/=_face[i].perimeter; // compute the area of the face for(size_t j=0;j<_face[i].nb_edge;j++) { FVPoint3D<double> u,v,w; u=_face[i].edge[j]->firstVertex->coord-_face[i].centroid; v=_face[i].edge[j]->secondVertex->coord-_face[i].centroid; w=CrossProduct(u,v); _face[i].area+=Norm(w)*0.5; } // build the list of vertex pointer for the face pos_v=0; for(size_t j=0;j<_face[i].nb_edge;j++) { bool _still_exist; _still_exist=false; for(size_t k=0;k<pos_v;k++) if(_face[i].edge[j]->firstVertex==_face[i].vertex[k]) _still_exist=true; if(!_still_exist) {_face[i].vertex[pos_v]=_face[i].edge[j]->firstVertex;pos_v++;} _still_exist=false; for(size_t k=0;k<pos_v;k++) if(_face[i].edge[j]->secondVertex==_face[i].vertex[k]) _still_exist=true; if(!_still_exist) {_face[i].vertex[pos_v]=_face[i].edge[j]->secondVertex;pos_v++;} } _face[i].nb_vertex=pos_v; } // left and right cell, normal vector will be determined after the loop on cells // end loop on the faces for(size_t i=0;i<_nb_cell;i++) { _cell[i].surface=0.; _cell[i].volume=0.; _cell[i].centroid=0.; // conpute surface of the cell // determine the left and right cell for the face for(size_t j=0;j<_cell[i].nb_face;j++) { size_t pos; _cell[i].surface+=_cell[i].face[j]->area; _cell[i].centroid+=_cell[i].face[j]->centroid*_cell[i].face[j]->area; pos=_cell[i].face[j]->label-1; if(!(_face[pos].leftCell) ) _face[pos].leftCell=&(_cell[i]); else _face[pos].rightCell=&(_cell[i]); } // compute the centroid of the cell _cell[i].centroid/=_cell[i].surface; // compute the cell2face vector // compute the volume of the cell for(size_t j=0;j<_cell[i].nb_face;j++) { _cell[i].cell2face[j]= _cell[i].face[j]->centroid-_cell[i].centroid; for(size_t k=0;k<_cell[i].face[j]->nb_edge;k++) { FVPoint3D<double> u,v,w; u=_cell[i].cell2face[j]; v=_cell[i].face[j]->edge[k]->firstVertex->coord-_cell[i].centroid; w=_cell[i].face[j]->edge[k]->secondVertex->coord-_cell[i].centroid; _cell[i].volume+=fabs(Det(u,v,w))/6; } } // build the list of the vertex pointer for a cell pos_v=0; for(size_t j=0;j<_cell[i].nb_face;j++) for(size_t k=0;k<_cell[i].face[j]->nb_edge;k++) { bool _still_exist; _still_exist=false; for(size_t m=0;m<pos_v;m++) if(_cell[i].face[j]->edge[k]->firstVertex==_cell[i].vertex[m]) _still_exist=true; if(!_still_exist) {_cell[i].vertex[pos_v]=_cell[i].face[j]->edge[k]->firstVertex;pos_v++;} _still_exist=false; for(size_t m=0;m<pos_v;m++) if(_cell[i].face[j]->edge[k]->secondVertex==_cell[i].vertex[m]) _still_exist=true; if(!_still_exist) {_cell[i].vertex[pos_v]=_cell[i].face[j]->edge[k]->secondVertex;pos_v++;} } _cell[i].nb_vertex=pos_v; // build the list of the cell pointer for a vertex for(size_t j=0;j<_cell[i].nb_vertex;j++) { size_t pos; pos=_cell[i].vertex[j]->label-1; _vertex[pos].cell[_vertex[pos].nb_cell]=&(_cell[i]); _vertex[pos].nb_cell++; if(_vertex[pos].nb_cell>=NB_CELL_PER_VERTEX_3D) cout<<"Warning, overflow in class FVVertex3D, too many Cells, found "<<_vertex[pos].nb_cell<<endl; } } // we compute the normal from left to rigth for each sub-triangle _boundary_face.resize(0); _nb_boundary_face=0; for(size_t i=0;i<_nb_face;i++) { for(size_t j=0;j<_face[i].nb_edge;j++) { FVPoint3D<double> u,v,w; double no; u=_face[i].edge[j]->firstVertex->coord-_face[i].centroid; v=_face[i].edge[j]->secondVertex->coord-_face[i].centroid; w=CrossProduct(u,v); no=Norm(w); w/=no; _face[i].normal[j]=w; u=_face[i].centroid-_face[i].leftCell->centroid; if(w*u<0) _face[i].normal[j]*=-1.; } // build the list of boundary face if(! (_face[i].rightCell)) {_boundary_face.push_back(&(_face[i]));_nb_boundary_face++;} } }
void displayRollerCoaster() { //DISPLAY THE ROLLER COASTER float a=0.01,f=0.1; texture = LoadTexture("wood.jpg",256, 256); glEnable(GL_TEXTURE_2D); for(float r=0;r<2;r++){ glBegin(GL_QUADS); for (int j = 0; j < g_iNumOfSplines; j++) { for(int i=-2;i<g_Splines[j].numControlPoints-1;i++) { for(float u=0.0;u<1.0;u+=0.02){ //Point p.x= CatmullRom(u, g_Splines[j].points[i].x, g_Splines[j].points[i+1].x, g_Splines[j].points[i+2].x, g_Splines[j].points[i+3].x); p.y= CatmullRom(u, g_Splines[j].points[i].y, g_Splines[j].points[i+1].y, g_Splines[j].points[i+2].y, g_Splines[j].points[i+3].y); p.z= CatmullRom(u, g_Splines[j].points[i].z, g_Splines[j].points[i+1].z, g_Splines[j].points[i+2].z, g_Splines[j].points[i+3].z); //Tangent t.x= CatmullRomTangent(u, g_Splines[j].points[i].x, g_Splines[j].points[i+1].x, g_Splines[j].points[i+2].x, g_Splines[j].points[i+3].x); t.y= CatmullRomTangent(u, g_Splines[j].points[i].y, g_Splines[j].points[i+1].y, g_Splines[j].points[i+2].y, g_Splines[j].points[i+3].y); t.z= CatmullRomTangent(u, g_Splines[j].points[i].z, g_Splines[j].points[i+1].z, g_Splines[j].points[i+2].z, g_Splines[j].points[i+3].z); t = normalize(t); //Normal n = CrossProduct(t, v); n = normalize(n); //Binormal b = CrossProduct(t, n); b = normalize(b); p1.x= CatmullRom(u+0.02, g_Splines[j].points[i].x, g_Splines[j].points[i+1].x, g_Splines[j].points[i+2].x, g_Splines[j].points[i+3].x); p1.y= CatmullRom(u+0.02, g_Splines[j].points[i].y, g_Splines[j].points[i+1].y, g_Splines[j].points[i+2].y, g_Splines[j].points[i+3].y); p1.z= CatmullRom(u+0.02, g_Splines[j].points[i].z, g_Splines[j].points[i+1].z, g_Splines[j].points[i+2].z, g_Splines[j].points[i+3].z); t1.x= CatmullRomTangent(u+0.02, g_Splines[j].points[i].x, g_Splines[j].points[i+1].x, g_Splines[j].points[i+2].x, g_Splines[j].points[i+3].x); t1.y= CatmullRomTangent(u+0.02, g_Splines[j].points[i].y, g_Splines[j].points[i+1].y, g_Splines[j].points[i+2].y, g_Splines[j].points[i+3].y); t1.z= CatmullRomTangent(u+0.02, g_Splines[j].points[i].z, g_Splines[j].points[i+1].z, g_Splines[j].points[i+2].z, g_Splines[j].points[i+3].z); t1 = normalize(t1); n1 = CrossProduct(t1, v); n1 = normalize(n1); b1 = CrossProduct(t1, n1); b1 = normalize(b1); if(r==1) { p.x+=f*n.x; p.y+=f*n.y; p.z+=f*n.z; p1.x+=f*n1.x; p1.y+=f*n1.y; p1.z+=f*n1.z; } glColor3f(1.0, 0.0, 0.0); //V1 glTexCoord2d(0.0,0.0);glVertex3f(p.x+a*(n.x-b.x),p.y+a*(n.y-b.y),p.z+a*(n.z-b.z)); //V2 glTexCoord2d(1.0,0.0);glVertex3f(p.x+a*(n.x+b.x),p.y+a*(n.y+b.y),p.z+a*(n.z+b.z)); //V3 glTexCoord2d(1.0,1.0);glVertex3f(p.x+a*(-n.x+b.x),p.y+a*(-n.y+b.y),p.z+a*(-n.z+b.z)); //V4 glTexCoord2d(0.0,1.0);glVertex3f(p.x+a*(-n.x-b.x),p.y+a*(-n.y-b.y),p.z+a*(-n.z-b.z)); //V5 glTexCoord2d(0.0,0.0);glVertex3f(p1.x+a*(n1.x-b1.x),p1.y+a*(n1.y-b1.y),p1.z+a*(n1.z-b1.z)); //V6 glTexCoord2d(1.0,0.0);glVertex3f(p1.x+a*(n1.x+b1.x),p1.y+a*(n1.y+b1.y),p1.z+a*(n1.z+b1.z)); //V7 glTexCoord2d(1.0,1.0);glVertex3f(p1.x+a*(-n1.x+b1.x),p1.y+a*(-n1.y+b1.y),p1.z+a*(-n1.z+b1.z)); //V8 glTexCoord2d(0.0,1.0);glVertex3f(p1.x+a*(-n1.x-b1.x),p1.y+a*(-n1.y-b1.y),p1.z+a*(-n1.z-b1.z)); //V1 glTexCoord2d(0.0,0.0);glVertex3f(p.x+a*(n.x-b.x),p.y+a*(n.y-b.y),p.z+a*(n.z-b.z)); //V4 glTexCoord2d(0.0,1.0);glVertex3f(p.x+a*(-n.x-b.x),p.y+a*(-n.y-b.y),p.z+a*(-n.z-b.z)); //V8 glTexCoord2d(0.0,1.0);glVertex3f(p1.x+a*(-n1.x-b1.x),p1.y+a*(-n1.y-b1.y),p1.z+a*(-n1.z-b1.z)); //V5 glTexCoord2d(0.0,0.0);glVertex3f(p1.x+a*(n1.x-b1.x),p1.y+a*(n1.y-b1.y),p1.z+a*(n1.z-b1.z)); //V3 glTexCoord2d(1.0,1.0);glVertex3f(p.x+a*(-n.x+b.x),p.y+a*(-n.y+b.y),p.z+a*(-n.z+b.z)); //V4 glTexCoord2d(0.0,1.0);glVertex3f(p.x+a*(-n.x-b.x),p.y+a*(-n.y-b.y),p.z+a*(-n.z-b.z)); //V8 glTexCoord2d(0.0,1.0);glVertex3f(p1.x+a*(-n1.x-b1.x),p1.y+a*(-n1.y-b1.y),p1.z+a*(-n1.z-b1.z)); //V7 glTexCoord2d(1.0,1.0);glVertex3f(p1.x+a*(-n1.x+b1.x),p1.y+a*(-n1.y+b1.y),p1.z+a*(-n1.z+b1.z)); //V2 glTexCoord2d(1.0,0.0);glVertex3f(p.x+a*(n.x+b.x),p.y+a*(n.y+b.y),p.z+a*(n.z+b.z)); //V3 glTexCoord2d(1.0,1.0);glVertex3f(p.x+a*(-n.x+b.x),p.y+a*(-n.y+b.y),p.z+a*(-n.z+b.z)); //V7 glTexCoord2d(1.0,1.0);glVertex3f(p1.x+a*(-n1.x+b1.x),p1.y+a*(-n1.y+b1.y),p1.z+a*(-n1.z+b1.z)); //V6 glTexCoord2d(1.0,0.0);glVertex3f(p1.x+a*(n1.x+b1.x),p1.y+a*(n1.y+b1.y),p1.z+a*(n1.z+b1.z)); //V1 glTexCoord2d(0.0,0.0);glVertex3f(p.x+a*(n.x-b.x),p.y+a*(n.y-b.y),p.z+a*(n.z-b.z)); //V2 glTexCoord2d(1.0,0.0);glVertex3f(p.x+a*(n.x+b.x),p.y+a*(n.y+b.y),p.z+a*(n.z+b.z)); //V6 glTexCoord2d(1.0,0.0);glVertex3f(p1.x+a*(n1.x+b1.x),p1.y+a*(n1.y+b1.y),p1.z+a*(n1.z+b1.z)); //V5 glTexCoord2d(0.0,0.0);glVertex3f(p1.x+a*(n1.x-b1.x),p1.y+a*(n1.y-b1.y),p1.z+a*(n1.z-b1.z)); } } } glEnd(); } glDisable(GL_TEXTURE_2D); }
void displayRails() { //DISPLAY RAILS ON ROLLER COASTER glColor3f(1.0, 1.0, 1.0); texture = LoadTexture("wood.jpg",256, 256); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); for (int j = 0; j < g_iNumOfSplines; j++) { for(int i=-2;i<g_Splines[j].numControlPoints-1;i++) { for(float u=0.0;u<1.0;u+=0.05){ point p,t,n,v,n1,t1,p1; v.x=0.0;v.y=0.0;v.z=-1.0; float f=0.1; //Point p.x= CatmullRom(u, g_Splines[j].points[i].x, g_Splines[j].points[i+1].x, g_Splines[j].points[i+2].x, g_Splines[j].points[i+3].x); p.y= CatmullRom(u, g_Splines[j].points[i].y, g_Splines[j].points[i+1].y, g_Splines[j].points[i+2].y, g_Splines[j].points[i+3].y); p.z= CatmullRom(u, g_Splines[j].points[i].z, g_Splines[j].points[i+1].z, g_Splines[j].points[i+2].z, g_Splines[j].points[i+3].z); //Tangent t.x= CatmullRomTangent(u, g_Splines[j].points[i].x, g_Splines[j].points[i+1].x, g_Splines[j].points[i+2].x, g_Splines[j].points[i+3].x); t.y= CatmullRomTangent(u, g_Splines[j].points[i].y, g_Splines[j].points[i+1].y, g_Splines[j].points[i+2].y, g_Splines[j].points[i+3].y); t.z= CatmullRomTangent(u, g_Splines[j].points[i].z, g_Splines[j].points[i+1].z, g_Splines[j].points[i+2].z, g_Splines[j].points[i+3].z); t = normalize(t); //Normal n = CrossProduct(t, v); n = normalize(n); p1.x= CatmullRom(u+0.01, g_Splines[j].points[i].x, g_Splines[j].points[i+1].x, g_Splines[j].points[i+2].x, g_Splines[j].points[i+3].x); p1.y= CatmullRom(u+0.01, g_Splines[j].points[i].y, g_Splines[j].points[i+1].y, g_Splines[j].points[i+2].y, g_Splines[j].points[i+3].y); p1.z= CatmullRom(u+0.01, g_Splines[j].points[i].z, g_Splines[j].points[i+1].z, g_Splines[j].points[i+2].z, g_Splines[j].points[i+3].z); t1.x= CatmullRomTangent(u+0.01, g_Splines[j].points[i].x, g_Splines[j].points[i+1].x, g_Splines[j].points[i+2].x, g_Splines[j].points[i+3].x); t1.y= CatmullRomTangent(u+0.01, g_Splines[j].points[i].y, g_Splines[j].points[i+1].y, g_Splines[j].points[i+2].y, g_Splines[j].points[i+3].y); t1.z= CatmullRomTangent(u+0.01, g_Splines[j].points[i].z, g_Splines[j].points[i+1].z, g_Splines[j].points[i+2].z, g_Splines[j].points[i+3].z); t1 = normalize(t1); n1 = CrossProduct(t1, v); n1 = normalize(n1); glColor3f(1.0, 1.0, 1.0); glTexCoord2d(0.0,0.0);glVertex3f(p.x,p.y,p.z); glTexCoord2d(3,0.0);glVertex3f(p.x+f*(n.x),p.y+f*(n.y),p.z+f*(n.z)); glTexCoord2d(3,1);glVertex3f(p1.x+f*(n1.x),p1.y+f*(n1.y),p1.z+f*(n1.z)); glTexCoord2d(0.0,1);glVertex3f(p1.x,p1.y,p1.z); glColor3f(1.0, 1.0, 1.0); glTexCoord2d(0.0,0.0);glVertex3f(p.x,p.y,p.z-0.003); glTexCoord2d(3.0,0.0);glVertex3f(p.x+f*(n.x),p.y+f*(n.y),p.z+f*(n.z)-0.003); glTexCoord2d(3.0,1.0);glVertex3f(p1.x+f*(n1.x),p1.y+f*(n1.y),p1.z+f*(n1.z)-0.003); glTexCoord2d(0.0,1.0);glVertex3f(p1.x,p1.y,p1.z-0.003); glColor3f(0.8, 0.5, 0.0); glTexCoord2d(0.0,0.0);glVertex3f(p.x,p.y,p.z); glTexCoord2d(3.0,0.0);glVertex3f(p.x+f*(n.x),p.y+f*(n.y),p.z+f*(n.z)); glTexCoord2d(3.0,1.0);glVertex3f(p.x+f*(n.x),p.y+f*(n.y),p.z+f*(n.z)-0.003); glTexCoord2d(0.0,1.0);glVertex3f(p.x,p.y,p.z-0.003); glColor3f(1.0, 1.0, 1.0); glTexCoord2d(0.0,0.0);glVertex3f(p1.x,p1.y,p1.z); glTexCoord2d(3.0,0.0);glVertex3f(p1.x+f*(n1.x),p1.y+f*(n1.y),p1.z+f*(n1.z)); glTexCoord2d(3.0,1.0);glVertex3f(p1.x+f*(n1.x),p1.y+f*(n1.y),p1.z+f*(n1.z)-0.003); glTexCoord2d(0.0,1.0);glVertex3f(p1.x,p1.y,p1.z-0.003); } } } glEnd(); glDisable(GL_TEXTURE_2D); }
/***************************************************************************** * Draw a faceted latitude band of the Boing ball. * * Parms: long_lo, long_hi * Low and high longitudes of slice, resp. *****************************************************************************/ void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi ) { vertex_t vert_ne; /* "ne" means south-east, so on */ vertex_t vert_nw; vertex_t vert_sw; vertex_t vert_se; vertex_t vert_norm; GLfloat lat_deg; static int colorToggle = 0; /* * Iterate thru the points of a latitude circle. * A latitude circle is a 2D set of X,Z points. */ for ( lat_deg = 0; lat_deg <= (360 - STEP_LATITUDE); lat_deg += STEP_LATITUDE ) { /* * Color this polygon with red or white. */ if ( colorToggle ) glColor3f( 0.8f, 0.1f, 0.1f ); else glColor3f( 0.95f, 0.95f, 0.95f ); #if 0 if ( lat_deg >= 180 ) if ( colorToggle ) glColor3f( 0.1f, 0.8f, 0.1f ); else glColor3f( 0.5f, 0.5f, 0.95f ); #endif colorToggle = ! colorToggle; /* * Change color if drawing shadow. */ if ( drawBallHow == DRAW_BALL_SHADOW ) glColor3f( 0.35f, 0.35f, 0.35f ); /* * Assign each Y. */ vert_ne.y = vert_nw.y = (float) cos_deg(long_hi) * RADIUS; vert_sw.y = vert_se.y = (float) cos_deg(long_lo) * RADIUS; /* * Assign each X,Z with sin,cos values scaled by latitude radius indexed by longitude. * Eg, long=0 and long=180 are at the poles, so zero scale is sin(longitude), * while long=90 (sin(90)=1) is at equator. */ vert_ne.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); vert_se.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); vert_nw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); vert_sw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); vert_ne.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); vert_se.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); vert_nw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); vert_sw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); /* * Draw the facet. */ glBegin( GL_POLYGON ); CrossProduct( vert_ne, vert_nw, vert_sw, &vert_norm ); glNormal3f( vert_norm.x, vert_norm.y, vert_norm.z ); glVertex3f( vert_ne.x, vert_ne.y, vert_ne.z ); glVertex3f( vert_nw.x, vert_nw.y, vert_nw.z ); glVertex3f( vert_sw.x, vert_sw.y, vert_sw.z ); glVertex3f( vert_se.x, vert_se.y, vert_se.z ); glEnd(); #if BOING_DEBUG printf( "----------------------------------------------------------- \n" ); printf( "lat = %f long_lo = %f long_hi = %f \n", lat_deg, long_lo, long_hi ); printf( "vert_ne x = %.8f y = %.8f z = %.8f \n", vert_ne.x, vert_ne.y, vert_ne.z ); printf( "vert_nw x = %.8f y = %.8f z = %.8f \n", vert_nw.x, vert_nw.y, vert_nw.z ); printf( "vert_se x = %.8f y = %.8f z = %.8f \n", vert_se.x, vert_se.y, vert_se.z ); printf( "vert_sw x = %.8f y = %.8f z = %.8f \n", vert_sw.x, vert_sw.y, vert_sw.z ); #endif } /* * Toggle color so that next band will opposite red/white colors than this one. */ colorToggle = ! colorToggle; /* * This circular band is done. */ return; }
/* ============== RB_DrawSun FIXME: sun should render behind clouds, so passing dark areas cover it up ============== */ void RB_DrawSun(void) { float size; float dist; vec3_t origin, vec1, vec2; byte color[4]; if (!tr.sunShader) { return; } if (!backEnd.skyRenderedThisView) { return; } if (!r_drawSun->integer) { return; } qglPushMatrix(); qglLoadMatrixf(backEnd.viewParms.world.modelMatrix); qglTranslatef(backEnd.viewParms.orientation.origin[0], backEnd.viewParms.orientation.origin[1], backEnd.viewParms.orientation.origin[2]); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) // shrunk the size of the sun size = dist * 0.2; VectorScale(tr.sunDirection, dist, origin); PerpendicularVector(vec1, tr.sunDirection); CrossProduct(tr.sunDirection, vec1, vec2); VectorScale(vec1, size, vec1); VectorScale(vec2, size, vec2); // farthest depth range qglDepthRange(1.0, 1.0); color[0] = color[1] = color[2] = color[3] = 255; // simpler sun drawing RB_BeginSurface(tr.sunShader, tess.fogNum); RB_AddQuadStamp(origin, vec1, vec2, color); /* // vec3_t temp; init moved down VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes].v ); tess.texCoords0[tess.numVertexes].v[0] = 0; tess.texCoords0[tess.numVertexes].v[1] = 0; tess.vertexColors[tess.numVertexes].v[0] = 255; tess.vertexColors[tess.numVertexes].v[1] = 255; tess.vertexColors[tess.numVertexes].v[2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes].v ); tess.texCoords0[tess.numVertexes].v[0] = 0; tess.texCoords0[tess.numVertexes].v[1] = 1; tess.vertexColors[tess.numVertexes].v[0] = 255; tess.vertexColors[tess.numVertexes].v[1] = 255; tess.vertexColors[tess.numVertexes].v[2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes].v ); tess.texCoords0[tess.numVertexes].v[0] = 1; tess.texCoords0[tess.numVertexes].v[1] = 1; tess.vertexColors[tess.numVertexes].v[0] = 255; tess.vertexColors[tess.numVertexes].v[1] = 255; tess.vertexColors[tess.numVertexes].v[2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes].v ); tess.texCoords0[tess.numVertexes].v[0] = 1; tess.texCoords0[tess.numVertexes].v[1] = 0; tess.vertexColors[tess.numVertexes].v[0] = 255; tess.vertexColors[tess.numVertexes].v[1] = 255; tess.vertexColors[tess.numVertexes].v[2] = 255; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; */ RB_EndSurface(); if (r_drawSun->integer > 1) // draw flare effect { vec3_t temp; // FYI: This is cheezy and was only a test so far. // If we decide to use the flare business I will /definatly/ improve all this // get a point a little closer dist = dist * 0.7; VectorScale(tr.sunDirection, dist, origin); // and make the flare a little smaller VectorScale(vec1, 0.5f, vec1); VectorScale(vec2, 0.5f, vec2); // add the vectors to give an 'off angle' result VectorAdd(tr.sunDirection, backEnd.viewParms.orientation.axis[0], temp); VectorNormalize(temp); // amplify the result origin[0] += temp[0] * 500.0; origin[1] += temp[1] * 500.0; origin[2] += temp[2] * 500.0; // FIXME: todo: flare effect should render last (on top of everything else) and only when sun is in view (sun moving out of camera past degree n should start to cause flare dimming until view angle to sun is off by angle n + x. // draw the flare RB_BeginSurface(tr.sunflareShader[0], tess.fogNum); RB_AddQuadStamp(origin, vec1, vec2, color); RB_EndSurface(); } // back to normal depth range qglDepthRange(0.0, 1.0); qglPopMatrix(); }
//----------------------------------------------------------------------------- // Assumes the material has already been bound //----------------------------------------------------------------------------- void DrawSprite( const Vector &vecOrigin, float flWidth, float flHeight, color32 color ) { unsigned char pColor[4] = { color.r, color.g, color.b, color.a }; // Generate half-widths flWidth *= 0.5f; flHeight *= 0.5f; // Compute direction vectors for the sprite Vector fwd, right( 1, 0, 0 ), up( 0, 1, 0 ); VectorSubtract( CurrentViewOrigin(), vecOrigin, fwd ); float flDist = VectorNormalize( fwd ); if (flDist >= 1e-3) { CrossProduct( CurrentViewUp(), fwd, right ); flDist = VectorNormalize( right ); if (flDist >= 1e-3) { CrossProduct( fwd, right, up ); } else { // In this case, fwd == g_vecVUp, it's right above or // below us in screen space CrossProduct( fwd, CurrentViewRight(), up ); VectorNormalize( up ); CrossProduct( up, fwd, right ); } } CMeshBuilder meshBuilder; Vector point; CMatRenderContextPtr pRenderContext( materials ); IMesh* pMesh = pRenderContext->GetDynamicMesh( ); meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); meshBuilder.Color4ubv (pColor); meshBuilder.TexCoord2f (0, 0, 1); VectorMA (vecOrigin, -flHeight, up, point); VectorMA (point, -flWidth, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv (pColor); meshBuilder.TexCoord2f (0, 0, 0); VectorMA (vecOrigin, flHeight, up, point); VectorMA (point, -flWidth, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv (pColor); meshBuilder.TexCoord2f (0, 1, 0); VectorMA (vecOrigin, flHeight, up, point); VectorMA (point, flWidth, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.Color4ubv (pColor); meshBuilder.TexCoord2f (0, 1, 1); VectorMA (vecOrigin, -flHeight, up, point); VectorMA (point, flWidth, right, point); meshBuilder.Position3fv (point.Base()); meshBuilder.AdvanceVertex(); meshBuilder.End(); pMesh->Draw(); }
/* ** RB_DrawSun */ void RB_DrawSun( void ) { float size; float dist; vec3_t origin, vec1, vec2; vec3_t temp; if ( !backEnd.skyRenderedThisView ) { return; } if ( !r_drawSun->integer ) { return; } qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); qglTranslatef (backEnd.viewParms.ori.origin[0], backEnd.viewParms.ori.origin[1], backEnd.viewParms.ori.origin[2]); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) size = dist * 0.4; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); CrossProduct( tr.sunDirection, vec1, vec2 ); VectorScale( vec1, size, vec1 ); VectorScale( vec2, size, vec2 ); // farthest depth range qglDepthRange( 1.0, 1.0 ); // FIXME: use quad stamp RB_BeginSurface( tr.sunShader, tess.fogNum ); VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = 255; tess.vertexColors[tess.numVertexes][1] = 255; tess.vertexColors[tess.numVertexes][2] = 255; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); // back to normal depth range qglDepthRange( 0.0, 1.0 ); }
int SV_FlyMove (edict_t *ent, float time, int mask) { edict_t *hit; int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; if (!ent) { return 0; } numbumps = 4; blocked = 0; VectorCopy(ent->velocity, original_velocity); VectorCopy(ent->velocity, primal_velocity); numplanes = 0; time_left = time; ent->groundentity = NULL; for (bumpcount = 0; bumpcount < numbumps; bumpcount++) { for (i = 0; i < 3; i++) { end[i] = ent->s.origin[i] + time_left * ent->velocity[i]; } trace = gi.trace(ent->s.origin, ent->mins, ent->maxs, end, ent, mask); if (trace.allsolid) { /* entity is trapped in another solid */ VectorCopy(vec3_origin, ent->velocity); return 3; } if (trace.fraction > 0) { /* actually covered some distance */ VectorCopy(trace.endpos, ent->s.origin); VectorCopy(ent->velocity, original_velocity); numplanes = 0; } if (trace.fraction == 1) { break; /* moved the entire distance */ } hit = trace.ent; if (trace.plane.normal[2] > 0.7) { blocked |= 1; /* floor */ if (hit->solid == SOLID_BSP) { ent->groundentity = hit; ent->groundentity_linkcount = hit->linkcount; } } if (!trace.plane.normal[2]) { blocked |= 2; /* step */ } /* run the impact function */ SV_Impact(ent, &trace); if (!ent->inuse) { break; /* removed by the impact function */ } time_left -= time_left * trace.fraction; /* cliped to another plane */ if (numplanes >= MAX_CLIP_PLANES) { /* this shouldn't really happen */ VectorCopy(vec3_origin, ent->velocity); return 3; } VectorCopy(trace.plane.normal, planes[numplanes]); numplanes++; /* modify original_velocity so it parallels all of the clip planes */ for (i = 0; i < numplanes; i++) { ClipVelocity(original_velocity, planes[i], new_velocity, 1); for (j = 0; j < numplanes; j++) { if ((j != i) && !VectorCompare(planes[i], planes[j])) { if (DotProduct(new_velocity, planes[j]) < 0) { break; /* not ok */ } } } if (j == numplanes) { break; } } if (i != numplanes) { /* go along this plane */ VectorCopy(new_velocity, ent->velocity); } else { /* go along the crease */ if (numplanes != 2) { VectorCopy(vec3_origin, ent->velocity); return 7; } CrossProduct(planes[0], planes[1], dir); d = DotProduct(dir, ent->velocity); VectorScale(dir, d, ent->velocity); } /* If original velocity is against the original velocity, stop dead to avoid tiny occilations in sloping corners */ if (DotProduct(ent->velocity, primal_velocity) <= 0) { VectorCopy(vec3_origin, ent->velocity); return blocked; } } return blocked; }
void display(void) { ballXPos = ballXPos + 0.03; ballZPos = ballZPos + 0.03; int d = floor(ballXPos * 5.0); int e = floor(ballZPos * 5.0); dx = ballXPos * 5.0 - d; dz = ballZPos * 5.0 - e; if(dx+dz<1){ dyx = tm->vertexArray[(d+1 + e * texWidth)*3+1] - tm->vertexArray[(d + e * texWidth)*3+1]; dyz = tm->vertexArray[(d + (e+1) * texWidth)*3+1] - tm->vertexArray[(d + e * texWidth)*3+1]; ballYPos = dyx*dx+dyz*dz + tm->vertexArray[(d + e * texWidth)*3+1]; } else{ dyx = tm->vertexArray[(d+1 + e * texWidth)*3+1] - tm->vertexArray[((d+1) + (e+1) * texWidth)*3+1]; dyz = tm->vertexArray[(d + (e+1) * texWidth)*3+1] - tm->vertexArray[((d+1) + (e+1) * texWidth)*3+1]; dx = (ceil(ballXPos * 5.0)-ballXPos * 5.0); dz = (ceil(ballZPos * 5.0)-ballZPos * 5.0); ballYPos = dyx*dx+dyz*dz + tm->vertexArray[((d+1) + (e+1) * texWidth)*3+1]; } //printf("%lf\n",ballYPos); vec3 lookingDir = Normalize(VectorSub(l, p)); vec3 walkSideways = Normalize(CrossProduct(lookingDir, v)); if (glutKeyIsDown('a')) { p = VectorSub(p, walkSideways); l = VectorSub(l, walkSideways); } if (glutKeyIsDown('d')) { p = VectorAdd(p, walkSideways); l = VectorAdd(l, walkSideways); } if (glutKeyIsDown('w')) { p = VectorAdd(p, lookingDir); l = VectorAdd(l, lookingDir); } if (glutKeyIsDown('s')) { p = VectorSub(p, lookingDir); l = VectorSub(l, lookingDir); } if (glutKeyIsDown('l')) { trans = T(-p.x, -p.y, -p.z); trans2 = T(p.x, p.y, p.z); rot = Ry(-0.05); l = MultVec3(trans2, MultVec3(rot, MultVec3(trans, l))); } if (glutKeyIsDown('j')) { trans = T(-p.x, -p.y, -p.z); trans2 = T(p.x, p.y, p.z); rot = Ry(0.05); l = MultVec3(trans2, MultVec3(rot, MultVec3(trans, l))); } if (glutKeyIsDown('i')) { trans = T(-p.x, -p.y, -p.z); trans2 = T(p.x, p.y, p.z); rotateUpDown = ArbRotate(walkSideways, 0.05); l = MultVec3(trans2, MultVec3(rotateUpDown, MultVec3(trans, l))); } if (glutKeyIsDown('k')) { trans = T(-p.x, -p.y, -p.z); trans2 = T(p.x, p.y, p.z); rotateUpDown = ArbRotate(walkSideways, -0.05); l = MultVec3(trans2, MultVec3(rotateUpDown, MultVec3(trans, l))); } // clear the screen glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); printError("pre display"); glUseProgram(program); // Build matrix camMatrix = lookAtv(p,l,v); modelView = IdentityMatrix(); total = Mult(camMatrix, modelView); glUniformMatrix4fv(glGetUniformLocation(program, "mdlMatrix"), 1, GL_TRUE, modelView.m); glUniformMatrix4fv(glGetUniformLocation(program, "cameraMatrix"), 1, GL_TRUE, camMatrix.m); DrawModel(tm, program, "inPosition", "inNormal", "inTexCoord"); //Draw sphere modelToWorld = T(ballXPos, ballYPos, ballZPos); glUniformMatrix4fv(glGetUniformLocation(program, "mdlMatrix"), 1, GL_TRUE, modelToWorld.m); DrawModel(sphere, program, "inPosition", "inNormal", NULL); printError("display 2"); glutSwapBuffers(); }
static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw ){ int i, style; float dist, area, value; vec3_t mins, maxs, normal, d1, d2, cross, color, gradient; light_t *light, *splash; winding_t *w; /* dummy check */ if ( rw == NULL || rw->numVerts < 3 ) { return; } /* get bounds for winding */ ClearBounds( mins, maxs ); for ( i = 0; i < rw->numVerts; i++ ) AddPointToBounds( rw->verts[ i ].xyz, mins, maxs ); /* subdivide if necessary */ for ( i = 0; i < 3; i++ ) { if ( maxs[ i ] - mins[ i ] > subdivide ) { radWinding_t front, back; /* make axial plane */ VectorClear( normal ); normal[ i ] = 1; dist = ( maxs[ i ] + mins[ i ] ) * 0.5f; /* clip the winding */ RadClipWindingEpsilon( rw, normal, dist, RADIOSITY_CLIP_EPSILON, &front, &back, cw ); /* recurse */ RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &front, cw ); RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &back, cw ); return; } } /* check area */ area = 0.0f; for ( i = 2; i < rw->numVerts; i++ ) { VectorSubtract( rw->verts[ i - 1 ].xyz, rw->verts[ 0 ].xyz, d1 ); VectorSubtract( rw->verts[ i ].xyz, rw->verts[ 0 ].xyz, d2 ); CrossProduct( d1, d2, cross ); area += 0.5f * VectorLength( cross ); } if ( area < 1.0f || area > 20000000.0f ) { return; } /* more subdivision may be necessary */ if ( bouncing ) { /* get color sample for the surface fragment */ RadSample( lightmapNum, ds, lm, si, rw, color, gradient, &style ); /* if color gradient is too high, subdivide again */ if ( subdivide > minDiffuseSubdivide && ( gradient[ 0 ] > RADIOSITY_MAX_GRADIENT || gradient[ 1 ] > RADIOSITY_MAX_GRADIENT || gradient[ 2 ] > RADIOSITY_MAX_GRADIENT ) ) { RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, ( subdivide / 2.0f ), qfalse, rw, cw ); return; } } /* create a regular winding and an average normal */ w = AllocWinding( rw->numVerts ); w->numpoints = rw->numVerts; VectorClear( normal ); for ( i = 0; i < rw->numVerts; i++ ) { VectorCopy( rw->verts[ i ].xyz, w->p[ i ] ); VectorAdd( normal, rw->verts[ i ].normal, normal ); } VectorScale( normal, ( 1.0f / rw->numVerts ), normal ); if ( VectorNormalize( normal, normal ) == 0.0f ) { return; } /* early out? */ if ( bouncing && VectorLength( color ) < RADIOSITY_MIN ) { return; } /* debug code */ //% Sys_Printf( "Size: %d %d %d\n", (int) (maxs[ 0 ] - mins[ 0 ]), (int) (maxs[ 1 ] - mins[ 1 ]), (int) (maxs[ 2 ] - mins[ 2 ]) ); //% Sys_Printf( "Grad: %f %f %f\n", gradient[ 0 ], gradient[ 1 ], gradient[ 2 ] ); /* increment counts */ numDiffuseLights++; switch ( ds->surfaceType ) { case MST_PLANAR: numBrushDiffuseLights++; break; case MST_TRIANGLE_SOUP: numTriangleDiffuseLights++; break; case MST_PATCH: numPatchDiffuseLights++; break; } /* create a light */ light = safe_malloc( sizeof( *light ) ); memset( light, 0, sizeof( *light ) ); /* attach it */ ThreadLock(); light->next = lights; lights = light; ThreadUnlock(); /* initialize the light */ light->flags = LIGHT_AREA_DEFAULT; light->type = EMIT_AREA; light->si = si; light->fade = 1.0f; light->w = w; /* set falloff threshold */ light->falloffTolerance = falloffTolerance; /* bouncing light? */ if ( bouncing == qfalse ) { /* handle first-pass lights in normal q3a style */ value = si->value; light->photons = value * area * areaScale; light->add = value * formFactorValueScale * areaScale; VectorCopy( si->color, light->color ); VectorScale( light->color, light->add, light->emitColor ); light->style = si->lightStyle; if ( light->style < 0 || light->style >= LS_NONE ) { light->style = 0; } /* set origin */ VectorAdd( mins, maxs, light->origin ); VectorScale( light->origin, 0.5f, light->origin ); /* nudge it off the plane a bit */ VectorCopy( normal, light->normal ); VectorMA( light->origin, 1.0f, light->normal, light->origin ); light->dist = DotProduct( light->origin, normal ); /* optionally create a point splashsplash light for first pass */ if ( original && si->backsplashFraction > 0 ) { /* allocate a new point light */ splash = safe_malloc( sizeof( *splash ) ); memset( splash, 0, sizeof( *splash ) ); splash->next = lights; lights = splash; /* set it up */ splash->flags = LIGHT_Q3A_DEFAULT; splash->type = EMIT_POINT; splash->photons = light->photons * si->backsplashFraction; splash->fade = 1.0f; splash->si = si; VectorMA( light->origin, si->backsplashDistance, normal, splash->origin ); VectorCopy( si->color, splash->color ); splash->falloffTolerance = falloffTolerance; splash->style = light->style; /* add to counts */ numPointLights++; } } else { /* handle bounced light (radiosity) a little differently */ value = RADIOSITY_VALUE * si->bounceScale * 0.375f; light->photons = value * area * bounceScale; light->add = value * formFactorValueScale * bounceScale; VectorCopy( color, light->color ); VectorScale( light->color, light->add, light->emitColor ); light->style = style; if ( light->style < 0 || light->style >= LS_NONE ) { light->style = 0; } /* set origin */ WindingCenter( w, light->origin ); /* nudge it off the plane a bit */ VectorCopy( normal, light->normal ); VectorMA( light->origin, 1.0f, light->normal, light->origin ); light->dist = DotProduct( light->origin, normal ); } /* emit light from both sides? */ if ( si->compileFlags & C_FOG || si->twoSided ) { light->flags |= LIGHT_TWOSIDED; } //% Sys_Printf( "\nAL: C: (%6f, %6f, %6f) [%6f] N: (%6f, %6f, %6f) %s\n", //% light->color[ 0 ], light->color[ 1 ], light->color[ 2 ], light->add, //% light->normal[ 0 ], light->normal[ 1 ], light->normal[ 2 ], //% light->si->shader ); }
void CGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ) { const int MASK_RADIUS_DAMAGE = MASK_SHOT&(~CONTENTS_HITBOX); CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc, MASK_WATER ) & MASK_WATER) ? true : false; #ifdef HL2_DLL if( bInWater ) { // Only muffle the explosion if deeper than 2 feet in water. if( !(UTIL_PointContents(vecSrc + Vector(0, 0, 24), MASK_WATER) & MASK_WATER) ) { bInWater = false; } } #endif // HL2_DLL vecSrc.z += 1;// in case grenade is lying on the ground float flHalfRadiusSqr = Square( flRadius / 2.0f ); // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); (pEntity = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() ) { // This value is used to scale damage when the explosion is blocked by some other object. float flBlockedDamagePercent = 0.0f; if ( pEntity == pEntityIgnore ) continue; if ( pEntity->m_takedamage == DAMAGE_NO ) continue; // UNDONE: this should check a damage mask, not an ignore if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack continue; } // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // Check that the explosion can 'see' this entity. vecSpot = pEntity->BodyTarget( vecSrc, false ); UTIL_TraceLine( vecSrc, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( old_radius_damage.GetBool() ) { if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity ) continue; } else { if ( tr.fraction != 1.0 ) { if ( IsExplosionTraceBlocked(&tr) ) { if( ShouldUseRobustRadiusDamage( pEntity ) ) { if( vecSpot.DistToSqr( vecSrc ) > flHalfRadiusSqr ) { // Only use robust model on a target within one-half of the explosion's radius. continue; } Vector vecToTarget = vecSpot - tr.endpos; VectorNormalize( vecToTarget ); // We're going to deflect the blast along the surface that // interrupted a trace from explosion to this target. Vector vecUp, vecDeflect; CrossProduct( vecToTarget, tr.plane.normal, vecUp ); CrossProduct( tr.plane.normal, vecUp, vecDeflect ); VectorNormalize( vecDeflect ); // Trace along the surface that intercepted the blast... UTIL_TraceLine( tr.endpos, tr.endpos + vecDeflect * ROBUST_RADIUS_PROBE_DIST, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 255, 0, false, 10 ); // ...to see if there's a nearby edge that the explosion would 'spill over' if the blast were fully simulated. UTIL_TraceLine( tr.endpos, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 10 ); if( tr.fraction != 1.0 && tr.DidHitWorld() ) { // Still can't reach the target. continue; } // else fall through } else { continue; } } // UNDONE: Probably shouldn't let children block parents either? Or maybe those guys should set their owner if they want this behavior? // HL2 - Dissolve damage is not reduced by interposing non-world objects if( tr.m_pEnt && tr.m_pEnt != pEntity && tr.m_pEnt->GetOwnerEntity() != pEntity ) { // Some entity was hit by the trace, meaning the explosion does not have clear // line of sight to the entity that it's trying to hurt. If the world is also // blocking, we do no damage. CBaseEntity *pBlockingEntity = tr.m_pEnt; //Msg( "%s may be blocked by %s...", pEntity->GetClassname(), pBlockingEntity->GetClassname() ); UTIL_TraceLine( vecSrc, vecSpot, CONTENTS_SOLID, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if( tr.fraction != 1.0 ) { continue; } // Now, if the interposing object is physics, block some explosion force based on its mass. if( pBlockingEntity->VPhysicsGetObject() ) { const float MASS_ABSORB_ALL_DAMAGE = 350.0f; float flMass = pBlockingEntity->VPhysicsGetObject()->GetMass(); float scale = flMass / MASS_ABSORB_ALL_DAMAGE; // Absorbed all the damage. if( scale >= 1.0f ) { continue; } ASSERT( scale > 0.0f ); flBlockedDamagePercent = scale; //Msg(" Object (%s) weighing %fkg blocked %f percent of explosion damage\n", pBlockingEntity->GetClassname(), flMass, scale * 100.0f); } else { // Some object that's not the world and not physics. Generically block 25% damage flBlockedDamagePercent = 0.25f; } } } } // decrease damage for an ent that's farther from the bomb. float flDistanceToEnt = ( vecSrc - tr.endpos ).Length(); flAdjustedDamage = flDistanceToEnt * falloff; flAdjustedDamage = info.GetDamage() - flAdjustedDamage; if ( flAdjustedDamage <= 0 ) { continue; } // the explosion can 'see' this entity, so hurt them! if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } CTakeDamageInfo adjustedInfo = info; //Msg("%s: Blocked damage: %f percent (in:%f out:%f)\n", pEntity->GetClassname(), flBlockedDamagePercent * 100, flAdjustedDamage, flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); adjustedInfo.SetRadius( flRadius ); adjustedInfo.SetDamage( flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); // Now make a consideration for skill level! if( info.GetAttacker() && info.GetAttacker()->IsPlayer() && pEntity->IsNPC() ) { // An explosion set off by the player is harming an NPC. Adjust damage accordingly. adjustedInfo.AdjustPlayerDamageInflictedForSkillLevel(); } Vector dir = vecSpot - vecSrc; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { if ( !( adjustedInfo.GetDamageType() & DMG_PREVENT_PHYSICS_FORCE ) ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc ); } } else { // Assume the force passed in is the maximum force. Decay it based on falloff. float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); } if ( tr.fraction != 1.0 && pEntity == tr.m_pEnt ) { ClearMultiDamage( ); pEntity->DispatchTraceAttack( adjustedInfo, dir, &tr ); ApplyMultiDamage(); } else { pEntity->TakeDamage( adjustedInfo ); } // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, tr.endpos, dir ); #if defined( GAME_DLL ) if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && ToBaseCombatCharacter( tr.m_pEnt ) ) { // This is a total hack!!! bool bIsPrimary = true; CBasePlayer *player = ToBasePlayer( info.GetAttacker() ); CBaseCombatWeapon *pWeapon = player->GetActiveWeapon(); if ( pWeapon && FClassnameIs( pWeapon, "weapon_smg1" ) ) { bIsPrimary = false; } gamestats->Event_WeaponHit( player, bIsPrimary, (pWeapon != NULL) ? player->GetActiveWeapon()->GetClassname() : "NULL", info ); } #endif } }
/* ================= BaseWindingForPlane ================= */ winding_t *BaseWindingForPlane (plane_t *p) { int i, x; double max, v; vec3_t org, vright, vup; winding_t *w; // find the major axis max = -BOGUS_RANGE; x = -1; for (i = 0 ; i < 3; i++) { v = fabs(p->normal[i]); if (v > max) { x = i; max = v; } } if (x == -1) Error ("%s: no axis found", __thisfunc__); VectorClear (vup); switch (x) { case 0: case 1: vup[2] = 1; break; case 2: vup[0] = 1; break; } v = DotProduct (vup, p->normal); VectorMA (vup, -v, p->normal, vup); VectorNormalize (vup); VectorScale (p->normal, p->dist, org); CrossProduct (vup, p->normal, vright); VectorScale (vup, 8192, vup); VectorScale (vright, 8192, vright); // project a really big axis aligned box onto the plane w = NewWinding (4); VectorSubtract (org, vright, w->points[0]); VectorAdd (w->points[0], vup, w->points[0]); VectorAdd (org, vright, w->points[1]); VectorAdd (w->points[1], vup, w->points[1]); VectorAdd (org, vright, w->points[2]); VectorSubtract (w->points[2], vup, w->points[2]); VectorSubtract (org, vright, w->points[3]); VectorSubtract (w->points[3], vup, w->points[3]); w->numpoints = 4; return w; }
int SV_FlyMove (edict_t *ent, float time, int mask) { edict_t *hit; int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; VectorCopy (ent->velocity, original_velocity); VectorCopy (ent->velocity, primal_velocity); numplanes = 0; time_left = time; ent->groundentity = NULL; for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++) { for (i=0 ; i<3 ; i++) end[i] = ent->s.origin[i] + time_left * ent->velocity[i]; trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask); if (trace.allsolid) { // entity is trapped in another solid VectorCopy (vec3_origin, ent->velocity); return 3; } if (trace.fraction > 0) { // actually covered some distance VectorCopy (trace.endpos, ent->s.origin); VectorCopy (ent->velocity, original_velocity); numplanes = 0; } if (trace.fraction == 1) break; // moved the entire distance hit = trace.ent; if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor if ( hit->solid == SOLID_BSP) { ent->groundentity = hit; ent->groundentity_linkcount = hit->linkcount; } } if (!trace.plane.normal[2]) { blocked |= 2; // step } // // run the impact function // SV_Impact (ent, &trace); if (!ent->inuse) break; // removed by the impact function time_left -= time_left * trace.fraction; // cliped to another plane if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen VectorCopy (vec3_origin, ent->velocity); return 3; } VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // // modify original_velocity so it parallels all of the clip planes // //numplanes = 0; if (ent->client)//K03 added in a call to make sure it is a client entity { //PON-CTF i = false; if(!i){if(!ent->groundentity) i = true;} //PON-CTF if(!i) { numplanes = 0; if(ent->waterlevel || (!ent->groundentity && ent->velocity[2] > 10 )) goto VELCX; i =0; if(/*ent->groundentity ||*/ ent->velocity[2] > 10) goto VELC; } }//K03 End for (i=0 ; i<numplanes ; i++) { ClipVelocity (original_velocity, planes[i], new_velocity, 1); for (j=0 ; j<numplanes ; j++) if (j != i) { if (DotProduct (new_velocity, planes[j]) < 0) break; // not ok } if (j == numplanes) break; } //ponko //ponko VELC: if (i != numplanes) { // go along this plane VectorCopy (new_velocity, ent->velocity); } else { // go along the crease if (numplanes != 2) { // gi.dprintf ("clip velocity, numplanes == %i\n",numplanes); VectorCopy (vec3_origin, ent->velocity); return 7; } CrossProduct (planes[0], planes[1], dir); d = DotProduct (dir, ent->velocity); VectorScale (dir, d, ent->velocity); } VELCX: // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // if (DotProduct (ent->velocity, primal_velocity) <= 0) { VectorCopy (vec3_origin, ent->velocity); return blocked; } } return blocked; }
//------------------------------------------------------------------------------ // Purpose: Break into panels // Input : pBreaker - // vDir - //----------------------------------------------------------------------------- void CBreakableSurface::Die( CBaseEntity *pBreaker, const Vector &vAttackDir ) { if ( m_bIsBroken ) return; // Play a break sound PhysBreakSound( this, VPhysicsGetObject(), GetAbsOrigin() ); m_bIsBroken = true; m_iHealth = 0.0f; if (pBreaker) { m_OnBreak.FireOutput( pBreaker, this ); } else { m_OnBreak.FireOutput( this, this ); } float flDir = -1; if ( vAttackDir.LengthSqr() > 0.001 ) { float flDot = DotProduct( m_vNormal, vAttackDir ); if (flDot < 0) { m_vLLVertex += m_vNormal; m_vLRVertex += m_vNormal; m_vULVertex += m_vNormal; m_vURVertex += m_vNormal; m_vNormal *= -1; flDir = 1; } } // ------------------------------------------------------- // The surface has two sides, when we are killed pick // the side that the damage came from // ------------------------------------------------------- Vector vWidth = m_vLLVertex - m_vLRVertex; Vector vHeight = m_vLLVertex - m_vULVertex; CrossProduct( vWidth, vHeight, m_vNormal.GetForModify() ); VectorNormalize(m_vNormal.GetForModify()); // --------------------------------------------------- // Make sure width and height are oriented correctly // --------------------------------------------------- QAngle vAngles; VectorAngles(-1*m_vNormal,vAngles); Vector vWidthDir,vHeightDir; AngleVectors(vAngles,NULL,&vWidthDir,&vHeightDir); float flWDist = DotProduct(vWidthDir,vWidth); if (fabs(flWDist)<0.5) { Vector vSaveHeight = vHeight; vHeight = vWidth * flDir; vWidth = vSaveHeight * flDir; } // ------------------------------------------------- // Find which corner to use // ------------------------------------------------- bool bLeft = (DotProduct(vWidthDir,vWidth) < 0); bool bLower = (DotProduct(vHeightDir,vHeight) < 0); if (bLeft) { m_vCorner = bLower ? m_vLLVertex : m_vULVertex; } else { m_vCorner = bLower ? m_vLRVertex : m_vURVertex; } // ------------------------------------------------- // Calculate the number of panels // ------------------------------------------------- float flWidth = vWidth.Length(); float flHeight = vHeight.Length(); m_nNumWide = flWidth / WINDOW_PANEL_SIZE; m_nNumHigh = flHeight / WINDOW_PANEL_SIZE; // If to many panels make panel size bigger if (m_nNumWide > MAX_NUM_PANELS) m_nNumWide = MAX_NUM_PANELS; if (m_nNumHigh > MAX_NUM_PANELS) m_nNumHigh = MAX_NUM_PANELS; m_flPanelWidth = flWidth / m_nNumWide; m_flPanelHeight = flHeight / m_nNumHigh; // Initialize panels for (int w=0;w<MAX_NUM_PANELS;w++) { for (int h=0;h<MAX_NUM_PANELS;h++) { SetSupport( w, h, WINDOW_PANE_HEALTHY ); } } // Reset onground flags for any entity that may // have been standing on me ResetOnGroundFlags(); VPhysicsDestroyObject(); AddSolidFlags( FSOLID_TRIGGER ); AddSolidFlags( FSOLID_NOT_SOLID ); SetTouch(&CBreakableSurface::SurfaceTouch); }
int R_MarkFragments( int numPoints, const vector3 *points, const vector3 *projection, int maxPoints, vector3 *pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) { int numsurfaces, numPlanes; int i, j, k, m, n; surfaceType_t *surfaces[64]; vector3 mins, maxs; int returnedFragments; int returnedPoints; vector3 normals[MAX_VERTS_ON_POLY+2]; float dists[MAX_VERTS_ON_POLY+2]; vector3 clipPoints[2][MAX_VERTS_ON_POLY]; int numClipPoints; vector3 *v; srfGridMesh_t *cv; drawVert_t *dv; vector3 normal; vector3 projectionDir; vector3 v1, v2; int *indexes; if (numPoints <= 0) { return 0; } //increment view count for double check prevention tr.viewCount++; // VectorNormalize2( projection, &projectionDir ); // find all the brushes that are to be considered ClearBounds( &mins, &maxs ); for ( i = 0 ; i < numPoints ; i++ ) { vector3 temp; AddPointToBounds( &points[i], &mins, &maxs ); VectorAdd( &points[i], projection, &temp ); AddPointToBounds( &temp, &mins, &maxs ); // make sure we get all the leafs (also the one(s) in front of the hit surface) VectorMA( &points[i], -20, &projectionDir, &temp ); AddPointToBounds( &temp, &mins, &maxs ); } if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY; // create the bounding planes for the to be projected polygon for ( i = 0 ; i < numPoints ; i++ ) { VectorSubtract(&points[(i+1)%numPoints], &points[i], &v1); VectorAdd(&points[i], projection, &v2); VectorSubtract(&points[i], &v2, &v2); CrossProduct(&v1, &v2, &normals[i]); VectorNormalizeFast(&normals[i]); dists[i] = DotProduct(&normals[i], &points[i]); } // add near and far clipping planes for projection VectorCopy(&projectionDir, &normals[numPoints]); dists[numPoints] = DotProduct(&normals[numPoints], &points[0]) - 32; VectorCopy(&projectionDir, &normals[numPoints+1]); VectorInverse(&normals[numPoints+1]); dists[numPoints+1] = DotProduct(&normals[numPoints+1], &points[0]) - 20; numPlanes = numPoints + 2; numsurfaces = 0; R_BoxSurfaces_r(tr.world->nodes, &mins, &maxs, surfaces, 64, &numsurfaces, &projectionDir); //assert(numsurfaces <= 64); //assert(numsurfaces != 64); returnedPoints = 0; returnedFragments = 0; for ( i = 0 ; i < numsurfaces ; i++ ) { if (*surfaces[i] == SF_GRID) { cv = (srfGridMesh_t *) surfaces[i]; for ( m = 0 ; m < cv->height - 1 ; m++ ) { for ( n = 0 ; n < cv->width - 1 ; n++ ) { // We triangulate the grid and chop all triangles within // the bounding planes of the to be projected polygon. // LOD is not taken into account, not such a big deal though. // // It's probably much nicer to chop the grid itself and deal // with this grid as a normal SF_GRID surface so LOD will // be applied. However the LOD of that chopped grid must // be synced with the LOD of the original curve. // One way to do this; the chopped grid shares vertices with // the original curve. When LOD is applied to the original // curve the unused vertices are flagged. Now the chopped curve // should skip the flagged vertices. This still leaves the // problems with the vertices at the chopped grid edges. // // To avoid issues when LOD applied to "hollow curves" (like // the ones around many jump pads) we now just add a 2 unit // offset to the triangle vertices. // The offset is added in the vertex normal vector direction // so all triangles will still fit together. // The 2 unit offset should avoid pretty much all LOD problems. numClipPoints = 3; dv = cv->verts + m * cv->width + n; VectorCopy(&dv[0].xyz, &clipPoints[0][0]); VectorMA(&clipPoints[0][0], MARKER_OFFSET, &dv[0].normal, &clipPoints[0][0]); VectorCopy(&dv[cv->width].xyz, &clipPoints[0][1]); VectorMA(&clipPoints[0][1], MARKER_OFFSET, &dv[cv->width].normal, &clipPoints[0][1]); VectorCopy(&dv[1].xyz, &clipPoints[0][2]); VectorMA(&clipPoints[0][2], MARKER_OFFSET, &dv[1].normal, &clipPoints[0][2]); // check the normal of this triangle VectorSubtract(&clipPoints[0][0], &clipPoints[0][1], &v1); VectorSubtract(&clipPoints[0][2], &clipPoints[0][1], &v2); CrossProduct(&v1, &v2, &normal); VectorNormalizeFast(&normal); if (DotProduct(&normal, &projectionDir) < -0.1f) { // add the fragments of this triangle R_AddMarkFragments(numClipPoints, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, &mins, &maxs); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } VectorCopy(&dv[1].xyz, &clipPoints[0][0]); VectorMA(&clipPoints[0][0], MARKER_OFFSET, &dv[1].normal, &clipPoints[0][0]); VectorCopy(&dv[cv->width].xyz, &clipPoints[0][1]); VectorMA(&clipPoints[0][1], MARKER_OFFSET, &dv[cv->width].normal, &clipPoints[0][1]); VectorCopy(&dv[cv->width+1].xyz, &clipPoints[0][2]); VectorMA(&clipPoints[0][2], MARKER_OFFSET, &dv[cv->width+1].normal, &clipPoints[0][2]); // check the normal of this triangle VectorSubtract(&clipPoints[0][0], &clipPoints[0][1], &v1); VectorSubtract(&clipPoints[0][2], &clipPoints[0][1], &v2); CrossProduct(&v1, &v2, &normal); VectorNormalizeFast(&normal); if (DotProduct(&normal, &projectionDir) < -0.05f) { // add the fragments of this triangle R_AddMarkFragments(numClipPoints, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, &mins, &maxs); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } } } } else if (*surfaces[i] == SF_FACE) { srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i]; // check the normal of this face if (DotProduct(&surf->plane.normal, &projectionDir) > -0.5f) { continue; } indexes = (int *)( (byte *)surf + surf->ofsIndices ); for ( k = 0 ; k < surf->numIndices ; k += 3 ) { for ( j = 0 ; j < 3 ; j++ ) { v = (vector3 *)(surf->points[0] + VERTEXSIZE * indexes[k+j]); VectorMA( v, MARKER_OFFSET, &surf->plane.normal, &clipPoints[0][j] ); } // add the fragments of this face R_AddMarkFragments( 3 , clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, &mins, &maxs); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } } else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) { srfTriangles_t *surf = (srfTriangles_t *) surfaces[i]; for (k = 0; k < surf->numIndexes; k += 3) { for(j = 0; j < 3; j++) { v = &surf->verts[surf->indexes[k + j]].xyz; VectorMA(v, MARKER_OFFSET, &surf->verts[surf->indexes[k + j]].normal, &clipPoints[0][j]); } // add the fragments of this face R_AddMarkFragments(3, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, &mins, &maxs); if(returnedFragments == maxFragments) { return returnedFragments; // not enough space for more fragments } } } } return returnedFragments; }
void C_EnergyWave::ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity ) { int is = (int)s; int it = (int)t; if( is >= EWAVE_NUM_HORIZONTAL_POINTS ) is -= 1; if( it >= EWAVE_NUM_VERTICAL_POINTS ) it -= 1; int idx[16]; ComputeIndices( is, it, idx ); // The patch equation is: // px = S * M * Gx * M^T * T^T // py = S * M * Gy * M^T * T^T // pz = S * M * Gz * M^T * T^T // where S = [s^3 s^2 s 1], T = [t^3 t^2 t 1] // M is the patch type matrix, in my case I'm using a catmull-rom // G is the array of control points. rows have constant t static VMatrix catmullRom( -0.5, 1.5, -1.5, 0.5, 1, -2.5, 2, -0.5, -0.5, 0, 0.5, 0, 0, 1, 0, 0 ); VMatrix controlPointsX, controlPointsY, controlPointsZ, controlPointsO; Vector pos; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { const Vector& v = m_EWaveEffect.GetPoint( idx[i * 4 + j] ); controlPointsX[j][i] = v.x; controlPointsY[j][i] = v.y; controlPointsZ[j][i] = v.z; controlPointsO[j][i] = m_EWaveEffect.ComputeOpacity( v, GetAbsOrigin() ); } } float fs = s - is; float ft = t - it; VMatrix temp, mgm[4]; MatrixTranspose( catmullRom, temp ); MatrixMultiply( controlPointsX, temp, mgm[0] ); MatrixMultiply( controlPointsY, temp, mgm[1] ); MatrixMultiply( controlPointsZ, temp, mgm[2] ); MatrixMultiply( controlPointsO, temp, mgm[3] ); MatrixMultiply( catmullRom, mgm[0], mgm[0] ); MatrixMultiply( catmullRom, mgm[1], mgm[1] ); MatrixMultiply( catmullRom, mgm[2], mgm[2] ); MatrixMultiply( catmullRom, mgm[3], mgm[3] ); Vector4D svec, tvec; float ft2 = ft * ft; tvec[0] = ft2 * ft; tvec[1] = ft2; tvec[2] = ft; tvec[3] = 1.0f; float fs2 = fs * fs; svec[0] = fs2 * fs; svec[1] = fs2; svec[2] = fs; svec[3] = 1.0f; Vector4D tmp; Vector4DMultiply( mgm[0], tvec, tmp ); pt[0] = DotProduct4D( tmp, svec ); Vector4DMultiply( mgm[1], tvec, tmp ); pt[1] = DotProduct4D( tmp, svec ); Vector4DMultiply( mgm[2], tvec, tmp ); pt[2] = DotProduct4D( tmp, svec ); Vector4DMultiply( mgm[3], tvec, tmp ); opacity = DotProduct4D( tmp, svec ); if ((s == 0.0f) || (t == 0.0f) || (s == (EWAVE_NUM_HORIZONTAL_POINTS-1.0f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-1.0f)) ) { opacity = 0.0f; } if ((s <= 0.3) || (t < 0.3)) { opacity *= 0.35f; } if ((s == (EWAVE_NUM_HORIZONTAL_POINTS-0.7f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-0.7f)) ) { opacity *= 0.35f; } if (opacity < 0.0f) opacity = 0.0f; else if (opacity > 255.0f) opacity = 255.0f; // Normal computation Vector4D dsvec, dtvec; dsvec[0] = 3.0f * fs2; dsvec[1] = 2.0f * fs; dsvec[2] = 1.0f; dsvec[3] = 0.0f; dtvec[0] = 3.0f * ft2; dtvec[1] = 2.0f * ft; dtvec[2] = 1.0f; dtvec[3] = 0.0f; Vector ds, dt; Vector4DMultiply( mgm[0], tvec, tmp ); ds[0] = DotProduct4D( tmp, dsvec ); Vector4DMultiply( mgm[1], tvec, tmp ); ds[1] = DotProduct4D( tmp, dsvec ); Vector4DMultiply( mgm[2], tvec, tmp ); ds[2] = DotProduct4D( tmp, dsvec ); Vector4DMultiply( mgm[0], dtvec, tmp ); dt[0] = DotProduct4D( tmp, svec ); Vector4DMultiply( mgm[1], dtvec, tmp ); dt[1] = DotProduct4D( tmp, svec ); Vector4DMultiply( mgm[2], dtvec, tmp ); dt[2] = DotProduct4D( tmp, svec ); CrossProduct( ds, dt, normal ); VectorNormalize( normal ); }
/* ============= DeformText Change a polygon into a bunch of text polygons ============= */ void DeformText( const char *text ) { int i; vec3_t origin, width, height; int len; int ch; byte color[ 4 ]; float bottom, top; vec3_t mid; height[ 0 ] = 0; height[ 1 ] = 0; height[ 2 ] = -1; CrossProduct( tess.normal[ 0 ].v, height, width ); // find the midpoint of the box VectorClear( mid ); bottom = 999999; top = -999999; for ( i = 0; i < 4; i++ ) { VectorAdd( tess.xyz[ i ].v, mid, mid ); if ( tess.xyz[ i ].v[ 2 ] < bottom ) { bottom = tess.xyz[ i ].v[ 2 ]; } if ( tess.xyz[ i ].v[ 2 ] > top ) { top = tess.xyz[ i ].v[ 2 ]; } } VectorScale( mid, 0.25f, origin ); // determine the individual character size height[ 0 ] = 0; height[ 1 ] = 0; height[ 2 ] = ( top - bottom ) * 0.5f; VectorScale( width, height[ 2 ] * -0.75f, width ); // determine the starting position len = strlen( text ); VectorMA( origin, ( len - 1 ), width, origin ); // clear the shader indexes tess.numIndexes = 0; tess.numVertexes = 0; color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 255; // draw each character for ( i = 0; i < len; i++ ) { ch = text[ i ]; ch &= 255; if ( ch != ' ' ) { int row, col; float frow, fcol, size; row = ch >> 4; col = ch & 15; frow = row * 0.0625f; fcol = col * 0.0625f; size = 0.0625f; RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size ); } VectorMA( origin, -2, width, origin ); }
//----------------------------------------------------------------------------- // Purpose: // Input : *pFluid - // *pObject - // *pEntity - //----------------------------------------------------------------------------- void PhysicsSplash( IPhysicsFluidController *pFluid, IPhysicsObject *pObject, CBaseEntity *pEntity ) { //FIXME: For now just allow ragdolls for E3 - jdw if ( ( pObject->GetGameFlags() & FVPHYSICS_PART_OF_RAGDOLL ) == false ) return; Vector velocity; pObject->GetVelocity( &velocity, NULL ); float impactSpeed = velocity.Length(); if ( impactSpeed < 25.0f ) return; Vector normal; float dist; pFluid->GetSurfacePlane( &normal, &dist ); matrix3x4_t &matrix = pEntity->EntityToWorldTransform(); // Find the local axis that best matches the water surface normal int bestAxis = BestAxisMatchingNormal( matrix, normal ); Vector tangent, binormal; MatrixGetColumn( matrix, (bestAxis+1)%3, tangent ); binormal = CrossProduct( normal, tangent ); VectorNormalize( binormal ); tangent = CrossProduct( binormal, normal ); VectorNormalize( tangent ); // Now we have a basis tangent to the surface that matches the object's local orientation as well as possible // compute an OBB using this basis // Get object extents in basis Vector tanPts[2], binPts[2]; tanPts[0] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), -tangent ); tanPts[1] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), tangent ); binPts[0] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), -binormal ); binPts[1] = physcollision->CollideGetExtent( pObject->GetCollide(), pEntity->GetAbsOrigin(), pEntity->GetAbsAngles(), binormal ); // now compute the centered bbox float mins[2], maxs[2], center[2], extents[2]; mins[0] = DotProduct( tanPts[0], tangent ); maxs[0] = DotProduct( tanPts[1], tangent ); mins[1] = DotProduct( binPts[0], binormal ); maxs[1] = DotProduct( binPts[1], binormal ); center[0] = 0.5 * (mins[0] + maxs[0]); center[1] = 0.5 * (mins[1] + maxs[1]); extents[0] = maxs[0] - center[0]; extents[1] = maxs[1] - center[1]; Vector centerPoint = center[0] * tangent + center[1] * binormal + dist * normal; Vector axes[2]; axes[0] = (maxs[0] - center[0]) * tangent; axes[1] = (maxs[1] - center[1]) * binormal; // visualize OBB hit /* Vector corner1 = centerPoint - axes[0] - axes[1]; Vector corner2 = centerPoint + axes[0] - axes[1]; Vector corner3 = centerPoint + axes[0] + axes[1]; Vector corner4 = centerPoint - axes[0] + axes[1]; NDebugOverlay::Line( corner1, corner2, 0, 0, 255, false, 10 ); NDebugOverlay::Line( corner2, corner3, 0, 0, 255, false, 10 ); NDebugOverlay::Line( corner3, corner4, 0, 0, 255, false, 10 ); NDebugOverlay::Line( corner4, corner1, 0, 0, 255, false, 10 ); */ Vector corner[4]; corner[0] = centerPoint - axes[0] - axes[1]; corner[1] = centerPoint + axes[0] - axes[1]; corner[2] = centerPoint + axes[0] + axes[1]; corner[3] = centerPoint - axes[0] + axes[1]; int contents = enginetrace->GetPointContents( centerPoint-Vector(0,0,2) ); bool bInSlime = ( contents & CONTENTS_SLIME ) ? true : false; Vector color = vec3_origin; float luminosity = 1.0f; if ( !bInSlime ) { // Get our lighting information FX_GetSplashLighting( centerPoint + ( normal * 8.0f ), &color, &luminosity ); } if ( impactSpeed > 150 ) { if ( bInSlime ) { FX_GunshotSlimeSplash( centerPoint, normal, random->RandomFloat( 8, 10 ) ); } else { FX_GunshotSplash( centerPoint, normal, random->RandomFloat( 8, 10 ) ); } } else if ( !bInSlime ) { FX_WaterRipple( centerPoint, 1.5f, &color, 1.5f, luminosity ); } int splashes = 4; Vector point; for ( int i = 0; i < splashes; i++ ) { point = RandomVector( -32.0f, 32.0f ); point[2] = 0.0f; point += corner[i]; if ( impactSpeed > 150 ) { if ( bInSlime ) { FX_GunshotSlimeSplash( centerPoint, normal, random->RandomFloat( 4, 6 ) ); } else { FX_GunshotSplash( centerPoint, normal, random->RandomFloat( 4, 6 ) ); } } else if ( !bInSlime ) { FX_WaterRipple( point, random->RandomFloat( 0.25f, 0.5f ), &color, luminosity, random->RandomFloat( 0.5f, 1.0f ) ); } } }
/* ================= R_MarkFragments ================= */ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) { int numsurfaces, numPlanes; int i, j, k, m, n; surfaceType_t *surfaces[64]; vec3_t mins, maxs; int returnedFragments; int returnedPoints; vec3_t normals[MAX_VERTS_ON_POLY+2]; float dists[MAX_VERTS_ON_POLY+2]; vec3_t clipPoints[2][MAX_VERTS_ON_POLY]; int numClipPoints; float *v; srfSurfaceFace_t *surf; srfGridMesh_t *cv; drawVert_t *dv; vec3_t normal; vec3_t projectionDir; vec3_t v1, v2; int *indexes; //increment view count for double check prevention tr.viewCount++; // VectorNormalize2( projection, projectionDir ); // find all the brushes that are to be considered ClearBounds( mins, maxs ); for ( i = 0 ; i < numPoints ; i++ ) { vec3_t temp; AddPointToBounds( points[i], mins, maxs ); VectorAdd( points[i], projection, temp ); AddPointToBounds( temp, mins, maxs ); // make sure we get all the leafs (also the one(s) in front of the hit surface) VectorMA( points[i], -20, projectionDir, temp ); AddPointToBounds( temp, mins, maxs ); } if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY; // create the bounding planes for the to be projected polygon for ( i = 0 ; i < numPoints ; i++ ) { VectorSubtract(points[(i+1)%numPoints], points[i], v1); VectorAdd(points[i], projection, v2); VectorSubtract(points[i], v2, v2); CrossProduct(v1, v2, normals[i]); VectorNormalizeFast(normals[i]); dists[i] = DotProduct(normals[i], points[i]); } // add near and far clipping planes for projection VectorCopy(projectionDir, normals[numPoints]); dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32; VectorCopy(projectionDir, normals[numPoints+1]); VectorInverse(normals[numPoints+1]); dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20; numPlanes = numPoints + 2; numsurfaces = 0; R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir); //assert(numsurfaces <= 64); //assert(numsurfaces != 64); returnedPoints = 0; returnedFragments = 0; for ( i = 0 ; i < numsurfaces ; i++ ) { if (*surfaces[i] == SF_GRID) { cv = (srfGridMesh_t *) surfaces[i]; for ( m = 0 ; m < cv->height - 1 ; m++ ) { for ( n = 0 ; n < cv->width - 1 ; n++ ) { // We triangulate the grid and chop all triangles within // the bounding planes of the to be projected polygon. // LOD is not taken into account, not such a big deal though. // // It's probably much nicer to chop the grid itself and deal // with this grid as a normal SF_GRID surface so LOD will // be applied. However the LOD of that chopped grid must // be synced with the LOD of the original curve. // One way to do this; the chopped grid shares vertices with // the original curve. When LOD is applied to the original // curve the unused vertices are flagged. Now the chopped curve // should skip the flagged vertices. This still leaves the // problems with the vertices at the chopped grid edges. // // To avoid issues when LOD applied to "hollow curves" (like // the ones around many jump pads) we now just add a 2 unit // offset to the triangle vertices. // The offset is added in the vertex normal vector direction // so all triangles will still fit together. // The 2 unit offset should avoid pretty much all LOD problems. numClipPoints = 3; dv = cv->verts + m * cv->width + n; VectorCopy(dv[0].xyz, clipPoints[0][0]); VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); VectorCopy(dv[1].xyz, clipPoints[0][2]); VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); // check the normal of this triangle VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); CrossProduct(v1, v2, normal); VectorNormalizeFast(normal); if (DotProduct(normal, projectionDir) < -0.1) { // add the fragments of this triangle R_AddMarkFragments(numClipPoints, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } VectorCopy(dv[1].xyz, clipPoints[0][0]); VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]); VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]); // check the normal of this triangle VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); CrossProduct(v1, v2, normal); VectorNormalizeFast(normal); if (DotProduct(normal, projectionDir) < -0.05) { // add the fragments of this triangle R_AddMarkFragments(numClipPoints, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } } } } else if (*surfaces[i] == SF_FACE) { surf = ( srfSurfaceFace_t * ) surfaces[i]; // check the normal of this face if (DotProduct(surf->plane.normal, projectionDir) > -0.5) { continue; } /* VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); CrossProduct(v1, v2, normal); VectorNormalize(normal); if (DotProduct(normal, projectionDir) > -0.5) continue; */ #ifdef _XBOX const unsigned char * const indexes = (unsigned char *)( (byte *)surf + surf->ofsIndices ); int nextSurfPoint = NEXT_SURFPOINT(surf->flags); #else indexes = (int *)( (byte *)surf + surf->ofsIndices ); #endif for ( k = 0 ; k < surf->numIndices ; k += 3 ) { for ( j = 0 ; j < 3 ; j++ ) { #ifdef _XBOX const unsigned short* v = surf->srfPoints + nextSurfPoint * indexes[k+j]; float fVec[3]; Q_CastShort2Float(&fVec[0], (short*)v + 0); Q_CastShort2Float(&fVec[1], (short*)v + 1); Q_CastShort2Float(&fVec[2], (short*)v + 2); VectorMA( fVec, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] ); #else v = surf->points[0] + VERTEXSIZE * indexes[k+j];; VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] ); #endif } // add the fragments of this face R_AddMarkFragments( 3 , clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } continue; } else { // ignore all other world surfaces // might be cool to also project polygons on a triangle soup // however this will probably create huge amounts of extra polys // even more than the projection onto curves continue; } } return returnedFragments; }
/* ** RB_DrawSun */ void RB_DrawSun( void ) { #if 0 float size; float dist; vec3_t origin, vec1, vec2; vec3_t temp; matrix_t transformMatrix; matrix_t modelViewMatrix; if ( !backEnd.skyRenderedThisView ) { return; } if ( !r_drawSun->integer ) { return; } GL_PushMatrix(); GL_BindProgram( &tr.genericShader ); // set uniforms GLSL_SetUniform_TCGen_Environment( &tr.genericShader, qfalse ); GLSL_SetUniform_InverseVertexColor( &tr.genericShader, qfalse ); if ( glConfig2.vboVertexSkinningAvailable ) { GLSL_SetUniform_VertexSkinning( &tr.genericShader, qfalse ); } GLSL_SetUniform_DeformGen( &tr.genericShader, DGEN_NONE ); GLSL_SetUniform_AlphaTest( &tr.genericShader, -1.0 ); MatrixSetupTranslation( transformMatrix, backEnd.viewParms.orientation.origin[ 0 ], backEnd.viewParms.orientation.origin[ 1 ], backEnd.viewParms.orientation.origin[ 2 ] ); MatrixMultiply( backEnd.viewParms.world.viewMatrix, transformMatrix, modelViewMatrix ); GL_LoadProjectionMatrix( backEnd.viewParms.projectionMatrix ); GL_LoadModelViewMatrix( modelViewMatrix ); GLSL_SetUniform_ModelMatrix( &tr.genericShader, backEnd.orientation.transformMatrix ); GLSL_SetUniform_ModelViewProjectionMatrix( &tr.genericShader, glState.modelViewProjectionMatrix[ glState.stackIndex ] ); GLSL_SetUniform_PortalClipping( &tr.genericShader, backEnd.viewParms.isPortal ); if ( backEnd.viewParms.isPortal ) { float plane[ 4 ]; // clipping plane in world space plane[ 0 ] = backEnd.viewParms.portalPlane.normal[ 0 ]; plane[ 1 ] = backEnd.viewParms.portalPlane.normal[ 1 ]; plane[ 2 ] = backEnd.viewParms.portalPlane.normal[ 2 ]; plane[ 3 ] = backEnd.viewParms.portalPlane.dist; GLSL_SetUniform_PortalPlane( &tr.genericShader, plane ); } dist = backEnd.viewParms.skyFar / 1.75; // div sqrt(3) size = dist * 0.4; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); CrossProduct( tr.sunDirection, vec1, vec2 ); VectorScale( vec1, size, vec1 ); VectorScale( vec2, size, vec2 ); // farthest depth range glDepthRange( 1.0, 1.0 ); // FIXME: use quad stamp Tess_Begin( Tess_StageIteratorGeneric, tr.sunShader, NULL, tess.skipTangentSpaces, qfalse, -1, tess.fogNum ); VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[ tess.numVertexes ] ); tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = 0; tess.texCoords[ tess.numVertexes ][ 1 ] = 0; tess.colors[ tess.numVertexes ][ 0 ] = 1; tess.colors[ tess.numVertexes ][ 1 ] = 1; tess.colors[ tess.numVertexes ][ 2 ] = 1; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorSubtract( temp, vec2, temp ); VectorCopy( temp, tess.xyz[ tess.numVertexes ] ); tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = 0; tess.texCoords[ tess.numVertexes ][ 1 ] = 1; tess.colors[ tess.numVertexes ][ 0 ] = 1; tess.colors[ tess.numVertexes ][ 1 ] = 1; tess.colors[ tess.numVertexes ][ 2 ] = 1; tess.numVertexes++; VectorCopy( origin, temp ); VectorAdd( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[ tess.numVertexes ] ); tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = 1; tess.texCoords[ tess.numVertexes ][ 1 ] = 1; tess.colors[ tess.numVertexes ][ 0 ] = 1; tess.colors[ tess.numVertexes ][ 1 ] = 1; tess.colors[ tess.numVertexes ][ 2 ] = 1; tess.numVertexes++; VectorCopy( origin, temp ); VectorSubtract( temp, vec1, temp ); VectorAdd( temp, vec2, temp ); VectorCopy( temp, tess.xyz[ tess.numVertexes ] ); tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = 1; tess.texCoords[ tess.numVertexes ][ 1 ] = 0; tess.colors[ tess.numVertexes ][ 0 ] = 1; tess.colors[ tess.numVertexes ][ 1 ] = 1; tess.colors[ tess.numVertexes ][ 2 ] = 1; tess.numVertexes++; tess.indexes[ tess.numIndexes++ ] = 0; tess.indexes[ tess.numIndexes++ ] = 1; tess.indexes[ tess.numIndexes++ ] = 2; tess.indexes[ tess.numIndexes++ ] = 0; tess.indexes[ tess.numIndexes++ ] = 2; tess.indexes[ tess.numIndexes++ ] = 3; Tess_End(); // back to standard depth range glDepthRange( 0.0, 1.0 ); GL_PopMatrix(); #endif }
void CG_AddScorePlum( localEntity_t *le ) { refEntity_t *re; vec3_t origin, delta, dir, vec, up = {0, 0, 1}; float c, len; int i, score, digits[10], numdigits, negative; re = &le->refEntity; c = ( le->endTime - cg.time ) * le->lifeRate; score = le->radius; if (score < 0) { re->shaderRGBA[0] = 0xff; re->shaderRGBA[1] = 0x11; re->shaderRGBA[2] = 0x11; } else { re->shaderRGBA[0] = 0xff; re->shaderRGBA[1] = 0xff; re->shaderRGBA[2] = 0xff; if (score >= 50) { re->shaderRGBA[1] = 0; } else if (score >= 20) { re->shaderRGBA[0] = re->shaderRGBA[1] = 0; } else if (score >= 10) { re->shaderRGBA[2] = 0; } else if (score >= 2) { re->shaderRGBA[0] = re->shaderRGBA[2] = 0; } } if (c < 0.25) re->shaderRGBA[3] = 0xff * 4 * c; else re->shaderRGBA[3] = 0xff; re->radius = NUMBER_SIZE / 2; VectorCopy(le->pos.trBase, origin); origin[2] += 110 - c * 100; VectorSubtract(cg.refdef.vieworg, origin, dir); CrossProduct(dir, up, vec); VectorNormalize(vec); VectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin); // if the view would be "inside" the sprite, kill the sprite // so it doesn't add too much overdraw VectorSubtract( origin, cg.refdef.vieworg, delta ); len = VectorLength( delta ); if ( len < 20 ) { CG_FreeLocalEntity( le ); return; } negative = qfalse; if (score < 0) { negative = qtrue; score = -score; } for (numdigits = 0; !(numdigits && !score); numdigits++) { digits[numdigits] = score % 10; score = score / 10; } if (negative) { digits[numdigits] = 10; numdigits++; } for (i = 0; i < numdigits; i++) { VectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin); re->customShader = cgs.media.numberShaders[digits[numdigits-1-i]]; trap_R_AddRefEntityToScene( re ); } }
/* ================= MakeMeshNormals ================= */ void MakeMeshNormals( mesh_t in ){ int i, j, k, dist; vec3_t normal; vec3_t sum; int count; vec3_t base; vec3_t delta; int x, y; bspDrawVert_t *dv; vec3_t around[8], temp; qboolean good[8]; qboolean wrapWidth, wrapHeight; float len; int neighbors[8][2] = { {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1} }; wrapWidth = qfalse; for ( i = 0 ; i < in.height ; i++ ) { VectorSubtract( in.verts[i * in.width].xyz, in.verts[i * in.width + in.width - 1].xyz, delta ); len = VectorLength( delta ); if ( len > 1.0 ) { break; } } if ( i == in.height ) { wrapWidth = qtrue; } wrapHeight = qfalse; for ( i = 0 ; i < in.width ; i++ ) { VectorSubtract( in.verts[i].xyz, in.verts[i + ( in.height - 1 ) * in.width].xyz, delta ); len = VectorLength( delta ); if ( len > 1.0 ) { break; } } if ( i == in.width ) { wrapHeight = qtrue; } for ( i = 0 ; i < in.width ; i++ ) { for ( j = 0 ; j < in.height ; j++ ) { count = 0; dv = &in.verts[j * in.width + i]; VectorCopy( dv->xyz, base ); for ( k = 0 ; k < 8 ; k++ ) { VectorClear( around[k] ); good[k] = qfalse; for ( dist = 1 ; dist <= 3 ; dist++ ) { x = i + neighbors[k][0] * dist; y = j + neighbors[k][1] * dist; if ( wrapWidth ) { if ( x < 0 ) { x = in.width - 1 + x; } else if ( x >= in.width ) { x = 1 + x - in.width; } } if ( wrapHeight ) { if ( y < 0 ) { y = in.height - 1 + y; } else if ( y >= in.height ) { y = 1 + y - in.height; } } if ( x < 0 || x >= in.width || y < 0 || y >= in.height ) { break; // edge of patch } VectorSubtract( in.verts[y * in.width + x].xyz, base, temp ); if ( VectorNormalize( temp, temp ) == 0 ) { continue; // degenerate edge, get more dist } else { good[k] = qtrue; VectorCopy( temp, around[k] ); break; // good edge } } } VectorClear( sum ); for ( k = 0 ; k < 8 ; k++ ) { if ( !good[k] || !good[( k + 1 ) & 7] ) { continue; // didn't get two points } CrossProduct( around[( k + 1 ) & 7], around[k], normal ); if ( VectorNormalize( normal, normal ) == 0 ) { continue; } VectorAdd( normal, sum, sum ); count++; } if ( count == 0 ) { //Sys_Printf("bad normal\n"); count = 1; } VectorNormalize( sum, dv->normal ); } } }