/** * @brief Get the next point in the object path based on movement converting the positions from * polar coordinates to vector for the calculation and back again to be returned. * @param[in] movement The distance that the object needs to move. * @param[in] originalPoint The point from which the object is moving. * @param[in] orthogonalVector The orthogonal vector. * @param[out] finalPoint The next point from the original point + movement in "angle" direction. */ static void AIRFIGHT_GetNextPointInPathFromVector (const float *movement, const vec2_t originalPoint, const vec3_t orthogonalVector, vec2_t finalPoint) { vec3_t startPoint, finalVectorPoint; PolarToVec(originalPoint, startPoint); RotatePointAroundVector(finalVectorPoint, orthogonalVector, startPoint, *movement); VecToPolar(finalVectorPoint, finalPoint); }
static void R_PlantGrass (Clump& clump) { if (clumpTriangleCount + TRIS_PER_CLUMP >= MAX_CLUMP_TRIS) { clump.firstTriangle = clumpTriangleCount; clump.numTriangles = 0; return; } clump.firstTriangle = clumpTriangleCount; clump.numTriangles = 0; /* safeguard */ vec3_t rot[3]; /* rotation matrix for the plant */ #define xt (rot[0]) #define yt (rot[1]) #define zt (rot[2]) #if 0 /* horisontal planting */ VectorSet(xt, 1, 0, 0); VectorSet(zt, 0, 0, 1); #else /* normal-based planting */ /* we can calculate the downslope vector and use it instead; * a bit more of math, but call allow us to create plants that interact with the slope in various ways */ VectorCopy(clump.normal, zt); VectorSet(xt, zt[2], 0.0, -zt[0]); /* short-circuit CrossProduct(yaxis, normal, xt) since it degenerates to a simple shuffle */ VectorNormalizeFast(xt); #endif /* generate geometry */ #if 0 /* prebuilt mesh or debug grass marker */ /* randomly rotate plant around the base */ RotatePointAroundVector(yt, zt, xt, frand() * 360); CrossProduct(yt, zt, xt); /* randomly mirror the plant, too */ if (rand() & 1) VectorInverse(yt); /* marker */ vec_t* ptr = gfv_pos[clumpTriangleCount * 3]; VectorMA(clump.position, 1, zt, ptr); VectorMA(ptr, 16, yt, ptr + 3); VectorMA(ptr, 16, xt, ptr + 6); vec_t* texc = gfv_texcoord[clumpTriangleCount * 3]; Vector2Set(texc, 0, 0); Vector2Set(texc + 2, 1, 0); Vector2Set(texc + 4, 0, 1); clumpTriangleCount++; #else /* programmatically generated clump */ CrossProduct(zt, xt, yt); for (int i = 0; i < TRIS_PER_CLUMP; i += 2) { vec3_t sdir, tdir; vec2_t sprrot; vec3_t tmp; sprrot[0] = frand() * 360; sprrot[1] = frand() * 60 + 15; PolarToVec(sprrot, tmp); VectorRotate(rot, tmp, tdir); sprrot[0] += 90; sprrot[1] = 0; PolarToVec(sprrot, tmp); VectorRotate(rot, tmp, sdir); #if 0 /* debug marker */ vec_t* ptr = gfv_pos[clumpTriangleCount * 3]; VectorCopy(clump.position, ptr); VectorMA(ptr, 16, sdir, ptr + 3); VectorMA(ptr, 16, tdir, ptr + 6); vec_t* texc = gfv_texcoord[clumpTriangleCount * 3]; Vector2Set(texc, 0, 0); Vector2Set(texc + 2, 1, 0); Vector2Set(texc + 4, 0, 1); clumpTriangleCount++; #else /* billboard sprite */ vec_t* ptr = gfv_pos[clumpTriangleCount * 3]; VectorCopy(clump.position, ptr); /** @todo use UNIT_SIZE and co defines here */ VectorMA(clump.position, -24, sdir, ptr); /* quad vertex 0 */ VectorMA(ptr, 32, tdir, ptr + 3); /* quad vertex 1 */ VectorMA(ptr + 3, 48, sdir, ptr + 6); /* quad vertex 2 */ VectorCopy(ptr, ptr + 9); /* quad vertex 0 */ VectorCopy(ptr + 6, ptr + 12); /* quad vertex 2 */ VectorMA(ptr + 6, -32, tdir, ptr + 15); /* quad vertex 3 */ vec_t* texc = gfv_texcoord[clumpTriangleCount * 3]; Vector2Set(texc, 0, 1); Vector2Set(texc + 2, 0, 0); Vector2Set(texc + 4, 1, 0); Vector2Set(texc + 6, 0, 1); Vector2Set(texc + 8, 1, 0); Vector2Set(texc + 12, 1, 1); clumpTriangleCount += 2; #endif } #endif #undef xt #undef yt #undef zt clump.numTriangles = clumpTriangleCount - clump.firstTriangle; }