diff --git a/RP_L4/RPL4APP.cpp b/RP_L4/RPL4APP.cpp index d70c501..002169b 100644 --- a/RP_L4/RPL4APP.cpp +++ b/RP_L4/RPL4APP.cpp @@ -133,20 +133,27 @@ void // meaningful in both. //--------------------------------------------------------------------- // + // + //--------------------------------------------------------------------- + // The stand's own geometry first, before anybody stands on it. + // + // The eight spots are fixed furniture on every map, so reading them up + // front gives one set of numbers to both jobs below: where to stand + // the finishers, and where to put the camera. Only the first is + // allowed to care who finished. + //--------------------------------------------------------------------- + // + enum { winnersSpotCount = 8 }; + DropZone *spot[winnersSpotCount]; + int spots_found = 0; + char winners_spot[] = "win?"; char *place = winners_spot + 3; - int placed = 0; - Point3D standFront(0.0f, 0.0f, 0.0f); - Point3D standCentre(0.0f, 0.0f, 0.0f); - Player *p; - for (int rank = 0; (p = CameraDirector::FindPlayerByRank(rank)) != NULL; ++rank) + for (int i = 0; i < winnersSpotCount; ++i) { - if (rank > 7) - { - break; // only eight spots exist on the stand - } - *place = (char) ('1' + rank); + *place = (char) ('1' + i); + spot[i] = NULL; ChainIteratorOf iterator(dropzones->groupMembers); DropZone *dropzone; @@ -154,10 +161,36 @@ void { if (!strcmp(dropzone->GetDropZoneName(), winners_spot)) { + spot[i] = dropzone; + ++spots_found; + Point3D at = dropzone->localOrigin.linearPosition; + DEBUG_STREAM << "WinnersCircle: " << winners_spot << " at " + << at.x << "," << at.y << "," << at.z << "\n" << std::flush; break; } } - if (dropzone == NULL) + } + + if (spot[0] == NULL) + { + DEBUG_STREAM << "WinnersCircle: no win1 spot on this map\n" << std::flush; + return; + } + + // + //--------------------------------------------------------------------- + // Stand the finishers up, in finishing order. + //--------------------------------------------------------------------- + // + int placed = 0; + Player *p; + for (int rank = 0; (p = CameraDirector::FindPlayerByRank(rank)) != NULL; ++rank) + { + if (rank >= winnersSpotCount) + { + break; // only eight spots exist on the stand + } + if (spot[rank] == NULL) { continue; } @@ -168,20 +201,9 @@ void continue; } VTV *vtv = (VTV*) vehicle; - vtv->Reset(dropzone->localOrigin, VTV::MissionReviewReset); + vtv->Reset(spot[rank]->localOrigin, VTV::MissionReviewReset); vtv->SetPerformance(&VTV::DoNothing); vtv->FlushEvents(); - - Point3D spot = dropzone->localOrigin.linearPosition; - if (placed == 0) - { - // remember where the front of the stand is - the shot is framed - // off it rather than off hardcoded map coordinates - standFront = spot; - } - standCentre += spot; - DEBUG_STREAM << "WinnersCircle: " << winners_spot << " at " - << spot.x << "," << spot.y << "," << spot.z << "\n" << std::flush; ++placed; } @@ -239,25 +261,52 @@ void // line-up frames up. The stand runs from z~3 (rank 1, low) to z~39 // (ranks 4-8, high) and x~1180..1219; at 45 degrees that needs roughly // 30 units of standoff. Eye is above the top tier looking slightly - // down at the middle of the group. + // down at the winner's spot. + // + // Framed off the stand, NOT off who is standing on it. This used to + // average the filled spots and anchor on the first one filled, which + // meant the camera moved with the head count: eight finishers put the + // anchor in the middle of the tiers and the eye about 58 units out, + // one finisher collapsed it onto the winner's spot and brought the eye + // in to 36. Same stand, different shot per race - and per machine, if + // a remote player's vehicle was not there to be placed. The furniture + // does not move, so the camera does not either. //--------------------------------------------------------------------- // - standCentre.x /= (Scalar) placed; - standCentre.y /= (Scalar) placed; - standCentre.z /= (Scalar) placed; + Point3D standFront = spot[0]->localOrigin.linearPosition; // - // Stand off along the line from the middle of the group out through the - // front spot, so the shot faces the stand however the map has it turned, - // and lift the eye above the top tier to look down on the line-up. + // The stand's own axis: back rows to the winner's spot, which points + // out of the front however the map has the stand turned. Taken from + // the geometry rather than assumed, so a map that mounts its stand at + // another angle still gets photographed from the front. // + Point3D standBack(0.0f, 0.0f, 0.0f); + int back_count = 0; + for (int i = 1; i < winnersSpotCount; ++i) + { + if (spot[i] != NULL) + { + standBack += spot[i]->localOrigin.linearPosition; + ++back_count; + } + } + if (back_count > 0) + { + standBack.x /= (Scalar) back_count; + standBack.y /= (Scalar) back_count; + standBack.z /= (Scalar) back_count; + } + Vector3D facing; - facing.x = standFront.x - standCentre.x; + facing.x = standFront.x - standBack.x; facing.y = 0.0f; - facing.z = standFront.z - standCentre.z; + facing.z = standFront.z - standBack.z; Scalar reach = (Scalar) sqrt(facing.x * facing.x + facing.z * facing.z); if (reach < 0.01f) { + // a one-spot stand, or all eight stacked: nothing to take a + // direction from, so fall back to the way the shipped stands face facing.x = 0.0f; facing.z = -1.0f; reach = 1.0f; } // @@ -285,10 +334,12 @@ void if (tune != NULL) aim_lift = (Scalar) atof(tune); Point3D eye; - eye.x = standCentre.x + (facing.x / reach) * standoff; - eye.y = standCentre.y + height; - eye.z = standCentre.z + (facing.z / reach) * standoff; - standCentre.y += aim_lift; + eye.x = standFront.x + (facing.x / reach) * standoff; + eye.y = standFront.y + height; + eye.z = standFront.z + (facing.z / reach) * standoff; + + Point3D aim = standFront; + aim.y += aim_lift; // // RP412PODIUMCAM=0 leaves the view in the cockpit, which is also the @@ -315,7 +366,7 @@ void if (camera_mode == NULL || atoi(camera_mode) != 0) { dpl_renderer->SetViewAngle(Degree(45.0f)); - dpl_renderer->SetPresentationCamera(eye, standCentre); + dpl_renderer->SetPresentationCamera(eye, aim); } else { @@ -340,8 +391,13 @@ void } dpl_renderer->StartPresentationFadeIn(fade_in); - DEBUG_STREAM << "WinnersCircle: " << placed << " placed; centre " - << standCentre.x << "," << standCentre.y << "," << standCentre.z + // + // placed is reported for diagnosis only - the camera numbers beside it + // must not move when it does. + // + DEBUG_STREAM << "WinnersCircle: " << placed << " placed on " + << spots_found << " spots; aim " + << aim.x << "," << aim.y << "," << aim.z << " eye " << eye.x << "," << eye.y << "," << eye.z << "\n" << std::flush; }