Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/goddard/draw_objects.c
7858 views
1
#include <PR/ultratypes.h>
2
#include <stdio.h>
3
4
#include "debug_utils.h"
5
#include "dynlist_proc.h"
6
#include "gd_macros.h"
7
#include "gd_main.h"
8
#include "gd_math.h"
9
#include "gd_types.h"
10
#include "macros.h"
11
#include "objects.h"
12
#include "old_menu.h"
13
#include "renderer.h"
14
#include "shape_helper.h"
15
#include "draw_objects.h"
16
17
/**
18
* @file draw_objects.c
19
* This file contains the functions and helpers for rendering the various
20
* GdObj primitives to the screen.
21
*/
22
23
// forward declarations
24
void func_80179B64(struct ObjGroup *);
25
void update_shaders(struct ObjShape *, struct GdVec3f *);
26
void draw_shape_faces(struct ObjShape *);
27
void register_light(struct ObjLight *);
28
29
// types
30
/**
31
* Modes for drawscene()
32
*/
33
enum SceneType {
34
RENDER_SCENE = 26, ///< render the primitives to screen
35
FIND_PICKS = 27 ///< only check position of primitives relative to cursor click
36
};
37
38
/**
39
* A possible remnant of an early `ObjVertex` structure that contained
40
* texture S,T coordinates.
41
*/
42
struct BetaVtx {
43
/* 0x00 */ u8 pad[0x44 - 0];
44
/* 0x44 */ f32 s;
45
/* 0x48 */ f32 t;
46
};
47
48
// data
49
static struct GdColour sClrWhite = { 1.0, 1.0, 1.0 }; // @ 801A8070
50
static struct GdColour sClrRed = { 1.0, 0.0, 0.0 }; // @ 801A807C
51
static struct GdColour sClrGreen = { 0.0, 1.0, 0.0 }; // @ 801A8088
52
static struct GdColour sClrBlue = { 0.0, 0.0, 1.0 }; // @ 801A8094
53
static struct GdColour sClrErrDarkBlue = { 0.0, 0.0, 6.0 }; // @ 801A80A0
54
static struct GdColour sClrPink = { 1.0, 0.0, 1.0 }; // @ 801A80AC
55
static struct GdColour sClrBlack = { 0.0, 0.0, 0.0 }; // @ 801A80B8
56
static struct GdColour sClrGrey = { 0.6, 0.6, 0.6 }; // @ 801A80C4
57
static struct GdColour sClrDarkGrey = { 0.4, 0.4, 0.4 }; // @ 801A80D0
58
static struct GdColour sClrYellow = { 1.0, 1.0, 0.0 }; // @ 801A80DC
59
static struct GdColour sLightColours[1] = { { 1.0, 1.0, 0.0 } }; // @ 801A80E8
60
static struct GdColour *sSelectedColour = &sClrRed; // @ 801A80F4
61
struct ObjCamera *gViewUpdateCamera = NULL; // @ 801A80F8
62
UNUSED static void *sUnref801A80FC = NULL;
63
static s32 sUnreadShapeFlag = 0; // @ 801A8100
64
struct GdColour *sColourPalette[5] = { // @ 801A8104
65
&sClrWhite, &sClrYellow, &sClrRed, &sClrBlack, &sClrBlack
66
};
67
struct GdColour *sWhiteBlack[2] = {
68
//@ 801A8118
69
&sClrWhite,
70
&sClrBlack,
71
};
72
UNUSED static Mat4f sUnref801A8120 = {
73
{ 1.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0, 1.0 }
74
};
75
UNUSED static Mat4f sUnrefIden801A8160 = {
76
{ 1.0, 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0, 1.0 }
77
};
78
static s32 sLightDlCounter = 1; // @ 801A81A0
79
UNUSED static s32 sUnref801A81A4[4] = { 0 };
80
81
// bss
82
u8 gUnref_801B9B30[0x88];
83
struct ObjGroup *gGdLightGroup; // @ 801B9BB8; is this the main light group? only light group?
84
85
UNUSED static u8 sUnref_801B9BBC[0x40];
86
static enum SceneType sSceneProcessType; // @ 801B9C00
87
static s32 sUseSelectedColor; // @ 801B9C04
88
static s16 sPickBuffer[100]; ///< buffer of objects near click
89
static s32 sPickDataTemp; ///< now, only data is the object number of a selected joint
90
static f32 sPickObjDistance; ///< distance between object position and cursor click location
91
static struct GdObj *sPickedObject; ///< object selected with cursor
92
/// Various counters and pointers set in update_view() and used in various `draw_XXX` functions
93
static struct {
94
u32 pad00; // @ 801B9CE0
95
struct ObjView *view; // @ 801B9CE4
96
s32 unreadCounter; // @ 801B9CE8
97
s32 mtlDlNum; // @ 801B9CEC; name is a big guess
98
s32 shapesDrawn; // @ 801B9CF0
99
s32 unused18; // @ 801B9CF4
100
} sUpdateViewState;
101
static struct ObjLight *sPhongLight; // material light? phong light?
102
static struct GdVec3f sPhongLightPosition; //@ 801B9D00; guess; light source unit position for light
103
// flagged 0x20 (sPhongLight)
104
static struct GdVec3f sLightPositionOffset; // @ 801B9D10
105
static struct GdVec3f sLightPositionCache[8]; // @ 801B9D20; unit positions
106
static s32 sNumActiveLights; // @ 801B9D80; maybe?
107
static struct GdVec3f sGrabCords; ///< x, y grabbable point near cursor
108
109
/**
110
* Set the ambient light color and turn on G_CULL_BACK.
111
*/
112
void setup_lights(void) {
113
set_light_num(NUMLIGHTS_2);
114
gd_setproperty(GD_PROP_AMB_COLOUR, 0.5f, 0.5f, 0.5f);
115
gd_setproperty(GD_PROP_CULLING, 1.0f, 0.0f, 0.0f); // set G_CULL_BACK
116
return;
117
118
// dead code
119
gd_setproperty(GD_PROP_STUB17, 2.0f, 0.0f, 0.0f);
120
gd_setproperty(GD_PROP_ZBUF_FN, 24.0f, 0.0f, 0.0f);
121
gd_setproperty(GD_PROP_CULLING, 1.0f, 0.0f, 0.0f);
122
return;
123
}
124
125
/**
126
* @note Not called
127
*/
128
void Unknown801781DC(struct ObjZone *zone) {
129
struct GdVec3f lightPos; // 3c
130
struct ObjUnk200000 *unk;
131
f32 sp34;
132
f32 sp30;
133
f32 sp2C;
134
struct ObjLight *light;
135
register struct ListNode *link = zone->unk30->firstMember; // s0 (24)
136
struct GdObj *obj; // 20
137
138
while (link != NULL) {
139
obj = link->obj;
140
light = (struct ObjLight *) gGdLightGroup->firstMember->obj;
141
lightPos.x = light->position.x;
142
lightPos.y = light->position.y;
143
lightPos.z = light->position.z;
144
unk = (struct ObjUnk200000 *) obj;
145
sp34 = gd_dot_vec3f(&unk->unk34->normal, &unk->unk30->pos);
146
sp30 = gd_dot_vec3f(&unk->unk34->normal, &lightPos);
147
lightPos.x -= unk->unk34->normal.x * (sp30 - sp34);
148
lightPos.y -= unk->unk34->normal.y * (sp30 - sp34);
149
lightPos.z -= unk->unk34->normal.z * (sp30 - sp34);
150
unk->unk30->pos.x = lightPos.x;
151
unk->unk30->pos.y = lightPos.y;
152
unk->unk30->pos.z = lightPos.z;
153
sp2C = ABS((sp30 - sp34));
154
if (sp2C > 600.0f) {
155
sp2C = 600.0f;
156
}
157
sp2C = 1.0 - sp2C / 600.0;
158
unk->unk30->normal.x = sp2C * light->colour.r;
159
unk->unk30->normal.y = sp2C * light->colour.g;
160
unk->unk30->normal.z = sp2C * light->colour.b;
161
link = link->next;
162
}
163
}
164
165
/* 226C6C -> 226FDC */
166
void draw_shape(struct ObjShape *shape, s32 flag, f32 c, f32 d, f32 e, // "sweep" indices 0-2 x, y, z
167
f32 f, f32 g, f32 h, // translate shape + store offset (unused)
168
f32 i, f32 j, f32 k, // translate shape
169
f32 l, f32 m, f32 n, // rotate x, y, z
170
s32 colorIdx, Mat4f *rotMtx) {
171
UNUSED u8 unused[8];
172
struct GdVec3f sp1C;
173
174
restart_timer("drawshape");
175
sUpdateViewState.shapesDrawn++;
176
177
if (shape == NULL) {
178
return;
179
}
180
181
sp1C.x = sp1C.y = sp1C.z = 0.0f;
182
if (flag & 2) {
183
gd_dl_load_trans_matrix(f, g, h);
184
sp1C.x += f;
185
sp1C.y += g;
186
sp1C.z += h;
187
}
188
189
if ((flag & 0x10) && rotMtx != NULL) {
190
gd_dl_load_matrix(rotMtx);
191
sp1C.x += (*rotMtx)[3][0];
192
sp1C.y += (*rotMtx)[3][1];
193
sp1C.z += (*rotMtx)[3][2];
194
}
195
196
if (flag & 8) {
197
if (m != 0.0f) {
198
func_8019F2C4(m, 121);
199
}
200
if (l != 0.0f) {
201
func_8019F2C4(l, 120);
202
}
203
if (n != 0.0f) {
204
func_8019F2C4(n, 122);
205
}
206
}
207
208
if (colorIdx != 0) {
209
sUseSelectedColor = TRUE;
210
sSelectedColour = gd_get_colour(colorIdx);
211
if (sSelectedColour != NULL) {
212
gd_dl_material_lighting(-1, sSelectedColour, GD_MTL_LIGHTS);
213
} else {
214
fatal_print("Draw_shape(): Bad colour");
215
}
216
} else {
217
sUseSelectedColor = FALSE;
218
sSelectedColour = NULL;
219
}
220
221
if (sNumActiveLights != 0 && shape->mtlGroup != NULL) {
222
if (rotMtx != NULL) {
223
sp1C.x = (*rotMtx)[3][0];
224
sp1C.y = (*rotMtx)[3][1];
225
sp1C.z = (*rotMtx)[3][2];
226
} else {
227
sp1C.x = sp1C.y = sp1C.z = 0.0f;
228
}
229
update_shaders(shape, &sp1C);
230
}
231
232
if (flag & 4) {
233
gd_dl_mul_trans_matrix(i, j, k);
234
}
235
236
if (flag & 1) {
237
gd_dl_scale(c, d, e);
238
}
239
240
draw_shape_faces(shape);
241
sUseSelectedColor = FALSE;
242
split_timer("drawshape");
243
}
244
245
void draw_shape_2d(struct ObjShape *shape, s32 flag, UNUSED f32 c, UNUSED f32 d, UNUSED f32 e, f32 f,
246
f32 g, f32 h, UNUSED f32 i, UNUSED f32 j, UNUSED f32 k, UNUSED f32 l, UNUSED f32 m,
247
UNUSED f32 n, UNUSED s32 color, UNUSED s32 p) {
248
UNUSED u8 unused[8];
249
struct GdVec3f sp1C;
250
251
restart_timer("drawshape2d");
252
sUpdateViewState.shapesDrawn++;
253
254
if (shape == NULL) {
255
return;
256
}
257
258
if (flag & 2) {
259
sp1C.x = f;
260
sp1C.y = g;
261
sp1C.z = h;
262
if (gViewUpdateCamera != NULL) {
263
gd_rotate_and_translate_vec3f(&sp1C, &gViewUpdateCamera->unkE8);
264
}
265
gd_dl_load_trans_matrix(sp1C.x, sp1C.y, sp1C.z);
266
}
267
draw_shape_faces(shape);
268
split_timer("drawshape2d");
269
}
270
271
void draw_light(struct ObjLight *light) {
272
struct GdVec3f sp94;
273
Mat4f sp54;
274
UNUSED Mat4f *uMatPtr;
275
UNUSED f32 uMultiplier;
276
struct ObjShape *shape;
277
278
if (sSceneProcessType == FIND_PICKS) {
279
return;
280
}
281
282
sLightColours[0].r = light->colour.r;
283
sLightColours[0].g = light->colour.g;
284
sLightColours[0].b = light->colour.b;
285
286
if (light->flags & LIGHT_UNK02) {
287
gd_set_identity_mat4(&sp54);
288
sp94.x = -light->unk80.x;
289
sp94.y = -light->unk80.y;
290
sp94.z = -light->unk80.z;
291
gd_create_origin_lookat(&sp54, &sp94, 0.0f);
292
uMultiplier = light->unk38 / 45.0;
293
shape = gSpotShape;
294
uMatPtr = &sp54;
295
} else {
296
uMultiplier = 1.0f;
297
shape = light->unk9C;
298
uMatPtr = NULL;
299
if (++sLightDlCounter >= 17) {
300
sLightDlCounter = 1;
301
}
302
shape->unk50 = sLightDlCounter;
303
}
304
305
draw_shape_2d(shape, 2, 1.0f, 1.0f, 1.0f, light->position.x, light->position.y, light->position.z,
306
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1, 0);
307
}
308
309
void draw_material(struct ObjMaterial *mtl) {
310
s32 mtlType = mtl->type; // 24
311
312
if (mtlType == GD_MTL_SHINE_DL) {
313
if (sPhongLight != NULL && sPhongLight->unk30 > 0.0f) {
314
if (gViewUpdateCamera != NULL) {
315
gd_dl_hilite(mtl->gddlNumber, gViewUpdateCamera, &sPhongLight->position,
316
&sLightPositionOffset, &sPhongLightPosition, &sPhongLight->colour);
317
} else {
318
fatal_printf("draw_material() no active camera for phong");
319
}
320
} else {
321
mtlType = GD_MTL_BREAK;
322
}
323
}
324
if (sUseSelectedColor == FALSE) {
325
gd_dl_material_lighting(mtl->gddlNumber, &mtl->Kd, mtlType);
326
} else {
327
gd_dl_material_lighting(mtl->gddlNumber, sSelectedColour, GD_MTL_LIGHTS);
328
}
329
}
330
331
/**
332
* Create a `GdDisplayList` and store its number in the input `ObjMaterial`
333
* if this material doesn't have one
334
*/
335
void create_mtl_gddl_if_empty(struct ObjMaterial *mtl) {
336
if (mtl->gddlNumber == 0) {
337
mtl->gddlNumber = create_mtl_gddl(mtl->type);
338
}
339
}
340
341
/**
342
* A function for checking if an `ObjFace` has bad vertices. These could be either
343
* unconverted vertex data, or old vertex structures (like `BetaVtx`)
344
* @note Not called
345
*/
346
void check_face_bad_vtx(struct ObjFace *face) {
347
s32 i;
348
struct ObjVertex *vtx;
349
350
for (i = 0; i < face->vtxCount; i++) {
351
vtx = face->vertices[i];
352
// These seem to be checks against bad conversions, or an outdated vertex structure..?
353
if ((uintptr_t) vtx == 39) {
354
gd_printf("bad1\n");
355
return;
356
}
357
if ((uintptr_t) vtx->gbiVerts == 0x3F800000) {
358
fatal_printf("bad2 %x,%d,%d,%d\n", (u32) (uintptr_t) vtx, vtx->scaleFactor, vtx->id, vtx->header.type);
359
}
360
}
361
}
362
363
/**
364
* @brief Convert a numeric index into pointer to a struct GdColour
365
*
366
* A simple switch case to convert from index @p idx to a pointer to the
367
* three f32 GdColour structure. Goddard stored the index in a structure,
368
* and uses this function to get the colour RGB values if needed.
369
* -1 uses the environment colour.
370
* A possible enhancement for this is to ennumerate all colours, and then
371
* use those enumerations and/or enum type where ever a colour is requested
372
*
373
* @param idx Index of colour
374
* @return Pointer to a GdColour struct
375
*/
376
struct GdColour *gd_get_colour(s32 idx) {
377
switch (idx) {
378
case COLOUR_BLACK:
379
return &sClrBlack;
380
break;
381
case COLOUR_WHITE:
382
return &sClrWhite;
383
break;
384
case COLOUR_RED:
385
return &sClrRed;
386
break;
387
case COLOUR_GREEN:
388
return &sClrGreen;
389
break;
390
case COLOUR_BLUE:
391
return &sClrBlue;
392
break;
393
case COLOUR_GRAY:
394
return &sClrGrey;
395
break;
396
case COLOUR_DARK_GRAY:
397
return &sClrDarkGrey;
398
break;
399
case COLOUR_DARK_BLUE:
400
return &sClrErrDarkBlue;
401
break;
402
case COLOUR_BLACK2:
403
return &sClrBlack;
404
break;
405
case COLOUR_YELLOW:
406
return &sClrYellow;
407
break;
408
case COLOUR_PINK:
409
return &sClrPink;
410
break;
411
case -1:
412
return &sLightColours[0];
413
break;
414
default:
415
return NULL;
416
}
417
}
418
419
/**
420
* Uncalled function that would render a triangle
421
* @note Not called
422
*/
423
void Unknown80178ECC(f32 v0X, f32 v0Y, f32 v0Z, f32 v1X, f32 v1Y, f32 v1Z) {
424
f32 difY = v1Y - v0Y;
425
f32 difX = v1X - v0X;
426
f32 difZ = v1Z - v0Z;
427
428
gd_dl_make_triangle(v0X, v0Y, v0Z, v1X, v1Y, v1Z, v0X + difY * 0.1, v0Y + difX * 0.1, v0Z + difZ * 0.1);
429
}
430
431
/**
432
* Rendering function for `ObjFace` structures. It has a fair amount
433
* of stub code
434
*/
435
void draw_face(struct ObjFace *face) {
436
struct ObjVertex *vtx; // 3c
437
f32 z; // 38
438
f32 y; // 34
439
f32 x; // 30
440
UNUSED u8 pad[12];
441
s32 i; // 20; also used to store mtl's gddl number
442
s32 hasTextCoords; // 1c
443
Vtx *gbiVtx; // 18
444
445
imin("draw_face");
446
hasTextCoords = FALSE;
447
if (sUseSelectedColor == FALSE && face->mtlId >= 0) // -1 == colored face
448
{
449
if (face->mtl != NULL) {
450
if ((i = face->mtl->gddlNumber) != 0) {
451
if (i != sUpdateViewState.mtlDlNum) {
452
gd_dl_flush_vertices();
453
branch_to_gddl(i);
454
sUpdateViewState.mtlDlNum = i;
455
}
456
}
457
}
458
459
if (FALSE) {
460
}
461
}
462
463
check_tri_display(face->vtxCount);
464
465
if (!gGdUseVtxNormal) {
466
set_Vtx_norm_buf_1(&face->normal);
467
}
468
469
for (i = 0; i < face->vtxCount; i++) {
470
vtx = face->vertices[i];
471
x = vtx->pos.x;
472
y = vtx->pos.y;
473
z = vtx->pos.z;
474
if (gGdUseVtxNormal) {
475
set_Vtx_norm_buf_2(&vtx->normal);
476
}
477
//! @bug This function seems to have some parts based on older versions of ObjVertex
478
//! as the struct requests fields passed the end of an ObjVertex.
479
//! The bad code is statically unreachable, so...
480
if (hasTextCoords) {
481
set_vtx_tc_buf(((struct BetaVtx *) vtx)->s, ((struct BetaVtx *) vtx)->t);
482
}
483
484
gbiVtx = gd_dl_make_vertex(x, y, z, vtx->alpha);
485
486
if (gbiVtx != NULL) {
487
vtx->gbiVerts = make_vtx_link(vtx->gbiVerts, gbiVtx);
488
}
489
}
490
func_8019FEF0();
491
imout();
492
}
493
494
/**
495
* Render a filled rectangle from (`ulx`, `uly`) to (`lrx`, `lry`).
496
*
497
* @param color `GdColour` index
498
* @param ulx,uly upper left point
499
* @param lrx,lry lower right point
500
*/
501
void draw_rect_fill(s32 color, f32 ulx, f32 uly, f32 lrx, f32 lry) {
502
gd_dl_set_fill(gd_get_colour(color));
503
gd_draw_rect(ulx, uly, lrx, lry);
504
}
505
506
/**
507
* Render a stroked rectangle (aka border box) from (`ulx`, `uly`) to (`lrx`, `lry`).
508
*
509
* @param color `GdColour` index
510
* @param ulx,uly upper left point
511
* @param lrx,lry lower right point
512
*/
513
void draw_rect_stroke(s32 color, f32 ulx, f32 uly, f32 lrx, f32 lry) {
514
gd_dl_set_fill(gd_get_colour(color));
515
gd_draw_border_rect(ulx, uly, lrx, lry);
516
}
517
518
/**
519
* Uncalled function that calls other orphan stub functions.
520
* @note Not called
521
*/
522
void Unknown801792F0(struct GdObj *obj) {
523
char objId[32];
524
struct GdVec3f objPos;
525
526
format_object_id(objId, obj);
527
set_cur_dynobj(obj);
528
d_get_world_pos(&objPos);
529
func_801A4438(objPos.x, objPos.y, objPos.z);
530
stub_draw_label_text(objId);
531
}
532
533
/**
534
* Draws a label
535
*/
536
void draw_label(struct ObjLabel *label) {
537
struct GdVec3f position;
538
char strbuf[0x100];
539
UNUSED u8 unused[16];
540
struct ObjValPtr *valptr;
541
union ObjVarVal varval;
542
valptrproc_t valfn = label->valfn;
543
544
if ((valptr = label->valptr) != NULL) {
545
if (valptr->flag == 0x40000) {
546
// position is offset from object
547
set_cur_dynobj(valptr->obj);
548
d_get_world_pos(&position);
549
} else {
550
// position is absolute
551
position.x = position.y = position.z = 0.0f;
552
}
553
554
switch (valptr->datatype) {
555
case OBJ_VALUE_FLOAT:
556
get_objvalue(&varval, OBJ_VALUE_FLOAT, valptr->obj, valptr->offset);
557
if (valfn != NULL) {
558
valfn(&varval, varval);
559
}
560
sprintf(strbuf, label->fmtstr, varval.f);
561
break;
562
case OBJ_VALUE_INT:
563
get_objvalue(&varval, OBJ_VALUE_INT, valptr->obj, valptr->offset);
564
if (valfn != NULL) {
565
valfn(&varval, varval);
566
}
567
sprintf(strbuf, label->fmtstr, varval.i);
568
break;
569
default:
570
if (label->fmtstr != NULL) {
571
gd_strcpy(strbuf, label->fmtstr);
572
} else {
573
gd_strcpy(strbuf, "NONAME");
574
}
575
break;
576
}
577
} else {
578
position.x = position.y = position.z = 0.0f;
579
if (label->fmtstr != NULL) {
580
gd_strcpy(strbuf, label->fmtstr);
581
} else {
582
gd_strcpy(strbuf, "NONAME");
583
}
584
}
585
position.x += label->position.x;
586
position.y += label->position.y;
587
position.z += label->position.z;
588
func_801A4438(position.x, position.y, position.z);
589
stub_renderer_10(label->unk30);
590
stub_draw_label_text(strbuf);
591
}
592
593
/* 227DF8 -> 227F3C; orig name: Proc80179628 */
594
void draw_net(struct ObjNet *self) {
595
struct ObjNet *net = self;
596
s32 netColor;
597
UNUSED u8 unused[80];
598
599
if (sSceneProcessType == FIND_PICKS) {
600
return;
601
}
602
603
if (net->header.drawFlags & OBJ_HIGHLIGHTED) {
604
netColor = COLOUR_YELLOW;
605
} else {
606
netColor = net->colourNum;
607
}
608
609
if (net->shapePtr != NULL) {
610
draw_shape(net->shapePtr, 0x10, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
611
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, netColor, &net->mat168);
612
}
613
614
if (net->unk1C8 != NULL) {
615
draw_group(net->unk1C8);
616
}
617
}
618
619
/**
620
* Draws a gadget
621
*/
622
void draw_gadget(struct ObjGadget *gdgt) {
623
s32 colour = 0;
624
625
if (gdgt->colourNum != 0) {
626
colour = gdgt->colourNum;
627
}
628
629
draw_rect_fill(colour,
630
gdgt->worldPos.x,
631
gdgt->worldPos.y,
632
gdgt->worldPos.x + gdgt->sliderPos * gdgt->size.x,
633
gdgt->worldPos.y + gdgt->size.y);
634
635
if (gdgt->header.drawFlags & OBJ_HIGHLIGHTED) {
636
draw_rect_stroke(COLOUR_YELLOW,
637
gdgt->worldPos.x,
638
gdgt->worldPos.y,
639
gdgt->worldPos.x + gdgt->sliderPos * gdgt->size.x,
640
gdgt->worldPos.y + gdgt->size.y);
641
}
642
gdgt->header.drawFlags &= ~OBJ_HIGHLIGHTED;
643
}
644
645
/* 22803C -> 22829C */
646
void draw_camera(struct ObjCamera *cam) {
647
struct GdVec3f sp44;
648
UNUSED f32 sp40 = 0.0f;
649
650
sp44.x = 0.0f;
651
sp44.y = 0.0f;
652
sp44.z = 0.0f;
653
if (cam->unk30 != NULL) {
654
set_cur_dynobj(cam->unk30);
655
d_get_world_pos(&sp44);
656
sp44.x += cam->lookAt.x;
657
sp44.y += cam->lookAt.y;
658
sp44.z += cam->lookAt.z;
659
; // needed to match
660
} else {
661
sp44.x = cam->lookAt.x;
662
sp44.y = cam->lookAt.y;
663
sp44.z = cam->lookAt.z;
664
}
665
666
if (0) {
667
// dead code
668
gd_printf("%f,%f,%f\n", cam->worldPos.x, cam->worldPos.y, cam->worldPos.z);
669
}
670
671
if (ABS(cam->worldPos.x - sp44.x) + ABS(cam->worldPos.z - sp44.z) == 0.0f) {
672
gd_printf("Draw_Camera(): Zero view distance\n");
673
return;
674
}
675
gd_dl_lookat(cam, cam->worldPos.x, cam->worldPos.y, cam->worldPos.z, sp44.x, sp44.y, sp44.z, cam->unkA4);
676
}
677
678
/**
679
* Forms uncalled recursive loop with func_80179B64().
680
* This function seems to turn off the otherwise unused `OBJ_DRAW_UNK01` flag
681
* for the GdObj.drawFlags
682
* @note Not called
683
*/
684
void Unknown80179ACC(struct GdObj *obj) {
685
switch (obj->type) {
686
case OBJ_TYPE_NETS:
687
if (((struct ObjNet *) obj)->unk1C8 != NULL) {
688
func_80179B64(((struct ObjNet *) obj)->unk1C8);
689
}
690
break;
691
default:
692
break;
693
}
694
obj->drawFlags &= ~OBJ_DRAW_UNK01;
695
}
696
697
/**
698
* Forms uncalled recursive loop with Unknown80179ACC()
699
* @note Not called
700
*/
701
void func_80179B64(struct ObjGroup *group) {
702
apply_to_obj_types_in_group(OBJ_TYPE_LABELS | OBJ_TYPE_GADGETS | OBJ_TYPE_CAMERAS | OBJ_TYPE_NETS
703
| OBJ_TYPE_JOINTS | OBJ_TYPE_BONES,
704
(applyproc_t) Unknown80179ACC, group);
705
}
706
707
/* 22836C -> 228498 */
708
void world_pos_to_screen_coords(struct GdVec3f *pos, struct ObjCamera *cam, struct ObjView *view) {
709
gd_rotate_and_translate_vec3f(pos, &cam->unkE8);
710
if (pos->z > -256.0f) {
711
return;
712
}
713
714
pos->x *= 256.0 / -pos->z;
715
pos->y *= 256.0 / pos->z;
716
pos->x += view->lowerRight.x / 2.0f;
717
pos->y += view->lowerRight.y / 2.0f;
718
}
719
720
/**
721
* Check if the current cursor position is near enough to @p input to
722
* grab that `GdObj`. The range is +/- 20 units for being close to a
723
* grab point.
724
*
725
* If the object can be grabbed, its information is stored in a buffer by
726
* `store_in_pickbuf()`.
727
*
728
* @param input `GdObj` to check position of
729
* @return void
730
*/
731
void check_grabable_click(struct GdObj *input) {
732
struct GdVec3f objPos;
733
UNUSED u8 unused[12];
734
struct GdObj *obj;
735
Mat4f *mtx;
736
737
if (gViewUpdateCamera == NULL) {
738
return;
739
}
740
obj = input;
741
if (!(obj->drawFlags & OBJ_IS_GRABBALE)) {
742
return;
743
}
744
745
set_cur_dynobj(obj);
746
mtx = d_get_rot_mtx_ptr();
747
objPos.x = (*mtx)[3][0];
748
objPos.y = (*mtx)[3][1];
749
objPos.z = (*mtx)[3][2];
750
world_pos_to_screen_coords(&objPos, gViewUpdateCamera, sUpdateViewState.view);
751
if (ABS(gGdCtrl.csrX - objPos.x) < 20.0f) {
752
if (ABS(gGdCtrl.csrY - objPos.y) < 20.0f) {
753
// store (size, Obj Type, Obj Index) in s16 pick buffer array
754
store_in_pickbuf(2);
755
store_in_pickbuf(obj->type);
756
store_in_pickbuf(obj->index);
757
sGrabCords.x = objPos.x;
758
sGrabCords.y = objPos.y;
759
}
760
}
761
}
762
763
/**
764
* The main function for rendering the components of an `ObjView`. It called
765
* both for drawing the various `GdObj` primatives as well as when checking
766
* the location of a cursor click.
767
* @note This has to be called from update_view() due to that function setting
768
* state variables on which this function relies
769
*
770
* @param process determines if this is rendering the scene
771
* or just checking click location
772
* @param interactables components of `ObjView`
773
* @param lightgrp lights of `ObjView
774
*/
775
void drawscene(enum SceneType process, struct ObjGroup *interactables, struct ObjGroup *lightgrp) {
776
UNUSED u8 unused[16];
777
778
restart_timer("drawscene");
779
imin("draw_scene()");
780
sUnreadShapeFlag = 0;
781
sUpdateViewState.unreadCounter = 0;
782
restart_timer("draw1");
783
set_gd_mtx_parameters(G_MTX_PROJECTION | G_MTX_MUL | G_MTX_PUSH);
784
if (sUpdateViewState.view->projectionType == 1) {
785
gd_create_perspective_matrix(sUpdateViewState.view->clipping.z,
786
sUpdateViewState.view->lowerRight.x / sUpdateViewState.view->lowerRight.y,
787
sUpdateViewState.view->clipping.x, sUpdateViewState.view->clipping.y);
788
} else {
789
gd_create_ortho_matrix(
790
-sUpdateViewState.view->lowerRight.x / 2.0, sUpdateViewState.view->lowerRight.x / 2.0,
791
-sUpdateViewState.view->lowerRight.y / 2.0, sUpdateViewState.view->lowerRight.y / 2.0,
792
sUpdateViewState.view->clipping.x, sUpdateViewState.view->clipping.y);
793
}
794
795
if (lightgrp != NULL) {
796
set_gd_mtx_parameters(G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH);
797
apply_to_obj_types_in_group(OBJ_TYPE_LIGHTS | OBJ_TYPE_PARTICLES,
798
(applyproc_t) apply_obj_draw_fn, lightgrp);
799
set_gd_mtx_parameters(G_MTX_PROJECTION | G_MTX_MUL | G_MTX_PUSH);
800
}
801
802
if (gViewUpdateCamera != NULL) {
803
draw_camera(gViewUpdateCamera);
804
} else {
805
gd_dl_mul_trans_matrix(0.0f, 0.0f, -1000.0f);
806
}
807
808
setup_lights();
809
set_gd_mtx_parameters(G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH);
810
gd_dl_push_matrix();
811
sSceneProcessType = process;
812
813
if ((sNumActiveLights = sUpdateViewState.view->flags & VIEW_LIGHT)) {
814
sUpdateViewState.view->flags &= ~VIEW_LIGHT;
815
}
816
817
sNumActiveLights = 1;
818
apply_to_obj_types_in_group(OBJ_TYPE_LIGHTS, (applyproc_t) register_light, gGdLightGroup);
819
split_timer("draw1");
820
restart_timer("drawobj");
821
imin("process_group");
822
if (sSceneProcessType == FIND_PICKS) {
823
apply_to_obj_types_in_group(OBJ_TYPE_ALL, (applyproc_t) check_grabable_click, interactables);
824
} else {
825
apply_to_obj_types_in_group(OBJ_TYPE_LIGHTS | OBJ_TYPE_GADGETS | OBJ_TYPE_NETS
826
| OBJ_TYPE_PARTICLES,
827
(applyproc_t) apply_obj_draw_fn, interactables);
828
}
829
imout();
830
split_timer("drawobj");
831
gd_setproperty(GD_PROP_LIGHTING, 0.0f, 0.0f, 0.0f);
832
apply_to_obj_types_in_group(OBJ_TYPE_LABELS, (applyproc_t) apply_obj_draw_fn, interactables);
833
gd_setproperty(GD_PROP_LIGHTING, 1.0f, 0.0f, 0.0f);
834
gd_dl_pop_matrix();
835
imout();
836
split_timer("drawscene");
837
return;
838
}
839
840
/**
841
* A drawing function that does nothing. This function is used for
842
* `GdObj`s that don't need to be rendered
843
*/
844
void draw_nothing(UNUSED struct GdObj *nop) {
845
}
846
847
/**
848
* Render the `faceGroup` of an `ObjShape`. This is called from
849
* draw_shape() and draw_shape_2d(), or when creating the shape
850
* `GdDisplayList` when calling create_shape_gddl()
851
*/
852
void draw_shape_faces(struct ObjShape *shape) {
853
sUpdateViewState.mtlDlNum = 0;
854
sUpdateViewState.unreadCounter = 0;
855
gddl_is_loading_stub_dl(FALSE);
856
sUnreadShapeFlag = (s32) shape->flag & 1;
857
set_render_alpha(shape->alpha);
858
if (shape->dlNums[gGdFrameBufNum] != 0) {
859
draw_indexed_dl(shape->dlNums[gGdFrameBufNum], shape->unk50);
860
} else if (shape->faceGroup != NULL) {
861
func_801A0038();
862
draw_group(shape->faceGroup);
863
gd_dl_flush_vertices();
864
}
865
}
866
867
/**
868
* Rendering function for `ObjParticle`.
869
*/
870
void draw_particle(struct GdObj *obj) {
871
struct ObjParticle *ptc = (struct ObjParticle *) obj;
872
UNUSED u8 unused1[16];
873
struct GdColour *white;
874
struct GdColour *black;
875
f32 brightness;
876
UNUSED u8 unused2[16];
877
878
if (ptc->timeout > 0) {
879
white = sColourPalette[0];
880
black = sWhiteBlack[1];
881
brightness = ptc->timeout / 10.0;
882
sLightColours[0].r = (white->r - black->r) * brightness + black->r;
883
sLightColours[0].g = (white->g - black->g) * brightness + black->g;
884
sLightColours[0].b = (white->b - black->b) * brightness + black->b;
885
; // needed to match
886
} else {
887
sLightColours[0].r = 0.0f;
888
sLightColours[0].g = 0.0f;
889
sLightColours[0].b = 0.0f;
890
}
891
892
if (ptc->timeout > 0) {
893
ptc->shapePtr->unk50 = ptc->timeout;
894
draw_shape_2d(ptc->shapePtr, 2, 1.0f, 1.0f, 1.0f, ptc->pos.x, ptc->pos.y, ptc->pos.z, 0.0f,
895
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1, 0);
896
}
897
if (ptc->unk60 == 3) {
898
if (ptc->subParticlesGrp != NULL) {
899
draw_group(ptc->subParticlesGrp);
900
}
901
}
902
}
903
904
/**
905
* Rendering fucntion for `ObjBone`.
906
*
907
* @note This function returns before doing any work. It seems
908
* that Goddard moved away from using bones in the final code
909
*/
910
void draw_bone(struct GdObj *obj) {
911
struct ObjBone *bone = (struct ObjBone *) obj;
912
UNUSED u8 unused1[4];
913
s32 colour;
914
UNUSED u8 unused2[4];
915
struct GdVec3f scale; // guess
916
917
return;
918
919
// dead code
920
scale.x = 1.0f;
921
scale.y = 1.0f;
922
scale.z = bone->unkF8 / 50.0f;
923
924
if (bone->header.drawFlags & OBJ_HIGHLIGHTED) {
925
colour = COLOUR_YELLOW;
926
} else {
927
colour = bone->colourNum;
928
}
929
bone->header.drawFlags &= ~OBJ_HIGHLIGHTED;
930
931
if (sSceneProcessType != FIND_PICKS) {
932
draw_shape(bone->shapePtr, 0x1B, scale.x, scale.y, scale.z, bone->worldPos.x, bone->worldPos.y,
933
bone->worldPos.z, 0.0f, 0.0f, 0.0f, bone->unk28.x, bone->unk28.y, bone->unk28.z, colour,
934
&bone->mat70);
935
}
936
}
937
938
/**
939
* Rendering function for `ObjJoint`.
940
*/
941
void draw_joint(struct GdObj *obj) {
942
struct ObjJoint *joint = (struct ObjJoint *) obj;
943
UNUSED u8 unused1[4];
944
UNUSED f32 sp7C = 70.0f;
945
UNUSED u8 unused2[4];
946
UNUSED s32 sp74 = 1;
947
s32 colour;
948
UNUSED u8 unused[8];
949
struct ObjShape *boneShape;
950
UNUSED u8 unused3[28];
951
952
if ((boneShape = joint->shapePtr) == NULL) {
953
return;
954
}
955
956
if (joint->header.drawFlags & OBJ_HIGHLIGHTED) {
957
colour = COLOUR_YELLOW;
958
} else {
959
colour = joint->colourNum;
960
}
961
962
draw_shape(boneShape, 0x10, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
963
colour, &joint->mat128);
964
}
965
966
/**
967
* Call `apply_obj_draw_fn()` to all `GdObj` in input `ObjGroup`
968
*
969
* @param grp `ObjGroup` of objects to draw
970
* @return void
971
*/
972
void draw_group(struct ObjGroup *grp) {
973
if (grp == NULL) {
974
fatal_print("Draw_Group: Bad group definition!");
975
}
976
977
apply_to_obj_types_in_group(OBJ_TYPE_ALL, (applyproc_t) apply_obj_draw_fn, grp);
978
}
979
980
/**
981
* Rendering function for `ObjPlane`.
982
*/
983
void draw_plane(struct GdObj *obj) {
984
struct ObjPlane *plane = (struct ObjPlane *) obj;
985
986
if (obj->drawFlags & OBJ_HIGHLIGHTED) {
987
obj->drawFlags &= ~OBJ_HIGHLIGHTED;
988
; // needed to match; presumably setting up the color to draw the plane with
989
} else {
990
sUseSelectedColor = FALSE;
991
}
992
draw_face(plane->unk40);
993
}
994
995
/**
996
* Apply `GdObj.objDrawFn` to the input `GdObj` if that object is draw-able.
997
*
998
* @param obj `GdObj` to draw
999
* @return void
1000
*/
1001
void apply_obj_draw_fn(struct GdObj *obj) {
1002
if (obj == NULL) {
1003
fatal_print("Bad object!");
1004
}
1005
if (obj->drawFlags & OBJ_INVISIBLE) {
1006
return;
1007
}
1008
1009
obj->objDrawFn(obj);
1010
}
1011
1012
/**
1013
* Count input `ObjLight` as an active light, if it wasn't already counted.
1014
*/
1015
void register_light(struct ObjLight *light) {
1016
set_light_id(light->id);
1017
gd_setproperty(GD_PROP_LIGHTING, 2.0f, 0.0f, 0.0f);
1018
if (light->flags & LIGHT_NEW_UNCOUNTED) {
1019
sNumActiveLights++;
1020
}
1021
light->flags &= ~LIGHT_NEW_UNCOUNTED;
1022
}
1023
1024
/* 229180 -> 229564 */
1025
void Proc8017A980(struct ObjLight *light) {
1026
f32 sp24; // diffuse factor?
1027
f32 sp20;
1028
f32 sp1C;
1029
1030
light->colour.r = light->diffuse.r * light->unk30;
1031
light->colour.g = light->diffuse.g * light->unk30;
1032
light->colour.b = light->diffuse.b * light->unk30;
1033
sLightPositionCache[light->id].x = light->position.x - sLightPositionOffset.x;
1034
sLightPositionCache[light->id].y = light->position.y - sLightPositionOffset.y;
1035
sLightPositionCache[light->id].z = light->position.z - sLightPositionOffset.z;
1036
gd_normalize_vec3f(&sLightPositionCache[light->id]);
1037
if (light->flags & LIGHT_UNK20) {
1038
sPhongLightPosition.x = sLightPositionCache[light->id].x;
1039
sPhongLightPosition.y = sLightPositionCache[light->id].y;
1040
sPhongLightPosition.z = sLightPositionCache[light->id].z;
1041
sPhongLight = light;
1042
}
1043
sp24 = light->unk30;
1044
if (light->flags & LIGHT_UNK02) {
1045
sp20 = -gd_dot_vec3f(&sLightPositionCache[light->id], &light->unk80);
1046
sp1C = 1.0 - light->unk38 / 90.0;
1047
if (sp20 > sp1C) {
1048
sp20 = (sp20 - sp1C) * (1.0 / (1.0 - sp1C));
1049
if (sp20 > 1.0) {
1050
sp20 = 1.0;
1051
} else if (sp20 < 0.0f) {
1052
sp20 = 0.0f;
1053
}
1054
} else {
1055
sp20 = 0.0f;
1056
}
1057
sp24 *= sp20;
1058
}
1059
set_light_id(light->id);
1060
gd_setproperty(GD_PROP_DIFUSE_COLOUR, light->diffuse.r * sp24, light->diffuse.g * sp24,
1061
light->diffuse.b * sp24);
1062
gd_setproperty(GD_PROP_LIGHT_DIR, sLightPositionCache[light->id].x,
1063
sLightPositionCache[light->id].y, sLightPositionCache[light->id].z);
1064
gd_setproperty(GD_PROP_LIGHTING, 2.0f, 0.0f, 0.0f);
1065
}
1066
1067
/* 229568 -> 229658; orig name: func_8017AD98 */
1068
void update_shaders(struct ObjShape *shape, struct GdVec3f *offset) {
1069
restart_timer("updateshaders");
1070
stash_current_gddl();
1071
sLightPositionOffset.x = offset->x;
1072
sLightPositionOffset.y = offset->y;
1073
sLightPositionOffset.z = offset->z;
1074
sPhongLight = NULL;
1075
if (gGdLightGroup != NULL) {
1076
apply_to_obj_types_in_group(OBJ_TYPE_LIGHTS, (applyproc_t) Proc8017A980, gGdLightGroup);
1077
}
1078
if (shape->mtlGroup != NULL) {
1079
apply_to_obj_types_in_group(OBJ_TYPE_MATERIALS, (applyproc_t) apply_obj_draw_fn,
1080
shape->mtlGroup);
1081
}
1082
pop_gddl_stash();
1083
split_timer("updateshaders");
1084
}
1085
1086
/**
1087
* Create `GdDisplayList`s for any `ObjMaterial`s in `shape` that don't already
1088
* have a GdDL. Doesn't do anything if `shape`'s `mtlGroup` is NULL
1089
*
1090
* @param shape Input `ObjShape` to create material GdDLs for
1091
* @return void
1092
*/
1093
void create_shape_mtl_gddls(struct ObjShape *shape) {
1094
if (shape->mtlGroup != NULL) {
1095
apply_to_obj_types_in_group(OBJ_TYPE_MATERIALS, (applyproc_t) create_mtl_gddl_if_empty,
1096
shape->mtlGroup);
1097
}
1098
}
1099
1100
/**
1101
* Uncalled function that calls a stubbed function (`stub_objects_1()`) for all
1102
* `GdObj`s in @p grp
1103
*
1104
* @param grp Unknown group of objects
1105
* @return void
1106
* @note Not called
1107
*/
1108
void unref_8017AEDC(struct ObjGroup *grp) {
1109
register struct ListNode *link = grp->firstMember;
1110
1111
while (link != NULL) {
1112
struct GdObj *obj = link->obj;
1113
1114
stub_objects_1(grp, obj);
1115
link = link->next;
1116
}
1117
}
1118
1119
/**
1120
* Start a new `GdDisplayList` struct and store its reference index
1121
* in the input `ObjShape`.
1122
*
1123
* @param s `ObjShape` to create GdDL for
1124
* @return Either `-1` if the DL couldn't be created,
1125
* or the created DL's reference index
1126
* @bug Nothing is returned if the DL is created
1127
* @note Contains string literals that suggest a removed `printf` call
1128
*/
1129
#ifdef AVOID_UB
1130
void
1131
#else
1132
s32
1133
#endif
1134
create_shape_gddl(struct ObjShape *s) {
1135
struct ObjShape *shape = s; // 24
1136
s32 shapedl; // 20
1137
UNUSED s32 enddl; // 1C
1138
1139
create_shape_mtl_gddls(shape);
1140
shapedl = gd_startdisplist(7);
1141
if (shapedl == 0) {
1142
#ifdef AVOID_UB
1143
return;
1144
#else
1145
return -1;
1146
#endif
1147
}
1148
1149
setup_lights();
1150
sUseSelectedColor = FALSE;
1151
if (shape->unk3C == 0) {
1152
draw_shape_faces(shape);
1153
}
1154
enddl = gd_enddlsplist_parent();
1155
shape->dlNums[0] = shapedl;
1156
shape->dlNums[1] = shapedl;
1157
1158
if (shape->name[0] != '\0') {
1159
printf("Generated '%s' (%d) display list ok.(%d)\n", shape->name, shapedl, enddl);
1160
} else {
1161
printf("Generated 'UNKNOWN' (%d) display list ok.(%d)\n", shapedl, enddl);
1162
}
1163
}
1164
1165
/**
1166
* Create `GdDisplayList` structs for all `ObjShapes` in `grp` by calling
1167
* `create_shape_gddl()`.
1168
*
1169
* @param grp `ObjGroup` containing `ObjShape` to create GdDLs for
1170
* @return void
1171
* @note Contains string literals that suggest a removed `printf` call
1172
*/
1173
void create_gddl_for_shapes(struct ObjGroup *grp) {
1174
UNUSED s32 shapedls =
1175
apply_to_obj_types_in_group(OBJ_TYPE_SHAPES, (applyproc_t) create_shape_gddl, grp);
1176
printf("made %d display lists\n", shapedls);
1177
}
1178
1179
/**
1180
* Map material id's to `ObjMaterial` pointers for an `ObjGroup` of `ObjFace` structs.
1181
* This is the final function used in dynlist processing (see `chk_shapegen()`)
1182
*
1183
* @param[in,out] faces `ObjGroup` of `ObjFace` structs to map over
1184
* @param[in] mtls `ObjGroup` of `ObjMaterial` structs to map ids to pointers
1185
* @return void
1186
*/
1187
void map_face_materials(struct ObjGroup *faces, struct ObjGroup *mtls) {
1188
struct ObjFace *face;
1189
register struct ListNode *linkFaces;
1190
struct GdObj *temp;
1191
register struct ListNode *linkMtls;
1192
struct ObjMaterial *mtl;
1193
1194
linkFaces = faces->firstMember;
1195
while (linkFaces != NULL) {
1196
temp = linkFaces->obj;
1197
face = (struct ObjFace *) temp;
1198
linkMtls = mtls->firstMember;
1199
while (linkMtls != NULL) {
1200
mtl = (struct ObjMaterial *) linkMtls->obj;
1201
if (mtl->id == face->mtlId) {
1202
break;
1203
}
1204
linkMtls = linkMtls->next;
1205
}
1206
1207
if (linkMtls != NULL) {
1208
face->mtl = mtl;
1209
}
1210
1211
linkFaces = linkFaces->next;
1212
}
1213
}
1214
1215
/**
1216
* @brief Calculate the normal for @p vtx by averaging the normals of all
1217
* `ObjFaces` in @p facegrp
1218
*
1219
* Calculate the normal for the input `ObjVetex` @p vtx based on the
1220
* `ObjFace` structures in @p facegrp of which that vertex is a part.
1221
*
1222
* @param vtx `ObjVertex` to update normal
1223
* @param facegrp `ObjGroup` of `ObjFace` structures that use @p vtx
1224
* @return void
1225
*/
1226
static void calc_vtx_normal(struct ObjVertex *vtx, struct ObjGroup *facegrp) {
1227
s32 i;
1228
s32 faceCount;
1229
register struct ListNode *node;
1230
struct ObjFace *curFace;
1231
1232
vtx->normal.x = vtx->normal.y = vtx->normal.z = 0.0f;
1233
1234
faceCount = 0;
1235
node = facegrp->firstMember;
1236
while (node != NULL) {
1237
curFace = (struct ObjFace *) node->obj;
1238
for (i = 0; i < curFace->vtxCount; i++) {
1239
if (curFace->vertices[i] == vtx) {
1240
vtx->normal.x += curFace->normal.x;
1241
vtx->normal.y += curFace->normal.y;
1242
vtx->normal.z += curFace->normal.z;
1243
faceCount++;
1244
}
1245
}
1246
node = node->next;
1247
}
1248
if (faceCount != 0) {
1249
vtx->normal.x /= faceCount;
1250
vtx->normal.y /= faceCount;
1251
vtx->normal.z /= faceCount;
1252
}
1253
}
1254
1255
/**
1256
* @brief Convert vertex indices in an `ObjFace` into pointers and computes the
1257
* face's normal
1258
*
1259
* Using the group of `ObjVertex` or `ObjParticle` structures in @p verts,
1260
* convert indices in @p face into pointers. The indices are indices
1261
* into the list contained in @p vertexGrp group
1262
*
1263
* @param face `ObjFace` to find vertices for
1264
* @param vertexGrp `ObjGroup` to index in for `ObjVertex` or `ObjPaticle` structures
1265
* @return void
1266
*/
1267
static void find_thisface_verts(struct ObjFace *face, struct ObjGroup *vertexGrp) {
1268
s32 i;
1269
u32 currIndex;
1270
struct ListNode *node;
1271
1272
for (i = 0; i < face->vtxCount; i++) {
1273
// find the vertex or particle whose index in vertexGrp equals face->vertices[i]
1274
node = vertexGrp->firstMember;
1275
currIndex = 0;
1276
while (node != NULL) {
1277
if (node->obj->type == OBJ_TYPE_VERTICES || node->obj->type == OBJ_TYPE_PARTICLES) {
1278
if (currIndex++ == (u32) (uintptr_t) face->vertices[i]) {
1279
break;
1280
}
1281
}
1282
node = node->next;
1283
}
1284
if (node == NULL) {
1285
fatal_printf("find_thisface_verts(): Vertex not found");
1286
}
1287
1288
// set the vertex to point to the resolved `ObjVertex`
1289
face->vertices[i] = (struct ObjVertex *) node->obj;
1290
}
1291
calc_face_normal(face);
1292
}
1293
1294
/**
1295
* @brief Convert vertex ID numbers for an `ObjGroup` of `ObjFace`s into pointers
1296
* to `ObjVertex` structures
1297
*
1298
* This function takes an `ObjGroup` of `ObjFace` structures whose `vertices` field
1299
* has indices and not pointers. These indices are transformed into pointers of
1300
* `ObjVertex` or `ObjParticle` structures from the @p vtxgrp `ObjGroup`.
1301
*
1302
* @param facegrp `ObjGroup` of `ObjFaces` to map vertex indices to pointers
1303
* @param vtxgrp `ObjGroup` of `ObjVertices`/`ObjParticles` to be mapped against
1304
* @return void
1305
* @note It seems that this function was replaced by `chk_shapegen()`, which performs
1306
* a very similar task...
1307
*/
1308
void map_vertices(struct ObjGroup *facegrp, struct ObjGroup *vtxgrp) {
1309
register struct ListNode *faceNode;
1310
struct ObjFace *curFace;
1311
register struct ListNode *vtxNode;
1312
struct ObjVertex *vtx;
1313
1314
imin("map_vertices");
1315
1316
// resolve vertex indices to actual vertices
1317
faceNode = facegrp->firstMember;
1318
while (faceNode != NULL) {
1319
curFace = (struct ObjFace *) faceNode->obj;
1320
find_thisface_verts(curFace, vtxgrp);
1321
faceNode = faceNode->next;
1322
}
1323
1324
// compute normals of vertices in vtxgrp
1325
vtxNode = vtxgrp->firstMember;
1326
while (vtxNode != NULL) {
1327
vtx = (struct ObjVertex *) vtxNode->obj;
1328
calc_vtx_normal(vtx, facegrp);
1329
vtxNode = vtxNode->next;
1330
}
1331
1332
imout();
1333
}
1334
1335
/**
1336
* Unselect a grabbable objects
1337
*
1338
* @param obj `GdObj` to unselect
1339
* @return void
1340
* @note Not Called
1341
*/
1342
void unpick_obj(struct GdObj *obj) {
1343
struct GdObj *why = obj;
1344
if (why->drawFlags & OBJ_IS_GRABBALE) {
1345
why->drawFlags &= ~(OBJ_PICKED | OBJ_HIGHLIGHTED);
1346
}
1347
}
1348
1349
/**
1350
* @brief Find the closest object to the cursor on an A-button press
1351
*
1352
* This function is applied to all objects in an `ObjView.components` group
1353
* to find the object closest to the cursor when there's an A press
1354
*
1355
* @param input `GdObj` to check
1356
* @return void
1357
*/
1358
void find_closest_pickable_obj(struct GdObj *input) {
1359
struct GdObj *obj = input;
1360
UNUSED u8 unused[12];
1361
f32 distance;
1362
1363
if (obj->drawFlags & OBJ_IS_GRABBALE) {
1364
if (obj->index == sPickDataTemp) {
1365
if (gViewUpdateCamera != NULL) {
1366
distance = d_calc_world_dist_btwn(&gViewUpdateCamera->header, obj);
1367
} else {
1368
distance = 0.0f;
1369
}
1370
1371
if (distance < sPickObjDistance) {
1372
sPickObjDistance = distance;
1373
sPickedObject = obj;
1374
}
1375
}
1376
}
1377
}
1378
1379
/**
1380
* @brief Set the global view camera if not already set.
1381
*
1382
* This function is used to find the first `ObjCamera` when running `update_view()`.
1383
*
1384
* @param cam `ObjCamera` to set to the update camera, if possible
1385
* @return void
1386
*/
1387
void set_view_update_camera(struct ObjCamera *cam) {
1388
if (gViewUpdateCamera != NULL) {
1389
return;
1390
}
1391
1392
gViewUpdateCamera = cam;
1393
}
1394
1395
/**
1396
* @brief The main per-frame function for handling a view
1397
*
1398
* This function handles updating and rendering a given `ObjView` structure.
1399
* It also handles the A button input for grabbing an area of an `ObjShape`
1400
* that is contained in the `ObjView.components` group
1401
*
1402
* @param view The `ObjView` to update
1403
* @return void
1404
*/
1405
void update_view(struct ObjView *view) {
1406
s32 i;
1407
s32 pickOffset;
1408
s32 pickDataSize;
1409
s32 j;
1410
s32 pickDataIdx;
1411
s32 pickedObjType;
1412
char objTypeAbbr[0x100];
1413
1414
sUpdateViewState.shapesDrawn = 0;
1415
sUpdateViewState.unused18 = 0;
1416
1417
if (!(view->flags & VIEW_UPDATE)) {
1418
view->flags &= ~VIEW_WAS_UPDATED;
1419
return;
1420
}
1421
1422
imin("UpdateView()");
1423
if (view->proc != NULL) {
1424
view->proc(view);
1425
}
1426
1427
if (!(view->flags & VIEW_WAS_UPDATED)) {
1428
view->flags |= VIEW_WAS_UPDATED;
1429
}
1430
1431
gViewUpdateCamera = NULL;
1432
if (view->components != NULL) {
1433
apply_to_obj_types_in_group(OBJ_TYPE_CAMERAS, (applyproc_t) set_view_update_camera,
1434
view->components);
1435
view->activeCam = gViewUpdateCamera;
1436
1437
if (view->activeCam != NULL) {
1438
gViewUpdateCamera->unk18C = view;
1439
}
1440
}
1441
1442
if (view->flags & VIEW_MOVEMENT) {
1443
split_timer("dlgen");
1444
restart_timer("dynamics");
1445
proc_view_movement(view);
1446
split_timer("dynamics");
1447
restart_timer("dlgen");
1448
gViewUpdateCamera = view->activeCam;
1449
}
1450
1451
if (!(view->flags & VIEW_DRAW)) {
1452
imout();
1453
return;
1454
}
1455
1456
sUpdateViewState.view = view;
1457
set_active_view(view);
1458
view->gdDlNum = gd_startdisplist(8);
1459
start_view_dl(sUpdateViewState.view);
1460
gd_shading(9);
1461
1462
if (view->flags & (VIEW_UNK_2000 | VIEW_UNK_4000)) {
1463
gd_set_one_cycle();
1464
}
1465
1466
if (view->components != NULL) {
1467
if (gGdCtrl.dragging) {
1468
if (gd_getproperty(3, 0) != FALSE && gGdCtrl.startedDragging != FALSE) {
1469
init_pick_buf(sPickBuffer, ARRAY_COUNT(sPickBuffer));
1470
drawscene(FIND_PICKS, sUpdateViewState.view->components, NULL);
1471
pickOffset = get_cur_pickbuf_offset(sPickBuffer);
1472
sPickDataTemp = 0;
1473
sPickedObject = NULL;
1474
sPickObjDistance = 10000000.0f;
1475
1476
if (pickOffset < 0) {
1477
fatal_printf("UpdateView(): Pick buffer too small");
1478
} else if (pickOffset > 0) {
1479
pickDataIdx = 0;
1480
for (i = 0; i < pickOffset; i++) {
1481
pickDataSize = sPickBuffer[pickDataIdx++];
1482
if (pickDataSize != 0) {
1483
switch ((pickedObjType = sPickBuffer[pickDataIdx++])) {
1484
case OBJ_TYPE_JOINTS:
1485
gd_strcpy(objTypeAbbr, "J");
1486
break;
1487
case OBJ_TYPE_NETS:
1488
gd_strcpy(objTypeAbbr, "N");
1489
break;
1490
case OBJ_TYPE_PARTICLES:
1491
gd_strcpy(objTypeAbbr, "P");
1492
break;
1493
default:
1494
gd_strcpy(objTypeAbbr, "?");
1495
break;
1496
}
1497
}
1498
1499
if (pickDataSize >= 2) {
1500
for (j = 0; j < pickDataSize - 1; j++) {
1501
sPickDataTemp = sPickBuffer[pickDataIdx++];
1502
apply_to_obj_types_in_group(pickedObjType,
1503
(applyproc_t) find_closest_pickable_obj,
1504
sUpdateViewState.view->components);
1505
}
1506
}
1507
}
1508
}
1509
1510
if (sPickedObject != NULL) {
1511
sPickedObject->drawFlags |= OBJ_PICKED;
1512
sPickedObject->drawFlags |= OBJ_HIGHLIGHTED;
1513
sUpdateViewState.view->pickedObj = sPickedObject;
1514
gGdCtrl.dragStartX = gGdCtrl.csrX = sGrabCords.x;
1515
gGdCtrl.dragStartY = gGdCtrl.csrY = sGrabCords.y;
1516
}
1517
}
1518
1519
find_and_drag_picked_object(sUpdateViewState.view->components);
1520
} else // check for any previously picked objects, and turn off?
1521
{
1522
if (sUpdateViewState.view->pickedObj != NULL) {
1523
sUpdateViewState.view->pickedObj->drawFlags &= ~OBJ_PICKED;
1524
sUpdateViewState.view->pickedObj->drawFlags &= ~OBJ_HIGHLIGHTED;
1525
sUpdateViewState.view->pickedObj = NULL;
1526
}
1527
}
1528
1529
drawscene(RENDER_SCENE, sUpdateViewState.view->components, sUpdateViewState.view->lights);
1530
}
1531
1532
border_active_view();
1533
gd_enddlsplist_parent();
1534
imout();
1535
return;
1536
}
1537
/**
1538
* Stub function.
1539
* @note Not Called
1540
*/
1541
void stub_draw_objects_1(void) {
1542
}
1543
1544