Skip to navigation

Drawing objects: DrawObject

Name: DrawObject [Show more] Type: Subroutine Category: Drawing objects Summary: Draw a 3D object
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * DrawObjectStack calls DrawObject * DrawTileAndObjects calls DrawObject * DrawTitleObject calls DrawObject * DrawUpdatedObject calls DrawObject

Arguments: Y The number of the object to be drawn
Returns: Y Y is preserved
.DrawObject JSR GetObjectAngles \ Calculate the angles and distances of the vector from \ the viewer to object #Y and put them into the \ following variables: \ \ * Set objectViewYaw(Hi Lo) to the yaw angle of the \ viewer's gaze towards the object, relative to the \ screen \ \ * Set objectGazeYaw(Hi Lo) to the difference in yaw \ angles between the viewer's gaze towards the \ object and the object's gaze to wherever it is \ looking (so that's the object's gaze relative to \ the viewer's gaze) \ \ * Set hypotenuse(Hi Lo) to the length of the 3D \ vector from the viewer to the object when \ projected down onto the ground plane \ \ * Set objectAdjacent(Hi Lo) to the length of the \ adjacent side in the vertical right-angled \ triangle with the projected vector along the \ bottom and the vector from the viewer to the \ object as the hypotenuse \ \ * Set objectOpposite(Hi Lo) to the length of the \ opposite side in the vertical right-angled \ triangle with the projected vector along the \ bottom and the vector from the viewer to the \ object as the hypotenuse \ \ Note that hypotenuse(Hi Lo) and objectAdjacent(Hi Lo) \ are the same value, as the hypotenuse of the ground \ plane triangle is the same as the adjacent side of the \ vertical triangle \ \ This also sets objectToAnalyse to the number of the \ object that we are drawing LDA hypotenuseHi \ If hypotenuseHi (i.e. objectAdjacentHi) is greater or CMP #15 \ equal to 15 then the object is a fair distance away ROR blendPolygonEdges \ from the viewer along the z-axis, so set bit 7 of \ blendPolygonEdges so we draw the polygon edges in the \ same colour as the polygon body (i.e. the fill \ colour), so the edges blend into the body \ \ We do this for distant objects because distinct edge \ colours can make those object look messy JSR GetObjPointAngles \ Calculate the view-relative pitch and yaw angles of \ all the points in the object and put them into the \ drawing tables at: \ \ drawViewYaw(Hi Lo) \ \ drawViewPitch(Hi Lo) \ \ We can use these as screen x- and y-coordinates, using \ the same screen projection that is used in Revs LDA #%01000000 \ Clear bit 7 and set bit 6 of polygonType so the call STA polygonType \ to DrawPolygon below draws the correct type of polygon \ for being part of an object LDA #0 \ Set drawingPhaseCount = 0, so the default is to draw STA drawingPhaseCount \ the object in one phase (we may change this later if \ the object needs to be drawn in two phases) STA drawingPhase \ Clear bit 7 of drawingPhase so for objects that need \ two drawing phases, we start by drawing the first \ phase (as the current phase is determined by bit 7) LDX objTypeToAnalyse \ Set X to the number of the object we are drawing LDA objPolygonPhases,X \ Set A to the phase data for the object we are drawing, \ which helps determine the number of drawing phases BEQ drob4 \ If A = 0 then this object only has one drawing phase, \ so jump to drob4 to move on to drawing the object \ (this applies to the tree, the boulder, the Sentinel's \ tower and the 3D text blocks) \ If we get here then bit 1 of A must be set, as the \ only values used in the objPolygonPhases table are \ %00, %10 and %11 LSR A \ If bit 0 of A is set then this object might need two BCS drob1 \ drawing phases, so jump to drob1 to work out how many \ phases are required by checking the relative altitude \ of the object (this applies to the robot, the sentry \ and the Sentinel) \ If we get here then bit 0 of A is clear and bit 1 is \ set, so we need to work out how many phases are \ required by checking whether or not the object is \ facing the viewer as given in the object's yaw angle \ (this applies to the meanie only) LDA objectGazeYawHi \ Set A to the object's gaze yaw angle + 192, to turn it ADC #192 \ anticlockwise (left) through 90 degrees for the phase \ calculation (the addition works because the C flag is \ clear, as we just passed through a BCS) JMP drob3 \ Jump to drob3 to set drawingPhaseCount to 0 or 2, \ depending on the direction in which the meanie is now \ facing: \ \ * 0 = one phase if the meanie's gaze yaw angle is \ positive after the rotation, which means it must \ be facing towards the viewer (so we leave \ drawingPhaseCount = 0) \ \ * 2 = two phases if the meanie's gaze yaw angle is \ negative after the rotation, which means it must \ be facing away from the viewer (so we set the \ drawingPhaseCount = 2) .drob1 \ If we get here then we are drawing a robot, a sentry \ or the Sentinel, so we need to work out how many \ drawing phases are required LDA objectOppositeHi \ If objectOpposite(Hi Lo) has a non-zero high byte, BNE drob2 \ then jump to drob2 to: \ \ * Draw the object in two phases if objectOppositeHi \ is positive (i.e. the object is reasonably far \ above the viewer) \ \ * Draw the object in one phase if objectOppositeHi \ is negative (i.e. the object is below the viewer) LDA objectOppositeLo \ If objectOpposite(Hi Lo) = 0 then the object is at the BEQ drob4 \ same height as the viewer, so jump to drob4 to draw \ the object in one phase (by leaving drawingPhaseCount \ set to 0) \ If we get here then objectOppositeHi is zero but \ objectOppositeLo is non-zero, so the object is only a \ little bit above the viewer and we draw the object in \ two phases (so now we set drawingPhaseCount = 2) LSR A \ Clear bit 7 of A, so the following EOR instruction \ will set bit 7, so we pass through the BPL instruction \ and set drawingPhaseCount = 2 before falling through \ into drob4 to do the actual drawing .drob2 EOR #%10000000 \ Flip bit 7 of A, which will contain objectOppositeHi \ if we jumped here from the BNE above .drob3 BPL drob4 \ If we jumped here because we are drawing a meanie, \ then this jumps to drob4 if the updated object's gaze \ yaw angle is positive \ \ If we fell through from drob2, then this jumps to \ drob4 if bit 7 of objectOppositeHi is set, i.e. if \ objectOpposite(Hi Lo) is negative \ If we get here then one of these is true: \ \ * We are drawing a meanie and it is facing away from \ the viewer \ \ * We are drawing a robot, a sentry or the Sentinel \ and one of these is true: \ \ * objectOpposite(Hi Lo) is positive and \ objectOppositeHi > 0 (so the object is \ reasonably far above the viewer) \ \ * objectOppositeHi is zero and objectOppositeLo is \ non-zero (so the object is a little bit above \ the viewer) \ \ In other words we are drawing a robot, a sentry or \ the Sentinel and the object is above the viewer LDA #2 \ Set drawingPhaseCount = 2 so we draw the object in two STA drawingPhaseCount \ phases .drob4 LDX objTypeToAnalyse \ Set X to the number of the object we are drawing LDA objPolygonRange+1,X \ Set objectLastPolygon to entry X + 1 from the STA objectLastPolygon \ table at objPolygonRange, so this now contains the \ number of the first polygon for the next object, \ object #X + 1, which is one greater than the last \ polygon number for object #X, as the lists of \ object polygons are sequential (so object #0's \ polygons are first in the object data tables, then \ object #1's polygons, and so on) LDY objPolygonRange,X \ Set Y to entry X from the table at objPolygonRange, so \ so this now contains the number of the first polygon \ for object #X \ \ This means that in the following loop, we start the \ drawing process with the first polygon for object #X .drob5 STY polygonNumber \ Set polygonNumber to Y, so we start from the first \ polygon and work through them in order LDA objPolygonData,Y \ Set A to the polygon data byte for the polygon we are \ drawing LDX drawingPhaseCount \ If drawingPhaseCount = 0 then jump to drob6 to skip BEQ drob6 \ the following, as there is only one drawing phase for \ this object EOR drawingPhase \ If bit 7 of the polygon data byte does not match bit 7 BMI drob7 \ of drawingPhase, then we do not draw this polygon in \ this phase, so jump to drob7 to skip drawing the \ polygon and move on to the next one \ If we get here then bit 7 of the polygon data byte \ matches the phase we are currently drawing, so we draw \ the polygon .drob6 AND #%00111100 \ Extract bits 2 to 5 from the polygon data byte to get STA polygonColours \ the polygon's edge and fill colours, and put them into \ polygonColours LDA objPolygonData,Y \ Set A to the polygon data byte for the polygon we are \ drawing AND #%00000011 \ Extract bits 0 to 1 from the polygon data byte to get CLC \ the number of sides in the polygon (where 0 means ADC #3 \ three sides and 1 means four sides) STA polygonEdgeCount \ \ Then add 3 to get the number of sides in the polygon, \ (three for a triangle or four for a quadrilateral) \ and store the result in polygonEdgeCount LDA objPolygonAddrLo,Y \ Set drawViewAngles(1 0) to the address of the list of STA drawViewAngles \ object-relative point numbers for this polygon so the LDA objPolygonAddrHi,Y \ DrawPolygon routine can use the yaw and pitch angles STA drawViewAngles+1 \ that we calculated for the object points in the \ GetObjPointAngles routine JSR DrawPolygon \ Draw the polygon LDY polygonNumber \ Set Y to the polygon number once again, as the call \ to DrawPolygon will have corrupted it .drob7 INY \ Increment the polygon number in Y CPY objectLastPolygon \ If we have not yet reached the end of the list, loop BCC drob5 \ back to drob5 to draw the next polygon, until we have \ processed all the polygons in the object DEC drawingPhaseCount \ Decrement the drawing phase counter BMI drob8 \ If drawingPhaseCount was zero before being decremented \ then there is only one drawing phase, so jump to drob8 \ to finish up BEQ drob8 \ If drawingPhaseCount was 1 before being decremented \ then there are two drawing phases and we have just \ finished drawing the second phase, so jump to drob8 to \ finish up \ If we get here then drawingPhaseCount was 2 before \ being decremented, so this is a two-phase object and \ we have only drawn the first phase, so now we draw the \ second phase LDA #%10000000 \ Set bit 7 of drawingPhase so we now draw the second STA drawingPhase \ phase BMI drob4 \ Jump back to drob4 to draw the second phase for the \ two-phase object .drob8 LDA #LO(polygonPoint) \ Set drawViewAngles(1 0) = polygonPoint STA drawViewAngles \ LDA #HI(polygonPoint) \ This resets drawViewAngles(1 0) so DrawPolygon will STA drawViewAngles+1 \ return to the default behaviour of drawing using point \ data for tile faces rather than object polygons LSR blendPolygonEdges \ Clear bit 7 of blendPolygonEdges so we return to the \ default setting of allowing drawing polygon edges to \ be a different colour to the polygon fill LDY objectToAnalyse \ Set Y to the number of the object we just drew, so it \ is preserved RTS \ Return from the subroutine