//"ls" is light source. U0 Lighting(CDC *dc, CD3I32 *ls, CD3I32 *poly, I64 color) {//color is a color from 0-7 CD3I32 v1, v2; I64 *r = dc->r, i, vn_x, vn_y, vn_z; F64 d; v1.x = poly[0].x - poly[1].x; v1.y = poly[0].y - poly[1].y; v1.z = poly[0].z - poly[1].z; v2.x = poly[2].x - poly[1].x; v2.y = poly[2].y - poly[1].y; v2.z = poly[2].z - poly[1].z; //V1 and V2 are vects along two sides //of the polygon joined at point[1]. vn_x = v1.y * v2.z - v1.z * v2.y; vn_y = v1.z * v2.x - v1.x * v2.z; vn_z = v1.x * v2.y - v1.y * v2.x; if (d = Sqrt(SqrI64(vn_x) + SqrI64(vn_y) + SqrI64(vn_z))) d = 1 << 16 / d; vn_x *= d; vn_y *= d; vn_z *= d; //Vn is the cross product of V1 and V3 //which means it is perpendicular. It //is the normal vect to the surface. //It has been scaled to length 65536. Mat4x4MulXYZ(r, &vn_x, &vn_y, &vn_z); i = (vn_x * ls->x + vn_y * ls->y + vn_z * ls->z) >> 16; //The dot product of the light source //vect and the surface normal //gives an illumination number. //ZealOS will generate a random U16 //and compare to dither_probability_u16 and //will pick from two colors. //Probability dithering does not work with thick>1 at this time. if (i < 0) { dc->color = ROPF_PROBABILITY_DITHER + BLACK << 16 + color; dc->dither_probability_u16 = -i; } else { dc->color = ROPF_PROBABILITY_DITHER + (color ^ 8) << 16 + color; dc->dither_probability_u16 = i; } } #define RINGS 8 #define FACES 32 #define SLOP 0.03 //Gaps appear without this. U0 DrawIt(CTask *task, CDC *dc) { CCtrl *c = CtrlFindUnique(task, CTRLT_VIEWING_ANGLES); CViewAngles *s = c->state; F64 tt = 0.5 * (Sin(pi * 2 * (tS % 10.0) / 10.0) + 2.0), theta, theta2, phi, phi2, radius, d; I64 i, j, cx = task->pix_width / 2, cy = task->pix_height / 2; CD3I32 poly[3], ls; dc->flags |= DCF_TRANSFORMATION; DCDepthBufAlloc(dc); Mat4x4IdentEqu(dc->r); Mat4x4RotZ(dc->r, s->az); Mat4x4RotY(dc->r, s->ay); Mat4x4RotX(dc->r, s->ax + pi); Mat4x4Scale(dc->r, tt); DCMat4x4Set(dc, dc->r); ls.x = -(mouse.pos.x - task->pix_left - task->scroll_x - cx); ls.y = -(mouse.pos.y - task->pix_top - task->scroll_y - cy); ls.z = GR_WIDTH / 8; d = 1 << 16 / D3I32Norm(&ls); ls.x *= d; ls.y *= d; ls.z *= d; dc->x = cx; dc->y = cy; dc->z = MaxI64(cx, cy); radius = MinI64(cx, cy) / 2; for (i = 0; i < RINGS; i++) { phi = i * pi / 2 / RINGS; phi2 = (i + 1) * pi / 2 / RINGS + SLOP; for (j = 0; j < FACES; j++) { theta = j * 2 * pi /FACES; theta2 = (j + 1) * 2 * pi / FACES + SLOP; //Upper half poly[0].x = radius * Cos(phi) * Cos(theta); poly[0].y = radius * Cos(phi) * Sin(theta); poly[0].z = radius * Sin(phi); poly[1].x = radius * Cos(phi) * Cos(theta2); poly[1].y = radius * Cos(phi) * Sin(theta2); poly[1].z = radius * Sin(phi); poly[2].x = radius * Cos(phi2) * Cos(theta + 2 * pi / FACES / 2); poly[2].y = radius * Cos(phi2) * Sin(theta + 2 * pi / FACES / 2); poly[2].z = radius * Sin(phi2); Lighting(dc, &ls, poly, BLUE); GrFillPoly3(dc, 3, poly); poly[2].x = radius * Cos(phi2) * Cos(theta + 2 * pi / FACES / 2); poly[2].y = radius * Cos(phi2) * Sin(theta + 2 * pi / FACES / 2); poly[2].z = radius * Sin(phi2); poly[1].x = radius * Cos(phi2) * Cos(theta2 + 2 * pi / FACES / 2); poly[1].y = radius * Cos(phi2) * Sin(theta2 + 2 * pi / FACES / 2); poly[1].z = radius * Sin(phi2); poly[0].x = radius * Cos(phi) * Cos(theta2); poly[0].y = radius * Cos(phi) * Sin(theta2); poly[0].z = radius * Sin(phi); Lighting(dc, &ls, poly, BLUE); GrFillPoly3(dc, 3, poly); //Lower half poly[2].x = radius * Cos(phi) * Cos(theta); poly[2].y = radius * Cos(phi) * Sin(theta); poly[2].z = -radius * Sin(phi); poly[1].x = radius * Cos(phi) * Cos(theta2); poly[1].y = radius * Cos(phi) * Sin(theta2); poly[1].z = -radius * Sin(phi); poly[0].x = radius * Cos(phi2) * Cos(theta + 2 * pi / FACES / 2); poly[0].y = radius * Cos(phi2) * Sin(theta + 2 * pi / FACES / 2); poly[0].z = -radius * Sin(phi2); Lighting(dc, &ls, poly, RED); GrFillPoly3(dc, 3, poly); poly[0].x = radius * Cos(phi2) * Cos(theta + 2 * pi / FACES / 2); poly[0].y = radius * Cos(phi2) * Sin(theta + 2 * pi / FACES / 2); poly[0].z = -radius * Sin(phi2); poly[1].x = radius * Cos(phi2) * Cos(theta2 + 2 * pi / FACES / 2); poly[1].y = radius * Cos(phi2) * Sin(theta2 + 2 * pi / FACES / 2); poly[1].z = -radius * Sin(phi2); poly[2].x = radius * Cos(phi) * Cos(theta2); poly[2].y = radius * Cos(phi) * Sin(theta2); poly[2].z = -radius * Sin(phi); Lighting(dc, &ls, poly, RED); GrFillPoly3(dc, 3, poly); } } } //See ::/Demo/Graphics/SpritePlot3D.ZC. //for a CSprite example. //See SpriteMeshEd() for a fancy example. U0 Main() { CCtrl *c = ViewAnglesNew; CViewAngles *s = c->state; s->sx = 2 * VIEWANGLES_SNAP; s->sy = 7 * VIEWANGLES_SNAP; s->sz = 6 * VIEWANGLES_SNAP; SettingsPush; //See SettingsPush AutoComplete; WinBorder; WinMax; DocClear; Fs->draw_it = &DrawIt; try { "\n\nMove mouse to change light source.\n\n"; PressAKey; } catch PutExcept; DocClear; SettingsPop; ViewAnglesDel; } Main;