Revs on the BBC Micro

# 3D objects: BuildCarObjects (Part 3 of 3)

```       Name: BuildCarObjects (Part 3 of 3)                           [Show more]
Type: Subroutine
Category: 3D objects
Summary: Calculate the screen coordinates of all the objects in the
specified car
Deep dive: Drawing a 3D car from 2D parts
Context: See this subroutine in context in the source code
References: No direct references to this subroutine in this source file

Now that we have the car's 3D coordinates in xCoord2, we calculate the car's
yaw and pitch angles, and use them to create either one car object, or four
car objects if this is the four-object car.

If this is the four-object car (i.e. the car is directly in front of us, is
close enough and is visible), then we calculate the coordinates for the three
extra objects as follows:

[ xCoord2 ]   [ xTrackSegmentI ]
Front tyres =     [ yCoord2 ] + [ yTrackSegmentI ] / 2
[ zCoord2 ]   [ zTrackSegmentI ]

[ xCoord2 ]   [ xTrackSegmentI ]
Body and helmet = [ yCoord2 ] + [ yTrackSegmentI ] / 4
[ zCoord2 ]   [ zTrackSegmentI ]

[ xCoord2 ]   [ xTrackSegmentI ]
Rear tyres =      [ yCoord2 ] + [ yTrackSegmentI ] / 8
[ zCoord2 ]   [ zTrackSegmentI ]

.bcar8

LDA #4                 \ Set A = 4, to use as the object type for the car (we
\ change this later if required)

JSR GetObjectAngles-2  \ Calculate the object's yaw and pitch angles, using the
\ coordinates in xCoord2, and set the object's
\ visibility, scale and type

LDX thisDriver         \ Set X = thisDriver (driver number of car we are
\ driving)

LDA objectDistanceHi   \ Set A to the high byte of the distance of the object

CMP #3                 \ If A >= 3, then the car is not close enough to be the
BCS bcar11             \ four-object car, so jump to bcar11 to check whether it
\ should be built as a distant car object

\ If we get here then A <= 2, so the car is close enough
\ to consider building as a four-object car

LDA thisPosition       \ If the car we are building is not the car just ahead
CMP positionAhead      \ of us in the race, then it can't be the four-object
BNE bcar10             \ car, so jump to bcar10 to return from the subroutine
\ with the car built as a standard car

LDA objectStatus,X     \ If bit 7 of the car's object status byte is set, then
BMI bcar9              \ the car is not visible, so jump to bcar9 to skip the
\ following instruction (which leaves the car object as
\ a standard car, but still builds the other three car
\ objects)

\ If we get here then the car we are building is the
\ nearest car in front of us, it's close and it is
\ visible, so we draw this car as the four-object car

DEC objectStatus,X     \ The object type is stored in bits 0-3 of objectStatus,
\ so this decrements the car's object type from 4 (the
\ standard car) to 3 (the rear wing in the four-object
\ car)

.bcar9

LDY vectorNumber       \ Set Y to the segment vector number that we stored
\ above

JSR GetSegmentVector   \ Fetch the inner segment vector for the part of the
\ track that the car is on:
\
\   [ (SS T) ]   [ xTrackSegmentI ]
\   [ (TT U) ] = [ yTrackSegmentI ]
\   [ (UU V) ]   [ yTrackSegmentI ]
\
\ So this contains the direction of the track where the
\ car is

JSR HalveCoordinate    \ Halve the coordinate in (SS T), (TT U) and (UU V)

LDY #&FD               \ Set Y = &FD so the call to AddVectors uses xCoord2

LDX #&FA               \ Set X = &FA so the call to AddVectors uses xCoord1

\
\                       [ (SS T) ]
\   xCoord1 = xCoord2 + [ (TT U) ] / 2
\                       [ (UU V) ]
\
\ So xCoord1 contains the 3D coordinates of the front
\ tyres of the four-object car

JSR HalveCoordinate    \ Halve the coordinate in (SS T), (TT U) and (UU V)

LDX #&F4               \ Set X = &F4 so the call to AddVectors uses
\ xHelmetCoord

\
\                            [ (SS T) ]
\   xHelmetCoord = xCoord2 + [ (TT U) ] / 4
\                            [ (UU V) ]
\
\ So xHelmetCoord contains the 3D coordinates of the
\ helmet and body of the four-object car

JSR HalveCoordinate    \ Halve the coordinate in (SS T), (TT U) and (UU V)

LDX #&FD               \ Set X = &FD so the call to AddVectors uses xCoord2

\
\                       [ (SS T) ]
\   xCoord2 = xCoord2 + [ (TT U) ] / 8
\                       [ (UU V) ]
\
\ So xCoord2 contains the 3D coordinates of the rear
\ tyres of the four-object car

\ Now that we have the 3D coordinates of the extra three
\ parts of the four-object car, we can calculate the
\ object's yaw and pitch angles, and store the details
\ in objects 20, 21 and 22 (for the rear tyres,
\ body/helmet and front tyres respectively)

LDA #20                \ Set objectNumber = 20, to use as then object number
STA objectNumber       \ for the rear tyres in the four-object car

LDA #2                 \ Set A = 2, to use as the object type for the rear
\ tyres in the four-object car

JSR GetObjectAngles-2  \ Calculate the object's yaw and pitch angles, using the
\ coordinates of the rear tyres in xCoord2, and set the
\ object's visibility, scale and type

LDA #21                \ Set objectNumber = 21, to use as then object number
STA objectNumber       \ for the body and helmet in the four-object car

LDA #1                 \ Set A = 1, to use as the object type for the body and
\ helmet in the four-object car

LDX #&F4               \ Set X = &F4 so the call to GetObjectAngles uses
\ xHelmetCoord

JSR GetObjectAngles    \ Calculate the object's yaw and pitch angles, using the
\ coordinates of the body and helmet in xHelmetCoord,
\ and set the object's visibility, scale and type

LDA #22                \ Set objectNumber = 22, to use as then object number
STA objectNumber       \ for the front tyres in the four-object car

LDA #0                 \ Set A = 0, to use as the object type for the rear
\ tyres in the four-object car

LDX #&FA               \ Set X = &FA so the call to GetObjectAngles uses
\ xCoord1

JSR GetObjectAngles    \ Calculate the object's yaw and pitch angles, using the
\ coordinates of the front tyres using xCoord1, and set
\ the object's visibility, scale and type

.bcar10

LDX thisDriver         \ Set X to the driver number that we stored at the start
\ of the BuildVisibleCar routine

RTS                    \ Return from the subroutine

.bcar11

\ We jump here when objectDistanceHi >= 3, so we now
\ need to check whether the car is far enough away for
\ us to change it to a distant car object
\
\ We jump here with A set to objectDistanceHi

CMP #5                 \ If A < 5, i.e. objectDistanceHi = 4, then the car is
BCC bcar10             \ close enough to stay as a standard car object, so jump
\ to bcar10 to return from the subroutine

LDA objectStatus,X     \ If bit 7 of the car's object status byte is set, then
BMI bcar10             \ the car is not visible, so jump to bcar10 to return
\ from the subroutine

\ If we get here then objectDistanceHi >= 5 and the car
\ is visible, so the car is far enough away to be a
\ distant car object

INC objectStatus,X     \ The object type is stored in bits 0-3 of objectStatus,
\ so this increments the car's object type from 4 (the
\ standard car) to 5 (the distant car)

RTS                    \ Return from the subroutine
```