Death Star: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Perl 6}}: light from below)
m (→‎{{header|POV-Ray}}: Changed syntax highlight language to "pov" to make it work)
(122 intermediate revisions by 40 users not shown)
Line 1: Line 1:
{{task|Constructive Solid Geometry}}{{requires|Graphics}}[[Category:Geometric Subtraction]]
{{task|Constructive Solid Geometry}}
{{requires|Graphics}}
Death Star is a task to display a region that consists of a large sphere with part of a smaller sphere removed from it as a result of geometric subtraction. (This will basically produce a shape like a "death star".)
[[Category:Geometric Subtraction]]
{{omit from|AWK|Does not have this functionality in the language}}
{{omit from|Lotus 123 Macro Scripting}}
{{omit from|ML/I}}
{{omit from|Modula-2}}
{{omit from|Retro}}
{{omit from|SQL PL|It does not handle GUI}}

[[File:Deathstar-tcl.gif|400px|thumb]]

;Task:
Display a region that consists of a large sphere with part of a smaller sphere removed from it as a result of geometric subtraction.

(This will basically produce a shape like a "death star".)


;Related tasks:
* [[Draw_a_sphere|draw a sphere]]
* [[Draw_a_cuboid|draw a cuboid]]
* [[Draw_a_rotating_cube|draw a rotating cube]]
* [[Write_language_name_in_3D_ASCII|write language name in 3D ASCII]]
<br><br>

=={{header|11l}}==
{{trans|Python}}

<syntaxhighlight lang="11l">T Sphere
Float cx, cy, cz, r
F (cx, cy, cz, r)
.cx = cx
.cy = cy
.cz = cz
.r = r

F dotp(v1, v2)
V d = dot(v1, v2)
R I d < 0 {-d} E 0.0

F hit_sphere(sph, x0, y0)
V x = x0 - sph.cx
V y = y0 - sph.cy
V zsq = sph.r ^ 2 - (x ^ 2 + y ^ 2)
I zsq < 0
R (0B, 0.0, 0.0)
V szsq = sqrt(zsq)
R (1B, sph.cz - szsq, sph.cz + szsq)

F draw_sphere(k, ambient, light)
V shades = ‘.:!*oe&#%@’
V pos = Sphere(20.0, 20.0, 0.0, 20.0)
V neg = Sphere(1.0, 1.0, -6.0, 20.0)

L(i) Int(floor(pos.cy - pos.r)) .< Int(ceil(pos.cy + pos.r) + 1)
V y = i + 0.5
L(j) Int(floor(pos.cx - 2 * pos.r)) .< Int(ceil(pos.cx + 2 * pos.r) + 1)
V x = (j - pos.cx) / 2.0 + 0.5 + pos.cx

V (h, zb1, zb2) = hit_sphere(pos, x, y)
Int hit_result
Float zs2
I !h
hit_result = 0
E
(h, V zs1, zs2) = hit_sphere(neg, x, y)
I !h
hit_result = 1
E I zs1 > zb1
hit_result = 1
E I zs2 > zb2
hit_result = 0
E I zs2 > zb1
hit_result = 2
E
hit_result = 1

V vec = (0.0, 0.0, 0.0)
I hit_result == 0
print(‘ ’, end' ‘’)
L.continue
E I hit_result == 1
vec = (x - pos.cx, y - pos.cy, zb1 - pos.cz)
E I hit_result == 2
vec = (neg.cx - x, neg.cy - y, neg.cz - zs2)
vec = normalize(vec)

V b = dotp(light, vec) ^ k + ambient
V intensity = Int((1 - b) * shades.len)
intensity = min(shades.len, max(0, intensity))
print(shades[intensity], end' ‘’)
print()

V light = normalize((-50.0, 30.0, 50.0))
draw_sphere(2, 0.5, light)</syntaxhighlight>

{{out}}
<pre>
eeeee:::::::
eeeeeeeee..............
ooeeeeeeeeee..................
ooooeeeeeeeee......................
oooooooeeeeeeee..........................
ooooooooooeeeee..............................
**ooooooooooeeee.................................
****ooooooooooee.....................................
!*****ooooooooooe.......................................
!!!*****ooooooooo:..........................................
:!!!!*****ooooooo:::...........................................
:::!!!!*****ooooo!:::::...........................................
::::!!!!!*****ooo!!!!::::............................................
.::::!!!!*****oo*!!!!!::::............................................
...::::!!!!*********!!!!:::::............................................
...::::!!!!****o*****!!!!!::::............................................
....::::!!!!***ooo******!!!!!::::............................................
....::::!!!!*ooooooo*****!!!!!:::::...........................................
...::::!!!!!oooooooooo*****!!!!!:::::..........................................
:::::!!!!eeooooooooooo******!!!!!:::::.........................................
!!!!!eeeeeeeooooooooooo******!!!!!:::::........................................
eeeeeeeeeeeeoooooooooooo******!!!!!:::::.......................................
eeeeeeeeeeeeeoooooooooooo******!!!!!!:::::.....................................
eeeeeeeeeeeeeeoooooooooooo******!!!!!!:::::....................................
eeeeeeeeeeeeeeoooooooooooo*******!!!!!!:::::.................................
eeeeeeeeeeeeeeeooooooooooooo******!!!!!!::::::..............................:
eeeeeeeeeeeeeeeooooooooooooo*******!!!!!!:::::::..........................:
eeeeeeeeeeeeeeeeoooooooooooooo*******!!!!!!!:::::::.....................::!
eeeeeeeeeeeeeeeeeooooooooooooo********!!!!!!!:::::::::..............::::!
eeeeeeeeeeeeeeeeeoooooooooooooo********!!!!!!!!::::::::::::::::::::::!*
eeeeeeeeeeeeeeeeeeooooooooooooooo********!!!!!!!!!!:::::::::::::!!!!*
eeeeeeeeeeeeeeeeeoooooooooooooooo**********!!!!!!!!!!!!!!!!!!!!!*
eeeeeeeeeeeeeeeeeeooooooooooooooooo************!!!!!!!!!!!!****
eeeeeeeeeeeeeeeeeeoooooooooooooooooo**********************o
eeeeeeeeeeeeeeeeeeeooooooooooooooooooooo************ooo
eeeeeeeeeeeeeeeeeeeeooooooooooooooooooooooooooooooo
eeeeeeeeeeeeeeeeeeeeooooooooooooooooooooooooo
eeeeeeeeeeeeeeeeeeeeeoooooooooooooooooo
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeee
</pre>

=={{header|Ada}}==
{{libheader|SDLAda}}{{trans|Go}}

<syntaxhighlight lang="ada">with Ada.Numerics.Elementary_Functions;
with Ada.Numerics.Generic_Real_Arrays;

with SDL.Video.Windows.Makers;
with SDL.Video.Renderers.Makers;
with SDL.Video.Palettes;
with SDL.Events.Events;

procedure Death_Star is

Width : constant := 400;
Height : constant := 400;

package Float_Arrays is
new Ada.Numerics.Generic_Real_Arrays (Float);
use Ada.Numerics.Elementary_Functions;
use Float_Arrays;

Window : SDL.Video.Windows.Window;
Renderer : SDL.Video.Renderers.Renderer;

subtype Vector_3 is Real_Vector (1 .. 3);

type Sphere_Type is record
Cx, Cy, Cz : Integer;
R : Integer;
end record;

function Normalize (V : Vector_3) return Vector_3 is
(V / Sqrt (V * V));

procedure Hit (S : Sphere_Type;
X, Y : Integer;
Z1, Z2 : out Float;
Is_Hit : out Boolean)
is
NX : constant Integer := X - S.Cx;
NY : constant Integer := Y - S.Cy;
Zsq : constant Integer := S.R * S.R - (NX * NX + NY * NY);
Zsqrt : Float;
begin
if Zsq >= 0 then
Zsqrt := Sqrt (Float (Zsq));
Z1 := Float (S.Cz) - Zsqrt;
Z2 := Float (S.Cz) + Zsqrt;
Is_Hit := True;
return;
end if;
Z1 := 0.0;
Z2 := 0.0;
Is_Hit := False;
end Hit;

procedure Draw_Death_Star (Pos, Neg : Sphere_Type;
K, Amb : Float;
Dir : Vector_3)
is
Vec : Vector_3;
ZB1, ZB2 : Float;
ZS1, ZS2 : Float;
Is_Hit : Boolean;
S : Float;
Lum : Integer;
begin
for Y in Pos.Cy - Pos.R .. Pos.Cy + Pos.R loop
for X in Pos.Cx - Pos.R .. Pos.Cx + Pos.R loop
Hit (Pos, X, Y, ZB1, ZB2, Is_Hit);
if not Is_Hit then
goto Continue;
end if;
Hit (Neg, X, Y, ZS1, ZS2, Is_Hit);
if Is_Hit then
if ZS1 > ZB1 then
Is_Hit := False;
elsif ZS2 > ZB2 then
goto Continue;
end if;
end if;

if Is_Hit then
Vec := (Float (Neg.Cx - X),
Float (Neg.Cy - Y),
Float (Neg.Cz) - ZS2);
else
Vec := (Float (X - Pos.Cx),
Float (Y - Pos.Cy),
ZB1 - Float (Pos.Cz));
end if;
S := Float'Max (0.0, Dir * Normalize (Vec));

Lum := Integer (255.0 * (S ** K + Amb) / (1.0 + Amb));
Lum := Integer'Max (0, Lum);
Lum := Integer'Min (Lum, 255);

Renderer.Set_Draw_Colour ((SDL.Video.Palettes.Colour_Component (Lum),
SDL.Video.Palettes.Colour_Component (Lum),
SDL.Video.Palettes.Colour_Component (Lum),
255));
Renderer.Draw (Point => (SDL.C.int (X + Width / 2),
SDL.C.int (Y + Height / 2)));
<<Continue>>
end loop;
end loop;
end Draw_Death_Star;

procedure Wait is
use type SDL.Events.Event_Types;
Event : SDL.Events.Events.Events;
begin
loop
while SDL.Events.Events.Poll (Event) loop
if Event.Common.Event_Type = SDL.Events.Quit then
return;
end if;
end loop;
delay 0.100;
end loop;
end Wait;

Direction : constant Vector_3 := Normalize ((20.0, -40.0, -10.0));
Positive : constant Sphere_Type := (0, 0, 0, 120);
Negative : constant Sphere_Type := (-90, -90, -30, 100);
begin
if not SDL.Initialise (Flags => SDL.Enable_Screen) then
return;
end if;

SDL.Video.Windows.Makers.Create (Win => Window,
Title => "Death star",
Position => SDL.Natural_Coordinates'(X => 10, Y => 10),
Size => SDL.Positive_Sizes'(Width, Height),
Flags => 0);
SDL.Video.Renderers.Makers.Create (Renderer, Window.Get_Surface);
Renderer.Set_Draw_Colour ((0, 0, 0, 255));
Renderer.Fill (Rectangle => (0, 0, Width, Height));

Draw_Death_Star (Positive, Negative, 1.5, 0.2, Direction);
Window.Update_Surface;

Wait;
Window.Finalize;
SDL.Finalise;
end Death_Star;</syntaxhighlight>

=={{header|ALGOL 68}}==
{{Trans|C}}{{Trans|11l}}
<syntaxhighlight lang="algol68">
BEGIN # draw a "Death Star" - translated from the C and 11l samples #
STRING shades = ".:!*oe&#%@";

PROC normalize = ( []REAL v )[]REAL:
BEGIN
REAL len = sqrt( v[ 1 ] * v[ 1 ] + v[ 2 ] * v[ 2 ] + v[ 3 ] * v[ 3 ] );
( v[ 1 ] / len, v[ 2 ] / len, v[ 3 ] / len )
END # normalize # ;

PROC dot = ( []REAL x, y )REAL:
BEGIN
REAL d = x[ 1 ] * y[ 1 ] + x[ 2 ] * y[ 2 ] + x[ 3 ] * y[ 3 ];
IF d < 0 THEN - d ELSE 0 FI
END # dot # ;

MODE SPHERE = STRUCT( REAL cx, cy, cz, r );

# positive shpere and negative sphere #
SPHERE pos = ( 20, 20, 0, 20 ), neg = ( 1, 1, -6, 20 );

# check if a ray (x,y, -inf)->(x, y, inf) hits a sphere; if so, return #
# the intersecting z values. z1 is closer to the eye #
PROC hit_sphere = ( SPHERE sph, REAL x in, y in, REF REAL z1, z2 )BOOL:
IF REAL x = x in - cx OF sph;
REAL y = y in - cy OF sph;
REAL zsq := r OF sph * r OF sph - ( x * x + y * y );
zsq < 0
THEN FALSE
ELSE zsq := sqrt( zsq );
z1 := cz OF sph - zsq;
z2 := cz OF sph + zsq;
TRUE
FI # hit_sphere # ;

PROC draw_sphere = ( REAL k, ambient, []REAL light )VOID:
FOR i FROM ENTIER ( cy OF pos - r OF pos ) TO ENTIER ( cy OF pos + r OF pos ) + 1 DO
REAL y := i + 0.5;
FOR j FROM ENTIER ( cx OF pos - 2 * r OF pos ) TO ENTIER (cx OF pos + 2 * r OF pos ) + 1 DO
REAL x := ( j - cx OF pos ) / 2.0 + 0.5 + cx OF pos;
REAL zb1 := 0, zb2 := 0, zs1 := 0, zs2 := 0;
INT hit_result
= IF NOT hit_sphere( pos, x, y, zb1, zb2 ) THEN
0 # ray lands in blank space, draw bg #
ELIF NOT hit_sphere( neg, x, y, zs1, zs2 ) THEN
1 # ray hits pos sphere but not neg, draw pos sphere surface #
ELIF zs1 > zb1 THEN
1 # ray hits both, but pos front surface is closer #
ELIF zs2 > zb2 THEN
0 # pos sphere surface is inside neg sphere, show bg #
ELIF zs2 > zb1 THEN
2 # back surface on neg sphere is inside pos sphere, #
# the only place where neg sphere surface will be shown #
ELSE
1 # show the pos sphere #
FI;
IF hit_result = 0 THEN
print( ( " " ) )
ELSE
[]REAL vec =
normalize( IF hit_result = 1
THEN []REAL( x - cx OF pos
, y - cy OF pos
, zb1 - cz OF pos
)
ELSE []REAL( cx OF neg - x
, cy OF neg - y
, cz OF neg - zs2
)
FI
);
REAL b = ( dot( light, vec ) ^ k ) + ambient;
INT intensity := ENTIER ( ( 1 - b ) * ( ( UPB shades - LWB shades ) + 1 ) ) + 1;
IF intensity < LWB shades THEN intensity := LWB shades
ELIF intensity > UPB shades THEN intensity := UPB shades
FI;
print( ( shades[ intensity ] ) )
FI
OD;
print( ( newline ) )
OD # draw_sphere # ;

BEGIN
[]REAL light = ( -50, 30, 50 );
draw_sphere( 2, 0.5, normalize( light ) )
END
END
</syntaxhighlight>
{{out}}
Same as 11l

=={{header|AutoHotkey}}==
{{libheader|GDIP}}
<syntaxhighlight lang="ahk">#NoEnv
SetBatchLines, -1
#SingleInstance, Force

; Uncomment if Gdip.ahk is not in your standard library
#Include, Gdip.ahk

; Settings
X := 200, Y := 200, Width := 200, Height := 200 ; Location and size of sphere
rotation := 60 ; degrees
ARGB := 0xFFFF0000 ; Color=Solid Red

If !pToken := Gdip_Startup() ; Start gdi+
{
MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
ExitApp
}
OnExit, Exit

Gui, -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs ; Create GUI
Gui, Show, NA ; Show GUI
hwnd1 := WinExist() ; Get a handle to this window we have created in order to update it later
hbm := CreateDIBSection(A_ScreenWidth, A_ScreenHeight) ; Create a gdi bitmap drawing area
hdc := CreateCompatibleDC() ; Get a device context compatible with the screen
obm := SelectObject(hdc, hbm) ; Select the bitmap into the device context
pGraphics := Gdip_GraphicsFromHDC(hdc) ; Get a pointer to the graphics of the bitmap, for use with drawing functions
Gdip_SetSmoothingMode(pGraphics, 4) ; Set the smoothing mode to antialias = 4 to make shapes appear smother

Gdip_TranslateWorldTransform(pGraphics, X, Y)
Gdip_RotateWorldTransform(pGraphics, rotation)

; Base ellipse
pBrush := Gdip_CreateLineBrushFromRect(0, 0, Width, Height, ARGB, 0xFF000000)
Gdip_FillEllipse(pGraphics, pBrush, 0, 0, Width, Height)

; First highlight ellipse
pBrush := Gdip_CreateLineBrushFromRect(Width*0.1, Height*0.01, Width*0.8, Height*0.6, 0x33FFFFFF, 0x00FFFFFF)
Gdip_FillEllipse(pGraphics, pBrush, Width*0.1, Height*0.01, Width*0.8, Height*0.6)

; Second highlight ellipse
pBrush := Gdip_CreateLineBrushFromRect(Width*0.3, Height*0.02, Width*0.3, Height*0.2, 0xBBFFFFFF, 0x00FFFFFF)
Gdip_FillEllipse(pGraphics, pBrush, Width*0.3, Height*0.02, Width*0.3, Height*0.2)


; Reset variables for smaller subtracted sphere
X-=150
Y-=10
Width*=0.5
Height*=0.4
rotation-=180

Gdip_TranslateWorldTransform(pGraphics, X, Y)
Gdip_RotateWorldTransform(pGraphics, rotation)

; Base ellipse
pBrush := Gdip_CreateLineBrushFromRect(0, 0, Width, Height, ARGB, 0xFF000000)
Gdip_FillEllipse(pGraphics, pBrush, 0, 0, Width, Height)

; First highlight ellipse
pBrush := Gdip_CreateLineBrushFromRect(Width*0.1, Height*0.01, Width*0.8, Height*0.6, 0x33FFFFFF, 0x00FFFFFF)
Gdip_FillEllipse(pGraphics, pBrush, Width*0.1, Height*0.01, Width*0.8, Height*0.6)

; Second highlight ellipse
pBrush := Gdip_CreateLineBrushFromRect(Width*0.3, Height*0.02, Width*0.3, Height*0.2, 0xBBFFFFFF, 0x00FFFFFF)
Gdip_FillEllipse(pGraphics, pBrush, Width*0.3, Height*0.02, Width*0.3, Height*0.2)


UpdateLayeredWindow(hwnd1, hdc, 0, 0, A_ScreenWidth, A_ScreenHeight)
SelectObject(hdc, obm) ; Select the object back into the hdc
Gdip_DeletePath(Path)
Gdip_DeleteBrush(pBrush)
DeleteObject(hbm) ; Now the bitmap may be deleted
DeleteDC(hdc) ; Also the device context related to the bitmap may be deleted
Gdip_DeleteGraphics(G) ; The graphics may now be deleted
Return

Exit:
; gdi+ may now be shutdown on exiting the program
Gdip_Shutdown(pToken)
ExitApp</syntaxhighlight>


See also: [[Draw a sphere]].
=={{header|Brlcad}}==
=={{header|Brlcad}}==
<lang brlcad># We need a database to hold the objects
<syntaxhighlight lang="brlcad"># We need a database to hold the objects
opendb deathstar.g y
opendb deathstar.g y


Line 29: Line 488:


# We now trigger the raytracer to see our finished product
# We now trigger the raytracer to see our finished product
rt</lang>
rt</syntaxhighlight>

=={{header|C}}==
=={{header|C}}==
Primitive ray tracing.
Primitive ray tracing.
<lang c>#include <stdio.h>
<syntaxhighlight lang="c">#include <stdio.h>
#include <math.h>
#include <math.h>
#include <unistd.h>


char shades[] = ".:!*oe&#%@";
const char *shades = ".:!*oe&#%@";


double light[3] = { -50, 30, 50 };
double light[3] = { -50, 0, 50 };
void normalize(double * v)
void normalize(double * v)
{
{
Line 101: Line 562:
switch(hit_result) {
switch(hit_result) {
case 0:
case 0:
putchar(' ');
putchar('+');
continue;
continue;
case 1:
case 1:
Line 128: Line 589:
int main()
int main()
{
{
double ang = 0;
normalize(light);


while (1) {
draw_sphere(2, .5);
printf("\033[H");
light[1] = cos(ang * 2);
light[2] = cos(ang);
light[0] = sin(ang);
normalize(light);
ang += .05;

draw_sphere(2, .3);
usleep(100000);
}
return 0;
return 0;
}</syntaxhighlight>
}</lang>output<lang> eeeee:::::::
eeeeeeeee..............
ooeeeeeeeeee..................
ooooeeeeeeeee......................
oooooooeeeeeeee..........................
ooooooooooeeeee..............................
**ooooooooooeeee.................................
****ooooooooooee.....................................
!*****ooooooooooe.......................................
!!!*****ooooooooo:..........................................
:!!!!*****ooooooo:::...........................................
:::!!!!*****ooooo!:::::...........................................
::::!!!!!*****ooo!!!!::::............................................
.::::!!!!*****oo*!!!!!::::............................................
...::::!!!!*********!!!!:::::............................................
...::::!!!!****o*****!!!!!::::............................................
....::::!!!!***ooo******!!!!!::::............................................
....::::!!!!*ooooooo*****!!!!!:::::...........................................
...::::!!!!!oooooooooo*****!!!!!:::::..........................................
:::::!!!!eeooooooooooo******!!!!!:::::.........................................
!!!!!eeeeeeeooooooooooo******!!!!!:::::........................................
eeeeeeeeeeeeoooooooooooo******!!!!!:::::.......................................
eeeeeeeeeeeeeoooooooooooo******!!!!!!:::::.....................................
eeeeeeeeeeeeeeoooooooooooo******!!!!!!:::::....................................
eeeeeeeeeeeeeeoooooooooooo*******!!!!!!:::::.................................
eeeeeeeeeeeeeeeooooooooooooo******!!!!!!::::::..............................:
eeeeeeeeeeeeeeeooooooooooooo*******!!!!!!:::::::..........................:
eeeeeeeeeeeeeeeeoooooooooooooo*******!!!!!!!:::::::.....................::!
eeeeeeeeeeeeeeeeeooooooooooooo********!!!!!!!:::::::::..............::::!
eeeeeeeeeeeeeeeeeoooooooooooooo********!!!!!!!!::::::::::::::::::::::!*
eeeeeeeeeeeeeeeeeeooooooooooooooo********!!!!!!!!!!:::::::::::::!!!!*
eeeeeeeeeeeeeeeeeoooooooooooooooo**********!!!!!!!!!!!!!!!!!!!!!*
eeeeeeeeeeeeeeeeeeooooooooooooooooo************!!!!!!!!!!!!****
eeeeeeeeeeeeeeeeeeoooooooooooooooooo**********************o
eeeeeeeeeeeeeeeeeeeooooooooooooooooooooo************ooo
eeeeeeeeeeeeeeeeeeeeooooooooooooooooooooooooooooooo
eeeeeeeeeeeeeeeeeeeeooooooooooooooooooooooooo
eeeeeeeeeeeeeeeeeeeeeoooooooooooooooooo
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeee</lang>


=={{header|D}}==
=={{header|D}}==
{{trans|C}}
{{trans|C}}
<lang d>import std.stdio, std.math, std.numeric, std.algorithm;
<syntaxhighlight lang="d">import std.stdio, std.math, std.numeric, std.algorithm;


/*const*/ struct V3 {
struct V3 {
double[3] v;
double[3] v;


@property V3 normalize() pure nothrow const {
@property V3 normalize() pure nothrow const @nogc {
//immutable double len = sqrt(dotProduct(v, v));
immutable double len = dotProduct(v, v).sqrt;
immutable double len= sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
return [v[0] / len, v[1] / len, v[2] / len].V3;
// return V3(v[] / len);
return V3([v[0] / len, v[1] / len, v[2] / len]);
}
}


double dot(const ref V3 y) pure nothrow const {
double dot(in ref V3 y) pure nothrow const @nogc {
immutable double d = dotProduct(v, y.v);
immutable double d = dotProduct(v, y.v);
return d < 0 ? -d : 0;
return d < 0 ? -d : 0;
Line 196: Line 626:
const struct Sphere { double cx, cy, cz, r; }
const struct Sphere { double cx, cy, cz, r; }


void drawSphere(in double k, in double ambient, in V3 light)nothrow{
void drawSphere(in double k, in double ambient, in V3 light) nothrow {
/** Check if a ray (x,y, -inf).(x, y, inf) hits a sphere; if so,
/** Check if a ray (x,y, -inf).(x, y, inf) hits a sphere; if so,
return the intersecting z values. z1 is closer to the eye */
return the intersecting z values. z1 is closer to the eye.*/
static bool hitSphere(const ref Sphere sph,
static bool hitSphere(in ref Sphere sph,
in double x0, in double y0,
in double x0, in double y0,
out double z1,
out double z1,
out double z2) pure nothrow {
out double z2) pure nothrow @nogc {
immutable double x = x0 - sph.cx;
immutable double x = x0 - sph.cx;
immutable double y = y0 - sph.cy;
immutable double y = y0 - sph.cy;
Line 208: Line 638:
if (zsq < 0)
if (zsq < 0)
return false;
return false;
immutable double szsq = sqrt(zsq);
immutable double szsq = zsq.sqrt;
z1 = sph.cz - szsq;
z1 = sph.cz - szsq;
z2 = sph.cz + szsq;
z2 = sph.cz + szsq;
Line 214: Line 644:
}
}


enum string shades = ".:!*oe&#%@";
immutable shades = ".:!*oe&#%@";
// positive and negative spheres
// Positive and negative spheres.
enum pos = Sphere(20, 20, 0, 20);
immutable pos = Sphere(20, 20, 0, 20);
enum neg = Sphere(1, 1, -6, 20);
immutable neg = Sphere(1, 1, -6, 20);


foreach (int i; cast(int)floor(pos.cy - pos.r) ..
foreach (immutable int i; cast(int)floor(pos.cy - pos.r) ..
cast(int)ceil(pos.cy + pos.r) + 1) {
cast(int)ceil(pos.cy + pos.r) + 1) {
immutable double y = i + 0.5;
immutable double y = i + 0.5;
jloop:
JLOOP:
foreach (int j; cast(int)floor(pos.cx - 2 * pos.r) ..
foreach (int j; cast(int)floor(pos.cx - 2 * pos.r) ..
cast(int)ceil(pos.cx + 2 * pos.r) + 1) {
cast(int)ceil(pos.cx + 2 * pos.r) + 1) {
Line 228: Line 658:


enum Hit { background, posSphere, negSphere }
enum Hit { background, posSphere, negSphere }

Hit hitResult;
double zb1, zs2;
double zb1, zs2;
{
immutable Hit hitResult = {
double zb2, zs1;
double zb2, zs1;

if (!hitSphere(pos, x, y, zb1, zb2)) {
if (!hitSphere(pos, x, y, zb1, zb2)) {
// Ray lands in blank space, draw bg
// Ray lands in blank space, draw bg.
hitResult = Hit.background;
return Hit.background;
} else if (!hitSphere(neg, x, y, zs1, zs2)) {
} else if (!hitSphere(neg, x, y, zs1, zs2)) {
// Ray hits pos sphere but not neg one,
// Ray hits pos sphere but not neg one,
// draw pos sphere surface
// draw pos sphere surface.
hitResult = Hit.posSphere;
return Hit.posSphere;
} else if (zs1 > zb1) {
} else if (zs1 > zb1) {
// ray hits both, but pos front surface is closer
// ray hits both, but pos front surface is closer.
hitResult = Hit.posSphere;
return Hit.posSphere;
} else if (zs2 > zb2) {
} else if (zs2 > zb2) {
// pos sphere surface is inside neg sphere,
// pos sphere surface is inside neg sphere,
// show bg
// show bg.
hitResult = Hit.background;
return Hit.background;
} else if (zs2 > zb1) {
} else if (zs2 > zb1) {
// Back surface on neg sphere is inside pos
// Back surface on neg sphere is inside pos
// sphere, the only place where neg sphere
// sphere, the only place where neg sphere
// surface will be shown
// surface will be shown.
hitResult = Hit.negSphere;
return Hit.negSphere;
} else {
} else {
hitResult = Hit.posSphere;
return Hit.posSphere;
}
}
}
}();


V3 vec_;
V3 vec_;
final switch (hitResult) {
final switch (hitResult) {
case Hit.background:
case Hit.background:
putchar(' ');
' '.putchar;
continue jloop;
continue JLOOP;
case Hit.posSphere:
case Hit.posSphere:
vec_ = V3([x - pos.cx, y - pos.cy, zb1 - pos.cz]);
vec_ = [x - pos.cx, y - pos.cy, zb1 - pos.cz].V3;
break;
break;
case Hit.negSphere:
case Hit.negSphere:
vec_ = V3([neg.cx-x, neg.cy-y, neg.cz-zs2]);
vec_ = [neg.cx - x, neg.cy - y, neg.cz - zs2].V3;
break;
break;
}
}
immutable V3 nvec = vec_.normalize;
immutable nvec = vec_.normalize;


immutable double b = light.dot(nvec) ^^ k + ambient;
immutable double b = light.dot(nvec) ^^ k + ambient;
int intensity = cast(int)((1 - b) * shades.length);
immutable intensity = cast(int)((1 - b) * shades.length);
intensity = min(shades.length, max(0, intensity));
immutable normInt = min(shades.length, max(0, intensity));
putchar(shades[intensity]);
shades[normInt].putchar;
}
}


putchar('\n');
'\n'.putchar;
}
}
}
}
Line 282: Line 713:


void main() {
void main() {
enum light = V3([-50, 30, 50]).normalize;
immutable light = [-50, 30, 50].V3.normalize;
drawSphere(2, 0.5, light);
drawSphere(2, 0.5, light);
}</lang>
}</syntaxhighlight>

The output is the same of the C version.
The output is the same of the C version.
=={{header|Delphi}}==
{{libheader| Winapi.Windows}}
{{libheader| System.SysUtils}}
{{libheader| system.Math}}
{{libheader| Vcl.Graphics}}
{{libheader| Vcl.Imaging.pngimage}}
{{Trans|C}}
Translate of [[#C]] and [[#Go]], with copy of some parts of [[#DWScript]].
<syntaxhighlight lang="delphi">
program Death_Star;

{$APPTYPE CONSOLE}

uses
Winapi.Windows,
System.SysUtils,
system.Math,
Vcl.Graphics,
Vcl.Imaging.pngimage;

type
TVector = array of double;

var
light: TVector = [20, -40, -10];

function ClampInt(value, amin, amax: Integer): Integer;
begin
Result := Max(amin, Min(amax, value))
end;

procedure Normalize(var v: TVector);
begin
var len := Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] := v[0] / len;
v[1] := v[1] / len;
v[2] := v[2] / len;
end;

function Dot(x, y: TVector): Double;
begin
var d := x[0] * y[0] + x[1] * y[1] + x[2] * y[2];
if d < 0 then
Result := -d
else
Result := 0;
end;

type
TSphere = record
cx, cy, cz, r: Double;
end;

const
pos: TSphere = (
cx: 0;
cy: 0;
cz: 0;
r: 120
);

const
neg: TSphere = (
cx: -90;
cy: -90;
cz: -30;
r: 80
);

function HitSphere(sph: TSphere; x, y: double; var z1, z2: Double): Boolean;
begin
x := x - sph.cx;
y := y - sph.cy;
var zsq := sph.r * sph.r - (x * x + y * y);
if (zsq < 0) then
Exit(False);
zsq := Sqrt(zsq);
z1 := sph.cz - zsq;
z2 := sph.cz + zsq;
Result := True;
end;

function DeathStar(pos, neg: TSphere; k, amb: Double; light: TVector): TBitmap;
var
w, h, yMax, xMax, s: double;
zp1, zp2, zn1, zn2, b: Double;
x, y: Integer;
hit: Boolean;
vec: TVector;
intensity: Byte;
ox, oy: Integer;
begin
w := pos.r * 4;
h := pos.r * 3;
ox := -trunc(pos.cx - w / 2);
oy := -trunc(pos.cy - h / 2);

vec := [0, 0, 0];
Result := TBitmap.Create;
Result.SetSize(trunc(w), trunc(h));

yMax := pos.cy + pos.r;
for y := Trunc(pos.cy - pos.r) to Trunc(yMax) do
begin
xMax := pos.cx + pos.r;
for x := trunc(pos.cy - pos.r) to trunc(xMax) do
begin
hit := HitSphere(pos, x, y, zp1, zp2);
if not hit then
continue;

hit := HitSphere(neg, x, y, zn1, zn2);

if hit then
begin
if zn1 > zp1 then
hit := false
else if zn2 > zp2 then
continue;
end;

if hit then
begin
vec[0] := neg.cx - x;
vec[1] := neg.cy - y;
vec[2] := neg.cz - zn2;
end
else
begin
vec[0] := x - pos.cx;
vec[1] := y - pos.cy;
vec[2] := zp1 - pos.cz;
end;

Normalize(vec);

s := max(0, dot(light, vec));

b := Power(s, k) + amb;

intensity := ClampInt(round(255 * b / (1 + amb)), 0, 254);

Result.Canvas.Pixels[x + ox, y + oy] := rgb(intensity, intensity, intensity);
end;
end;
end;

var
bmp: TBitmap;

begin
Normalize(light);
bmp := DeathStar(pos, neg, 1.2, 0.3, light);


with TPngImage.Create do
begin
Assign(bmp);
TransparentColor := clwhite;
SaveToFile('out.png');
bmp.Free;
Free;
end;
end.</syntaxhighlight>
=={{header|DWScript}}==
=={{header|DWScript}}==
{{trans|C}}
{{trans|C}}
<lang delphi>const cShades = '.:!*oe&#%@';
<syntaxhighlight lang="delphi">const cShades = '.:!*oe&#%@';


type TVector = array [0..2] of Float;
type TVector = array [0..2] of Float;
Line 382: Line 976:
Normalize(light);
Normalize(light);
DrawSphere(2, 0.3);</lang>
DrawSphere(2, 0.3);</syntaxhighlight>

=={{header|Frink}}==
This program not only draws a Death Star and renders it onscreen projected on the x,y, and z axes but also outputs a .stl file for 3-D printing. Frink has [https://frinklang.org/3d/frink/graphics/package-summary.html built-in routines for 3-D modeling].
<syntaxhighlight lang="frink">res = 254 / in
v = callJava["frink.graphics.VoxelArray", "makeSphere", [1/2 inch res]]

dish = callJava["frink.graphics.VoxelArray", "makeSphere", [1/2 inch res]]
dish.translate[round[.45 inch res], round[.45 inch res], round[.45 inch res]]
v.remove[dish]

v.projectX[undef].show["X"]
v.projectY[undef].show["Y"]
v.projectZ[undef].show["Z"]

filename = "DeathStar.stl"
print["Writing $filename..."]
w = new Writer[filename]
w.println[v.toSTLFormat["DeathStar", 1/(res mm)]]
w.close[]
println["done."]
</syntaxhighlight>

=={{header|Go}}==
[[file:GoDstar.png|right|thumb|Output png]]
{{trans|C}}
<syntaxhighlight lang="go">package main

import (
"fmt"
"image"
"image/color"
"image/png"
"math"
"os"
)

type vector [3]float64

func (v *vector) normalize() {
invLen := 1 / math.Sqrt(dot(v, v))
v[0] *= invLen
v[1] *= invLen
v[2] *= invLen
}

func dot(x, y *vector) float64 {
return x[0]*y[0] + x[1]*y[1] + x[2]*y[2]
}

type sphere struct {
cx, cy, cz int
r int
}

func (s *sphere) hit(x, y int) (z1, z2 float64, hit bool) {
x -= s.cx
y -= s.cy
if zsq := s.r*s.r - (x*x + y*y); zsq >= 0 {
zsqrt := math.Sqrt(float64(zsq))
return float64(s.cz) - zsqrt, float64(s.cz) + zsqrt, true
}
return 0, 0, false
}

func deathStar(pos, neg *sphere, k, amb float64, dir *vector) *image.Gray {
w, h := pos.r*4, pos.r*3
bounds := image.Rect(pos.cx-w/2, pos.cy-h/2, pos.cx+w/2, pos.cy+h/2)
img := image.NewGray(bounds)
vec := new(vector)
for y, yMax := pos.cy-pos.r, pos.cy+pos.r; y <= yMax; y++ {
for x, xMax := pos.cx-pos.r, pos.cx+pos.r; x <= xMax; x++ {
zb1, zb2, hit := pos.hit(x, y)
if !hit {
continue
}
zs1, zs2, hit := neg.hit(x, y)
if hit {
if zs1 > zb1 {
hit = false
} else if zs2 > zb2 {
continue
}
}
if hit {
vec[0] = float64(neg.cx - x)
vec[1] = float64(neg.cy - y)
vec[2] = float64(neg.cz) - zs2
} else {
vec[0] = float64(x - pos.cx)
vec[1] = float64(y - pos.cy)
vec[2] = zb1 - float64(pos.cz)
}
vec.normalize()
s := dot(dir, vec)
if s < 0 {
s = 0
}
lum := 255 * (math.Pow(s, k) + amb) / (1 + amb)
if lum < 0 {
lum = 0
} else if lum > 255 {
lum = 255
}
img.SetGray(x, y, color.Gray{uint8(lum)})
}
}
return img
}

func main() {
dir := &vector{20, -40, -10}
dir.normalize()
pos := &sphere{0, 0, 0, 120}
neg := &sphere{-90, -90, -30, 100}

img := deathStar(pos, neg, 1.5, .2, dir)
f, err := os.Create("dstar.png")
if err != nil {
fmt.Println(err)
return
}
if err = png.Encode(f, img); err != nil {
fmt.Println(err)
}
if err = f.Close(); err != nil {
fmt.Println(err)
}
}</syntaxhighlight>

=={{header|Haskell}}==

=== ASCII art ===

<syntaxhighlight lang="haskell">import Data.List (genericLength)

shades = ".:!*oe%#&@"
n = genericLength shades
dot a b = sum $ zipWith (*) a b
normalize x = (/ sqrt (x `dot` x)) <$> x

deathStar r k amb = unlines $
[ [ if x*x + y*y <= r*r
then let vec = normalize $ normal x y
b = (light `dot` vec) ** k + amb
intensity = (1 - b)*(n - 1)
in shades !! round ((0 `max` intensity) `min` n)
else ' '
| y <- map (/2.12) [- 2*r - 0.5 .. 2*r + 0.5] ]
| x <- [ - r - 0.5 .. r + 0.5] ]
where
light = normalize [-30,-30,-50]
normal x y
| (x+r)**2 + (y+r)**2 <= r**2 = [x+r, y+r, sph2 x y]
| otherwise = [x, y, sph1 x y]
sph1 x y = sqrt (r*r - x*x - y*y)
sph2 x y = r - sqrt (r*r - (x+r)**2 - (y+r)**2)</syntaxhighlight>

<pre>λ> putStrLn $ deathStar 10 4 0.1
eeeeoo*&&&&&&&
eeeeeoooo**!&&&&&&&&&&&&
eeooooooo***!!&&&&&&&&&&&&&&&&
eooooo*****!!!::&&&&&&&&&&&&&&&&&&
eooo****!!!!:::.&&&&&&&&&&&&&&&&&&&&
eeeoo***!!!::::.&&&&&&##############&&&&
eeeoo***!!:::...&&&########%%%%%%%%#####&&
eeoo**!!!::...&&######%%%%%%%eeeeee%%%%###
eooo**!!::..&&&#####%%%%%eeeeeooooooeeee%%#&
oo**!!:&&&&&&&####%%%%eeeoooo********oooee%#
&&&&&&&&&&&&#####%%%eeeoo****!!!!!!!!***oe%#
&&&&&&&&&&&####%%%eeeoo***!!!::::::::!!**oe#
&&&&&&&&&&###%%%eeooo**!!:::.......::!!*oe
&&&&&&&&&####%%eeeoo**!!::..........::!*o%
&&&&&&&&####%%eeoo**!!::...........:!*o%
&&&&&&####%%eeoo**!!::..........:!*o
&&&&&&###%%%eeoo**!!::......::!*oe
&&&&&###%%%eeoo**!!!!:::!!!*o%
&&&&###%%%eeoooo****ooe%
&&####%%%%%%%#
</pre>

=={{header|J}}==
{{Trans|Python}}

<syntaxhighlight lang="j">
load'graphics/viewmat'
mag =: +/&.:*:"1
norm=: %"1 0 mag
dot =: +/@:*"1

NB. (pos;posr;neg;negr) getvec (x,y)
getvec =: 4 :0 "1
pt =. y
'pos posr neg negr' =. x
if. (dot~ pt-}:pos) > *:posr do.
0 0 0
else.
zb =. ({:pos) (-,+) posr -&.:*: pt mag@:- }:pos
if. (dot~ pt-}:neg) > *:negr do.
(pt,{:zb) - pos
else.
zs =. ({:neg) (-,+) negr -&.:*: pt mag@:- }:neg
if. zs >&{. zb do. (pt,{:zb) - pos
elseif. zs >&{: zb do. 0 0 0
elseif. ({.zs) < ({:zb) do. neg - (pt,{.zs)
elseif. do. (pt,{.zb) - pos end.
end.
end.
)

NB. (k;ambient;light) draw_sphere (pos;posr;neg;negr)
draw_sphere =: 4 :0
'pos posr neg negr' =. y
'k ambient light' =. x
vec=. norm y getvec ,"0// (2{.pos) +/ i: 200 j.~ 0.5+posr

b=. (mag vec) * ambient + k * 0>. light dot vec
)

togray =: 256#. 255 255 255 <.@*"1 0 (%>./@,)

env=.(2; 0.5; (norm _50 30 50))
sph=. 20 20 0; 20; 1 1 _6; 20
'rgb' viewmat togray env draw_sphere sph</syntaxhighlight>

=={{header|Java}}==
{{libheader|JavaFX}}
<syntaxhighlight lang="java">import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
public class DeathStar extends Application {

private static final int DIVISION = 200;// the bigger the higher resolution
float radius = 300;// radius of the sphere

@Override
public void start(Stage primaryStage) throws Exception {
Point3D otherSphere = new Point3D(-radius, 0, -radius * 1.5);
final TriangleMesh triangleMesh = createMesh(DIVISION, radius, otherSphere);
MeshView a = new MeshView(triangleMesh);

a.setTranslateY(radius);
a.setTranslateX(radius);
a.setRotationAxis(Rotate.Y_AXIS);
Scene scene = new Scene(new Group(a));
// uncomment if you want to move the other sphere
// scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
// Point3D sphere = otherSphere;
//
// @Override
// public void handle(KeyEvent e) {
// KeyCode code = e.getCode();
// switch (code) {
// case UP:
// sphere = sphere.add(0, -10, 0);
// break;
// case DOWN:
// sphere = sphere.add(0, 10, 0);
// break;
// case LEFT:
// sphere = sphere.add(-10, 0, 0);
// break;
// case RIGHT:
// sphere = sphere.add(10, 0, 0);
// break;
// case W:
// sphere = sphere.add(0, 0, 10);
// break;
// case S:
// sphere = sphere.add(0, 0, -10);
// break;
// default:
// return;
// }
// a.setMesh(createMesh(DIVISION, radius, sphere));
//
// }
// });

primaryStage.setScene(scene);
primaryStage.show();
}

static TriangleMesh createMesh(final int division, final float radius, final Point3D centerOtherSphere) {
Rotate rotate = new Rotate(180, centerOtherSphere);
final int div2 = division / 2;

final int nPoints = division * (div2 - 1) + 2;
final int nTPoints = (division + 1) * (div2 - 1) + division * 2;
final int nFaces = division * (div2 - 2) * 2 + division * 2;

final float rDiv = 1.f / division;

float points[] = new float[nPoints * 3];
float tPoints[] = new float[nTPoints * 2];
int faces[] = new int[nFaces * 6];

int pPos = 0, tPos = 0;

for (int y = 0; y < div2 - 1; ++y) {
float va = rDiv * (y + 1 - div2 / 2) * 2 * (float) Math.PI;
float sin_va = (float) Math.sin(va);
float cos_va = (float) Math.cos(va);

float ty = 0.5f + sin_va * 0.5f;
for (int i = 0; i < division; ++i) {
double a = rDiv * i * 2 * (float) Math.PI;
float hSin = (float) Math.sin(a);
float hCos = (float) Math.cos(a);
points[pPos + 0] = hSin * cos_va * radius;
points[pPos + 2] = hCos * cos_va * radius;
points[pPos + 1] = sin_va * radius;

final Point3D point3D = new Point3D(points[pPos + 0], points[pPos + 1], points[pPos + 2]);
double distance = centerOtherSphere.distance(point3D);
if (distance <= radius) {
Point3D subtract = centerOtherSphere.subtract(point3D);
Point3D transform = rotate.transform(subtract);
points[pPos + 0] = (float) transform.getX();
points[pPos + 1] = (float) transform.getY();
points[pPos + 2] = (float) transform.getZ();
}
tPoints[tPos + 0] = 1 - rDiv * i;
tPoints[tPos + 1] = ty;
pPos += 3;
tPos += 2;
}
tPoints[tPos + 0] = 0;
tPoints[tPos + 1] = ty;
tPos += 2;
}

points[pPos + 0] = 0;
points[pPos + 1] = -radius;
points[pPos + 2] = 0;
points[pPos + 3] = 0;
points[pPos + 4] = radius;
points[pPos + 5] = 0;
pPos += 6;

int pS = (div2 - 1) * division;

float textureDelta = 1.f / 256;
for (int i = 0; i < division; ++i) {
tPoints[tPos + 0] = rDiv * (0.5f + i);
tPoints[tPos + 1] = textureDelta;
tPos += 2;
}

for (int i = 0; i < division; ++i) {
tPoints[tPos + 0] = rDiv * (0.5f + i);
tPoints[tPos + 1] = 1 - textureDelta;
tPos += 2;
}

int fIndex = 0;
for (int y = 0; y < div2 - 2; ++y) {
for (int x = 0; x < division; ++x) {
int p0 = y * division + x;
int p1 = p0 + 1;
int p2 = p0 + division;
int p3 = p1 + division;

int t0 = p0 + y;
int t1 = t0 + 1;
int t2 = t0 + division + 1;
int t3 = t1 + division + 1;

// add p0, p1, p2
faces[fIndex + 0] = p0;
faces[fIndex + 1] = t0;
faces[fIndex + 2] = p1 % division == 0 ? p1 - division : p1;
faces[fIndex + 3] = t1;
faces[fIndex + 4] = p2;
faces[fIndex + 5] = t2;
fIndex += 6;

// add p3, p2, p1
faces[fIndex + 0] = p3 % division == 0 ? p3 - division : p3;
faces[fIndex + 1] = t3;
faces[fIndex + 2] = p2;
faces[fIndex + 3] = t2;
faces[fIndex + 4] = p1 % division == 0 ? p1 - division : p1;
faces[fIndex + 5] = t1;
fIndex += 6;
}
}

int p0 = pS;
int tB = (div2 - 1) * (division + 1);
for (int x = 0; x < division; ++x) {
int p2 = x, p1 = x + 1, t0 = tB + x;
faces[fIndex + 0] = p0;
faces[fIndex + 1] = t0;
faces[fIndex + 2] = p1 == division ? 0 : p1;
faces[fIndex + 3] = p1;
faces[fIndex + 4] = p2;
faces[fIndex + 5] = p2;
fIndex += 6;
}

p0 = p0 + 1;
tB = tB + division;
int pB = (div2 - 2) * division;

for (int x = 0; x < division; ++x) {
int p1 = pB + x, p2 = pB + x + 1, t0 = tB + x;
int t1 = (div2 - 2) * (division + 1) + x, t2 = t1 + 1;
faces[fIndex + 0] = p0;
faces[fIndex + 1] = t0;
faces[fIndex + 2] = p1;
faces[fIndex + 3] = t1;
faces[fIndex + 4] = p2 % division == 0 ? p2 - division : p2;
faces[fIndex + 5] = t2;
fIndex += 6;
}

TriangleMesh m = new TriangleMesh();
m.getPoints().setAll(points);
m.getTexCoords().setAll(tPoints);
m.getFaces().setAll(faces);

return m;
}

public static void main(String[] args) {

launch(args);
}

}
</syntaxhighlight>
===Using Java 11===
Alternatively, without using JavaFX, which has been removed from the JavaJDK since version 11.
<syntaxhighlight lang="java">

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.imageio.ImageIO;

public final class DeathStar {

public static void main(String[] aArgs) throws IOException {
Vector direction = new Vector(20.0, -40.0, -10.0);
direction.normalise();
Sphere positive = new Sphere(0, 0, 0, 120);
Sphere negative = new Sphere(-90, -90, -30, 100);

BufferedImage image = deathStar(positive, negative, direction, 1.5, 0.5);
ImageIO.write(image, "png", new File("DeathStarJava.png"));
}
private static BufferedImage deathStar(
Sphere aPositive, Sphere aNegative, Vector aDirection, double aShadow, double aBrightness) {
final int width = aPositive.radius * 4;
final int height = aPositive.radius * 3;
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = result.getGraphics();
graphics.setColor(Color.CYAN);
graphics.fillRect(0, 0, width, height);
Vector ray = new Vector(0.0, 0.0, 0.0);
final int deltaX = aPositive.x - width / 2;
final int deltaY = aPositive.y - height / 2;

double xMax = aPositive.x + aPositive.radius;
double yMax = aPositive.y + aPositive.radius;
for ( int y = aPositive.y - aPositive.radius; y < yMax; y++ ) {
for ( int x = aPositive.x - aPositive.radius; x < xMax; x++ ) {
List<Object> contacts = aPositive.contact(x, y);
final double zb1 = (double) contacts.get(0);
final int zb2 = (int) contacts.get(1);
final boolean positiveHit = (boolean) contacts.get(2);
if ( ! positiveHit ) {
continue;
}
contacts = aNegative.contact(x, y);
final double zs1 = (double) contacts.get(0);
final int zs2 = (int) contacts.get(1);
boolean negativeHit = (boolean) contacts.get(2);
if ( negativeHit ) {
if ( zs1 > zb1 ) {
negativeHit = false;
} else if ( zs2 > zb2 ) {
continue;
}
}
if ( negativeHit ) {
ray.x = aNegative.x - x;
ray.y = aNegative.y - y;
ray.z = aNegative.z - zs2;
} else {
ray.x = x - aPositive.x;
ray.y = y - aPositive.y;
ray.z = zb1 - aPositive.z;
}
ray.normalise();
double rayComponent = ray.scalarProduct(aDirection);
if ( rayComponent < 0 ) {
rayComponent = 0;
}
int color = (int) ( 255 * ( Math.pow(rayComponent, aShadow) + aBrightness) / ( 1 + aBrightness ) );
if ( color < 0 ) {
color = 0;
} else if ( color > 255 ) {
color = 255;
}
result.setRGB(x - deltaX, y - deltaY, color);
}
}
return result;
}
private static class Vector {
public Vector(double aX, double aY, double aZ) {
x = aX; y = aY; z = aZ;
}
public double scalarProduct(Vector aOther) {
return x * aOther.x + y * aOther.y + z * aOther.z;
}
public Vector normalise() {
final double magnitude = Math.sqrt(this.scalarProduct(this));
return new Vector(x /= magnitude, y /= magnitude, z /= magnitude);
}
private double x, y, z;
}
private static class Sphere {
public Sphere(int aX, int aY, int aZ, int aRadius) {
x = aX; y = aY; z = aZ; radius = aRadius;
}
public List<Object> contact(int aX, int aY) {
final int xx = aX - x;
final int yy = aY - y;
final int zSquared = radius * radius - ( xx * xx + yy * yy );
if ( zSquared >= 0 ) {
final double zz = Math.sqrt(zSquared);
return List.of(z - zz, z, true);
}
return List.of( 0.0, 0, false );
}
private int x, y, z, radius;
}

}
</syntaxhighlight>
{{ out }}
[[Media:DeathStarJava.png]]

=={{header|JavaScript}}==
Layer circles and gradients to achieve result similar to that of the Wikipedia page for the [http://en.wikipedia.org/wiki/Death_Star Death Star].
<syntaxhighlight lang="javascript">
<!DOCTYPE html>
<html>
<body style="margin:0">
<canvas id="myCanvas" width="250" height="250" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
//Fill the canvas with a dark gray background
ctx.fillStyle = "#222222";
ctx.fillRect(0,0,250,250);

// Create radial gradient for large base circle
var grd = ctx.createRadialGradient(225,175,190,225,150,130);
grd.addColorStop(0,"#EEEEEE");
grd.addColorStop(1,"black");
//Apply gradient and fill circle
ctx.fillStyle = grd;
ctx.beginPath();
ctx.arc(125,125,105,0,2*Math.PI);
ctx.fill();
// Create linear gradient for small inner circle
var grd = ctx.createLinearGradient(75,90,102,90);
grd.addColorStop(0,"black");
grd.addColorStop(1,"gray");
//Apply gradient and fill circle
ctx.fillStyle = grd;
ctx.beginPath();
ctx.arc(90,90,30,0,2*Math.PI);
ctx.fill();
//Add another small circle on top of the previous one to enhance the "shadow"
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(80,90,17,0,2*Math.PI);
ctx.fill();
</script>
</body>
</html>

</syntaxhighlight>

=={{header|Julia}}==
<syntaxhighlight lang="julia"># run in REPL
using GLMakie

function deathstar()
n = 60
θ = [0; (0.5: n - 0.5) / n; 1]
φ = [(0: 2n - 2) * 2 / (2n - 1); 2]
# if x is +0.9 radius units, replace it with the coordinates of sphere surface
# at (1.2,0,0) center, radius 0.5 units
x = [(x1 = cospi(φ)*sinpi(θ)) > 0.9 ? 1.2 - x1 * 0.5 : x1 for θ in θ, φ in φ]
y = [sinpi(φ)*sinpi(θ) for θ in θ, φ in φ]
z = [cospi(θ) for θ in θ, φ in φ]
scene = Scene(backgroundcolor=:black)
surface!(scene, x, y, z, color = rand(RGBAf0, 124, 124), show_axis=false)
return scene
end

scene = deathstar()
</syntaxhighlight>

=={{header|LSL}}==
Rez a box on the ground, raise it up a few meters, add the following as a New Script.
<syntaxhighlight lang="lsl">default {
state_entry() {
llSetPrimitiveParams([PRIM_NAME, "RosettaCode DeathStar"]);
llSetPrimitiveParams([PRIM_DESC, llGetObjectName()]);
llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_SPHERE, PRIM_HOLE_CIRCLE, <0.0, 1.0, 0.0>, 0.0, <0.0, 0.0, 0.0>, <0.12, 1.0, 0.0>]);
llSetPrimitiveParams([PRIM_ROTATION, <-0.586217, 0.395411, -0.586217, 0.395411>]);
llSetPrimitiveParams([PRIM_TEXTURE, ALL_SIDES, TEXTURE_BLANK, ZERO_VECTOR, ZERO_VECTOR, 0.0]);
llSetPrimitiveParams([PRIM_TEXT, llGetObjectName(), <1.0, 1.0, 1.0>, 1.0]);
llSetPrimitiveParams([PRIM_COLOR, ALL_SIDES, <0.5, 0.5, 0.5>, 1.0]);
llSetPrimitiveParams([PRIM_BUMP_SHINY, ALL_SIDES, PRIM_SHINY_HIGH, PRIM_BUMP_NONE]);
llSetPrimitiveParams([PRIM_SIZE, <10.0, 10.0, 10.0>]);
llSetPrimitiveParams([PRIM_OMEGA, <0.0, 0.0, 1.0>, 1.0, 1.0]);
}
}</syntaxhighlight>
Output:
[[File:Death_Star_LSL.jpg|200px|Death Star]]

=={{header|Lua}}==
{{trans|C}}
<syntaxhighlight lang="lua">function V3(x,y,z) return {x=x,y=y,z=z} end
function dot(v,w) return v.x*w.x + v.y*w.y + v.z*w.z end
function norm(v) local m=math.sqrt(dot(v,v)) return V3(v.x/m, v.y/m, v.z/m) end
function clamp(n,lo,hi) return math.floor(math.min(math.max(lo,n),hi)) end
function hittest(s, x, y)
local z = s.r^2 - (x-s.x)^2 - (y-s.y)^2
if z >= 0 then
z = math.sqrt(z)
return true, s.z-z, s.z+z
end
return false, 0, 0
end

function deathstar(pos, neg, sun, k, amb)
shades = {[0]=" ",".",":","!","*","o","e","&","#","%","@"}
for y = pos.x-pos.r-0.5, pos.x+pos.r+0.5 do
for x = pos.x-pos.r-0.5, pos.x+pos.r+0.5, 0.5 do
local hitpos, pz1, pz2 = hittest(pos, x, y)
local result, hitneg, nz1, nz2 = 0
if hitpos then
hitneg, nz1, nz2 = hittest(neg, x, y)
if not hitneg or nz1 > pz1 then result = 1
elseif nz2 > pz2 then result = 0
elseif nz2 > pz1 then result = 2
else result = 1
end
end
local shade = 0
if result > 0 then
if result == 1 then
shade = clamp((1-dot(sun, norm(V3(x-pos.x, y-pos.y, pz1-pos.z)))^k+amb) * #shades, 1, #shades)
else
shade = clamp((1-dot(sun, norm(V3(neg.x-x, neg.y-y, neg.z-nz2)))^k+amb) * #shades, 1, #shades)
end
end
io.write(shades[shade])
end
io.write("\n")
end
end

deathstar({x=20, y=20, z=0, r=20}, {x=10, y=10, z=-15, r=10}, norm(V3(-2,1,3)), 2, 0.1)</syntaxhighlight>
{{out}}
<pre style="font-size:50%"> @@@%%%%%%%%%#########%
@@@@@%%%%%%#######&&&&&&&&&&&&&&&&&&##
@@@@@@%%%%%%######&&&&&&&eeeeeeeeeeeeeeeeeeeee&&
@@@@@@@@@@@@@@@@@@@&&&&&&eeeeeeeoooooooooooooooooooooeee&
@@@@@&####%%%%@@@@@@@@@@@@%eeeeoooooooo*******************oooee
@@@@eeee&&&&####%%%@@@@@@@@@@@@%oooooo********!!!!!!!!!!!!!!*****oooe
@@@**ooooeeee&&&####%%%@@@@@@@@@@@%oo*******!!!!!!!!!!!!!!!!!!!!!!!****oo&
@@@!!!****ooooeee&&&###%%%%@@@@@@@@@@%*****!!!!!!!!:::::::::::::::::!!!!!**ooe
@@@:::!!!!!****oooeee&&###%%%%@@@@@@@@@%***!!!!!!!::::::::::::::::::::::::!!!***oe
@@@@::::::::!!!***oooeee&&&##%%%%@@@@@@@@@**!!!!!!!:::::::::............::::::!!!**oo
@@@.......::::!!!!***ooeee&&###%%%@@@@@@@@@*!!!!!!::::::::..................:::::!!!**oe
%@@@@.........::::!!!**oooee&&&##%%%@@@@@@@@*!!!!!!::::::::......................::::!!!*oe
%@@@@...........:::!!!***ooeee&&###%%%@@@@@@**!!!!!!:::::::........................::::!!!*oo
%@@@@@...........:::!!!***ooeee&&###%%@@@@@@***!!!!!!:::::::.........................::::!!!*oe
@@@@@@..........::::!!!**oooee&&&##%%%@@@@@****!!!!!!:::::::..........................::::!!**oe
%@@@@@@::::...:::::!!!!***ooeee&&###%%@@@@o*****!!!!!!:::::::..........................::::!!!**o
@@@@@@@@!!!:::::!!!!!***oooee&&&##%%%@@oooo******!!!!!!:::::::.........................:::::!!**oe
%@@@@@@@@@o****!******ooooeee&&###%%%eeeooooo*****!!!!!!!:::::::........................::::!!!**oe
%@@@@@@@@@@@eeoooooooeeeee&&&##%%%&eeeeeeooooo*****!!!!!!!::::::::.....................:::::!!!**oo&
%@@@@@@@@@@@@@@@@##&&&#####%###&&&&&eeeeeoooooo******!!!!!!:::::::::..................:::::!!!!**oe&
%@@@@@@@@@@@@@@@@@@@%%%%%%######&&&&&eeeeeoooooo******!!!!!!!:::::::::::...........:::::::!!!!***oe&
%%@@@@@@@@@@@@@@@@@@@%%%%%%######&&&&&eeeeeeooooo*******!!!!!!!::::::::::::::::::::::::::!!!!***ooe&
#%@@@@@@@@@@@@@@@@@@@%%%%%%%######&&&&&eeeeeeoooooo*******!!!!!!!!::::::::::::::::::::!!!!!!***ooee
%%@@@@@@@@@@@@@@@@@@@%%%%%%%######&&&&&&eeeeeeoooooo*******!!!!!!!!!!!!::::::::::!!!!!!!!****ooee&
#%@@@@@@@@@@@@@@@@@@@@%%%%%%%######&&&&&&eeeeeeooooooo*********!!!!!!!!!!!!!!!!!!!!!!!!****oooee&
%%@@@@@@@@@@@@@@@@@@@@@%%%%%%%######&&&&&&eeeeeeeooooooo**********!!!!!!!!!!!!!!!*******ooooee&#
&%%@@@@@@@@@@@@@@@@@@@@@%%%%%%%#######&&&&&&eeeeeeeooooooooo*************************oooooeee&#
#%%@@@@@@@@@@@@@@@@@@@@@@%%%%%%%#######&&&&&&&eeeeeeeooooooooooo****************ooooooeeee&&#
&%%@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%#######&&&&&&&&eeeeeeeeeoooooooooooooooooooooooooeeeee&&##
#%%@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%########&&&&&&&&eeeeeeeeeeeeoooooooooooooeeeeeeee&&&##%
#%%@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########&&&&&&&&&&eeeeeeeeeeeeeeeeeeeeeeee&&&&&##%
#%%@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%#########&&&&&&&&&&&&&&&&eeeee&&&&&&&&&&####%%
#%%@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%%###########&&&&&&&&&&&&&&&&&&&&######%%%
#%%@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%%%#############################%%%%@
#%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%%%%%%%###############%%%%%%%@
#%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@
#%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@
%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@</pre>

=={{header|Maple}}==
<syntaxhighlight lang="maple">with(plots):
with(plottools):
plots:-display(
implicitplot3d(x^2 + y^2 + z^2 = 1, x = -1..0.85, y = -1..1, z = -1..1, style = surface, grid = [50,50,50]),
translate(rotate(implicitplot3d(x^2 + y^2 + z^2 = 1, x = 0.85..1, y = -1..1, z = -1..1, style = surface, grid = [50,50,50]), 0, Pi, 0), 1.70, 0, 0),
axes = none, scaling = constrained, color = gray)</syntaxhighlight>

=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">RegionPlot3D[x^2 + y^2 + z^2 < 1 && (x + 1.7)^2 + y^2 + z^2 > 1,
{x, -1, 1}, {y, -1, 1}, {z, -1, 1},
Boxed -> False, Mesh -> False, Axes -> False, Background -> Black, PlotPoints -> 100]</syntaxhighlight>

=={{header|Nim}}==
{{trans|Go}}
{{libheader|nimPNG}}

The result is written in a PNG file. For this purpose, we used the modules “bitmap” and “grayscale_image” created for the tasks “Bitmap” and “Grayscale image”. To write the PNG file, we use the third party library “nimPNG”.

<syntaxhighlight lang="nim">import math

import bitmap, grayscale_image, nimPNG

type

Vector = array[3, float]

Sphere = object
cx, cy, cz: int
r: int

#---------------------------------------------------------------------------------------------------

func dot(x, y: Vector): float {.inline.} =
x[0] * y[0] + x[1] * y[1] + x[2] * y[2]

#---------------------------------------------------------------------------------------------------

func normalize(v: var Vector) =
let invLen = 1 / sqrt(dot(v, v))
v[0] *= invLen
v[1] *= invLen
v[2] *= invLen

#---------------------------------------------------------------------------------------------------

func hit(s: Sphere; x, y: int): tuple[z1, z2: float; hit: bool] =
let x = x - s.cx
let y = y - s.cy
let zsq = s.r * s.r - (x * x + y * y)
if zsq >= 0:
let zsqrt = sqrt(zsq.toFloat)
result = (s.cz.toFloat - zsqrt, s.cz.toFloat, true)
else:
result = (0.0, 0.0, false)

#---------------------------------------------------------------------------------------------------

func deathStar(pos, neg: Sphere; k, amb: float; dir: Vector): GrayImage =

let w = pos.r * 4
let h = pos.r * 3
result = newGrayImage(w, h)
var vect: Vector
let deltaX = pos.cx - w div 2
let deltaY = pos.cy - h div 2

let xMax = pos.cx + pos.r
let yMax = pos.cy + pos.r
for y in (pos.cy - pos.r)..yMax:
for x in (pos.cx - pos.r)..xMax:
let (zb1, zb2, posHit) = pos.hit(x, y)
if not posHit: continue
var (zs1, zs2, negHit) = neg.hit(x, y)
if negHit:
if zs1 > zb1: negHit = false
elif zs2 > zb2: continue
if negHit:
vect[0] = (neg.cx - x).toFloat
vect[1] = (neg.cy - y).toFloat
vect[2] = neg.cz.toFloat - zs2
else:
vect[0] = (x - pos.cx).toFloat
vect[1] = (y - pos.cy).toFloat
vect[2] = zb1 - pos.cz.toFloat
vect.normalize()
var s = dot(dir, vect)
if s < 0: s = 0
var lum = (255 * (s.pow(k) + amb) / (1 + amb)).toInt
if lum < 0: lum = 0
elif lum > 255: lum = 255
result[x - deltaX, y - deltaY] = Luminance(lum)

#———————————————————————————————————————————————————————————————————————————————————————————————————

var dir: Vector = [float 20, -40, -10]
dir.normalize()
let pos = Sphere(cx: 0, cy: 0, cz: 0, r: 120)
let neg = Sphere(cx: -90, cy: -90, cz: -30, r: 100)

let grayImage = deathStar(pos, neg, 1.5, 0.2, dir)

# Save to PNG. We convert to an RGB image then transform the pixels
# in a sequence of bytes (actually a copy) in order to call "savePNG24".
let rgbImage = grayImage.toImage
var data = newSeqOfCap[byte](rgbImage.pixels.len * 3)
for color in rgbImage.pixels:
data.add([color.r, color.g, color.b])
echo savePNG24("death_star.png", data, rgbImage.w, rgbImage.h)</syntaxhighlight>

=={{header|Openscad}}==
<syntaxhighlight lang="openscad">// We are performing geometric subtraction

difference() {

// Create the primary sphere of radius 60 centred at the origin

translate(v = [0,0,0]) {
sphere(60);
}

/*Subtract an overlapping sphere with a radius of 40
The resultant hole will be smaller than this, because we only
only catch the edge
*/

translate(v = [0,90,0]) {
sphere(40);
}
}</syntaxhighlight>


=={{header|Perl}}==
=={{header|Perl}}==
[[file:death-star-perl.png|thumb]]
[[file:death-star-perl.png|thumb]]
Writes a PGM to stdout.
Writes a PGM to stdout.
<lang perl>use strict;
<syntaxhighlight lang="perl">use strict;


sub sq {
sub sq {
Line 461: Line 1,936:
}
}


draw(2, 0.2);</lang>
draw(2, 0.2);</syntaxhighlight>


=={{header|Perl 6}}==
=={{header|Phix}}==
{{trans|Go}}
{{libheader|Phix/pGUI}}
{{libheader|Phix/online}}
You can run this online [http://phix.x10.mx/p2js/deathstar.htm here]. Note it is rather slow to redraw fullscreen.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\DeathStar.exw
-- ==========================
--
-- Translated from Go.
--</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">title</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Death Star"</span>
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span>
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">dot</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sum</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">normalize</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">len</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dot</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">len</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sq_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">/</span><span style="color: #000000;">len</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">enum</span> <span style="color: #000000;">X</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Z</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">hit</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">x</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">y</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">zsq</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">*</span><span style="color: #000000;">r</span> <span style="color: #0000FF;">-</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">*</span><span style="color: #000000;">x</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">*</span><span style="color: #000000;">y</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">zsq</span> <span style="color: #0000FF;">>=</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">zsqrt</span> <span style="color: #0000FF;">:=</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">zsq</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Z</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">zsqrt</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Z</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">zsqrt</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">true</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">false</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">deathStar</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">height</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">amb</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">direction</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">t1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">t0</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">lmul</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">255</span><span style="color: #0000FF;">/(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">+</span><span style="color: #000000;">amb</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">width</span><span style="color: #0000FF;">,</span><span style="color: #000000;">height</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">40</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">cx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">width</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">cy</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">height</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">pos</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #000000;">neg</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">r</span><span style="color: #0000FF;">*-</span><span style="color: #000000;">3</span><span style="color: #0000FF;">/</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">r</span><span style="color: #0000FF;">*-</span><span style="color: #000000;">3</span><span style="color: #0000FF;">/</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">r</span><span style="color: #0000FF;">*-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">/</span><span style="color: #000000;">4</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">r</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">+</span><span style="color: #000000;">r</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()></span><span style="color: #000000;">t1</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- Let the user know we aren't completely dead just yet</span>
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s - drawing (%d%%)"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">title</span><span style="color: #0000FF;">,</span><span style="color: #000000;">100</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)/(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">t1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()+</span><span style="color: #000000;">1</span>
<span style="color: #000080;font-style:italic;">--
-- Hmm, not entirely sure why this is needed, but without it
-- after ~7 seconds the window gets a "(Not Responding)" and
-- then something decides to force a full repaint, which at
-- fullscreen will never finish in &lt; 7s on this ancient box.
-- I suppose this is the corrollary to the above, this time
-- letting Windows 10 know the process is not quite dead...
-- Currently and possibly forever neither of these routines
-- exist in pGUI.js, the browser is more forgiving anyway.
--</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">IupLoopStep</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">IUP_CLOSE</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupExitLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">r</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">+</span><span style="color: #000000;">r</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">zb1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">zb2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">hit1</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">hit</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">hit1</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">zs1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">zs2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">hit2</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">hit</span><span style="color: #0000FF;">(</span><span style="color: #000000;">neg</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">hit2</span> <span style="color: #008080;">or</span> <span style="color: #000000;">zs2</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">zb2</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">dish</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">hit2</span> <span style="color: #008080;">and</span> <span style="color: #000000;">zs1</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">zb1</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">vec</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dish</span><span style="color: #0000FF;">?</span><span style="color: #7060A8;">sq_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">neg</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">zs2</span><span style="color: #0000FF;">}):{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">zb1</span><span style="color: #0000FF;">})</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dot</span><span style="color: #0000FF;">(</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">normalize</span><span style="color: #0000FF;">(</span><span style="color: #000000;">vec</span><span style="color: #0000FF;">)),</span>
<span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #000000;">0</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">))</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">lum</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">#FF</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lmul</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">+</span><span style="color: #000000;">amb</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">cdCanvasPixel</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cy</span><span style="color: #0000FF;">-</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lum</span><span style="color: #0000FF;">*</span><span style="color: #000000;">#10101</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">t1</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">t0</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">title</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000080;font-style:italic;">/*posx*/</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">/*posy*/</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">height</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasClear</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">deathStar</span><span style="color: #0000FF;">(</span><span style="color: #000000;">width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">height</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">normalize</span><span style="color: #0000FF;">({</span><span style="color: #000000;">20</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">40</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">10</span><span style="color: #0000FF;">}))</span>
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_DBUFFER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_BLACK</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=340x340"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetCallbacks</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">),</span>
<span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`TITLE="%s"`</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">title</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">IupMap</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- release the minimum limitation</span>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->

=={{header|POV-Ray}}==
<syntaxhighlight lang="pov">camera { perspective location <0.0 , .8 ,-3.0> look_at 0
aperture .1 blur_samples 20 variance 1/100000 focal_point 0}
light_source{< 3,3,-3> color rgb 1}

sky_sphere { pigment{ color rgb <0,.2,.5>}}

plane {y,-5 pigment {color rgb .54} normal {hexagon} }

difference {
sphere { 0,1 }
sphere { <-1,1,-1>,1 }
texture {
pigment{ granite }
finish { phong 1 reflection {0.10 metallic 0.5} }
}
} </syntaxhighlight>
[[image:PovRay-deathstar.jpg]]

=={{header|Python}}==
{{trans|C}}
<syntaxhighlight lang="python">import sys, math, collections

Sphere = collections.namedtuple("Sphere", "cx cy cz r")
V3 = collections.namedtuple("V3", "x y z")

def normalize((x, y, z)):
len = math.sqrt(x**2 + y**2 + z**2)
return V3(x / len, y / len, z / len)

def dot(v1, v2):
d = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z
return -d if d < 0 else 0.0

def hit_sphere(sph, x0, y0):
x = x0 - sph.cx
y = y0 - sph.cy
zsq = sph.r ** 2 - (x ** 2 + y ** 2)
if zsq < 0:
return (False, 0, 0)
szsq = math.sqrt(zsq)
return (True, sph.cz - szsq, sph.cz + szsq)

def draw_sphere(k, ambient, light):
shades = ".:!*oe&#%@"
pos = Sphere(20.0, 20.0, 0.0, 20.0)
neg = Sphere(1.0, 1.0, -6.0, 20.0)

for i in xrange(int(math.floor(pos.cy - pos.r)),
int(math.ceil(pos.cy + pos.r) + 1)):
y = i + 0.5
for j in xrange(int(math.floor(pos.cx - 2 * pos.r)),
int(math.ceil(pos.cx + 2 * pos.r) + 1)):
x = (j - pos.cx) / 2.0 + 0.5 + pos.cx

(h, zb1, zb2) = hit_sphere(pos, x, y)
if not h:
hit_result = 0
else:
(h, zs1, zs2) = hit_sphere(neg, x, y)
if not h:
hit_result = 1
elif zs1 > zb1:
hit_result = 1
elif zs2 > zb2:
hit_result = 0
elif zs2 > zb1:
hit_result = 2
else:
hit_result = 1

if hit_result == 0:
sys.stdout.write(' ')
continue
elif hit_result == 1:
vec = V3(x - pos.cx, y - pos.cy, zb1 - pos.cz)
elif hit_result == 2:
vec = V3(neg.cx-x, neg.cy-y, neg.cz-zs2)
vec = normalize(vec)

b = dot(light, vec) ** k + ambient
intensity = int((1 - b) * len(shades))
intensity = min(len(shades), max(0, intensity))
sys.stdout.write(shades[intensity])
print

light = normalize(V3(-50, 30, 50))
draw_sphere(2, 0.5, light)</syntaxhighlight>

=={{header|Q}}==
write an image in BMP format:
<syntaxhighlight lang="q">
/ https://en.wikipedia.org/wiki/BMP_file_format
/ BITMAPINFOHEADER / RGB24

/ generate a header

genheader:{[w;h]
0x424d, "x"$(f2i4[54+4*h*w],0,0,0,0,54,0,0,0,40,0,0,0,
f2i4[h],f2i4[w],1,0,24,0,0,0,0,0,
f2i4[h*((w*3)+((w*3)mod 4))],
19,11,0,0,19,11,0,0,0,0,0,0,0,0,0,0)};

/ generate a raster line at a vertical position

genrow:{[w;y;fcn]
row:enlist 0i;xx:0i;do[w;row,:fcn[xx;y];xx+:1i];row,:((w mod 4)#0i);1_row};

/ generate a bitmap

genbitmap:{[w;h;fcn]
ary:enlist 0i;yy:0i;do[h;ary,:genrow[w;yy;fcn];yy+:1i];"x"$1_ary};

/ deal with endianness
/ might need to reverse last line if host computer is not a PC

f2i4:{[x] r:x;
s0:r mod 256;r-:s0; r%:256;
s1:r mod 256;r-:s1; r%:256;
s2:r mod 256;r-:s2; r%:256;
s3:r mod 256;
"h"$(s0,s1,s2,s3)}

/ compose and write a file

writebmp:{[w;h;fcn;fn]
fn 1: (genheader[h;w],genbitmap[w;h;fcn])};

/ / usage example:
/ w:400;
/ h:300;
/ fcn:{x0:x-w%2;y0:y-h%2;r:175;$[(r*r)>((x0*x0)+(y0*y0));(0;0;255);(0;255;0)]};
/ fn:`:demo.bmp;
/ writebmp[w;h;fcn;fn];
</syntaxhighlight>

Create the death star image:

<syntaxhighlight lang="q">
w:400; h:300; r:150; l:-0.5 0.7 0.5
sqrt0:{$[x>0;sqrt x;0]};

/ get x,y,z position of point on sphere given x,y,r

z:{[x;y;r]sqrt0((r*r)-((x*x)+(y*y)))};

/ get diffused light at point on sphere

is:{[x;y;r]
z0:z[x;y;r];
s:(x;y;z0)%r;
$[z0>0;i:0.5*1+(+/)(s*l);i:0];
i};

/ get pixel value at given image position

fcn:{[xpx;ypx]
x:xpx-w%2;
y:ypx-h%2;
z1:z[x;y;r];
x2:x+190;
z2:170-z[x2;y;r];
$[(r*r)<((x*x)+(y*y));
$[y>-50;
i:3#0;
i:200 100 50];
$[z2>z1;
i:3#is[x;y;r]*140;
i:3#is[(-1*x2);(-1*y);r]*120]
];
"i"$i};

/ do it ...

\l bmp.q
fn:`:demo.bmp;
writebmp[w;h;fcn;fn];

</syntaxhighlight>(converted to JPG ...)

[[image:qdstar.jpg]]

=={{header|Racket}}==
<syntaxhighlight lang="racket">
#lang racket
(require plot)
(plot3d (polar3d (λ (φ θ) (real-part (- (sin θ) (sqrt (- (sqr 1/3) (sqr (cos θ)))))))
#:samples 100 #:line-style 'transparent #:color 9)
#:altitude 60 #:angle 80
#:height 500 #:width 400
#:x-min -1/2 #:x-max 1/2
#:y-min -1/2 #:y-max 1/2
#:z-min 0 #:z-max 1)
</syntaxhighlight>
[[File:death-star.png]]

=={{header|Raku}}==
(formerly Perl 6)
{{trans|C}}Reimplemented to output a .pgm image.
{{trans|C}}Reimplemented to output a .pgm image.
{{works with|Rakudo|2018.10}}
[[File:Deathstar-perl6.png|thumb]]
[[File:Deathstar-perl6.png|thumb]]
<lang perl6>class sphere {
<syntaxhighlight lang="raku" line>class sphere {
has $.cx; # center x coordinate
has $.cx; # center x coordinate
has $.cy; # center y coordinate
has $.cy; # center y coordinate
Line 475: Line 2,278:
my $depth = 255; # image color depth
my $depth = 255; # image color depth


my $x = my $y = 255; # dimensions of generated .pgm; must be odd
my $width = my $height = 255; # dimensions of generated .pgm; must be odd


my $s = ($x - 1)/2; # scaled dimension to build geometry
my $s = ($width - 1)/2; # scaled dimension to build geometry


my @light = normalize([ 4, -1, -3 ]);
my @light = normalize([ 4, -1, -3 ]);
Line 498: Line 2,301:


sub MAIN ($outfile = 'deathstar-perl6.pgm') {
sub MAIN ($outfile = 'deathstar-perl6.pgm') {
my $out = open( $outfile, :w, :bin ) or die "$!\n";
spurt $outfile, ("P5\n$width $height\n$depth\n"); # .pgm header
$out.say("P5\n$x $y\n$depth"); # .pgm header
my $out = open( $outfile, :a, :bin ) orelse .die;
say 'Calculating row:';
say 'Working...';
$out.print( draw_ds(3, .15)».chrs );
$out.write( Blob.new( |draw_ds(3, .15) ) );
say 'File written.';
$out.close;
$out.close;
}
}


sub draw_ds ( $k, $ambient ) {
sub draw_ds ( $k, $ambient ) {
my @pixels;
my @pixels[$height];

my $bs = "\b" x 8;
for ($pos.cy - $pos.r) .. ($pos.cy + $pos.r) -> $y {
(($pos.cy - $pos.r) .. ($pos.cy + $pos.r)).race.map: -> $y {
note $bs, $y, ' '; # monitor progress
my @row[$width];
for ($pos.cx - $pos.r) .. ($pos.cx + $pos.r) -> $x {
(($pos.cx - $pos.r) .. ($pos.cx + $pos.r)).map: -> $x {
# black if we don't hit positive sphere, ignore negative sphere
# black if we don't hit positive sphere, ignore negative sphere
if not hit($pos, $x, $y, my $posz) {
if not hit($pos, $x, $y, my $posz) {
@pixels.push(0);
@row[$x + $s] = 0;
next;
next;
}
}
Line 520: Line 2,324:
if hit($neg, $x, $y, my $negz) and $negz.min < $posz.min < $negz.max {
if hit($neg, $x, $y, my $negz) and $negz.min < $posz.min < $negz.max {
# make black if whole positive sphere eaten here
# make black if whole positive sphere eaten here
if $negz.min < $posz.max < $negz.max { @pixels.push(0); next; }
if $negz.min < $posz.max < $negz.max { @row[$x + $s] = 0; next; }
# render inside of negative sphere
# render inside of negative sphere
@vec = normalize([$neg.cx - $x, $neg.cy - $y, -$negz.max - $neg.cz]);
@vec = normalize([$neg.cx - $x, $neg.cy - $y, -$negz.max - $neg.cz]);
Line 529: Line 2,333:
}
}
my $intensity = dot(@light, @vec) ** $k + $ambient;
my $intensity = dot(@light, @vec) ** $k + $ambient;
@pixels.push( ($intensity * $depth).Int min $depth );
@row[$x + $s] = ($intensity * $depth).Int min $depth;
}
}
@pixels[$y + $s] = @row;
}
}
say $bs, 'Writing file.';
flat |@pixels.map: *.list;
return @pixels;
}
}


# normalize a vector
# normalize a vector
sub normalize (@vec) { return @vec »/» ([+] @vec Z* @vec).sqrt }
sub normalize (@vec) { @vec »/» ([+] @vec »*« @vec).sqrt }


# dot product of two vectors
# dot product of two vectors
sub dot (@x, @y) { return -([+] @x Z* @y) max 0 }
sub dot (@x, @y) { -([+] @x »*« @y) max 0 }


# are the coordinates within the radius of the sphere?
# are the coordinates within the radius of the sphere?
Line 547: Line 2,351:
$y -= $sphere.cy;
$y -= $sphere.cy;
my $z2 = $sphere.r * $sphere.r - $x * $x - $y * $y;
my $z2 = $sphere.r * $sphere.r - $x * $x - $y * $y;
return 0 if $z2 < 0;
return False if $z2 < 0;
$z2 = $z2.sqrt;
$z2 = $z2.sqrt;
$z = $sphere.cz - $z2 .. $sphere.cz + $z2;
$z = $sphere.cz - $z2 .. $sphere.cz + $z2;
return 1;
True;
}</lang>
}</syntaxhighlight>


=={{header|Python}}==
=={{header|REXX}}==
{{trans|C}}
{{trans|D}}
<lang python>import sys, math, collections


(Apologies for the comments making the lines so wide, but it was easier to read and compare to the original &nbsp; '''D''' &nbsp; source.)
Sphere = collections.namedtuple("Sphere", "cx cy cz r")
<syntaxhighlight lang="rexx">/*REXX program displays a sphere with another sphere subtracted where it's superimposed.*/
V3 = collections.namedtuple("V3", "x y z")
call deathStar 2, .5, v3('-50 30 50')
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
dot: #=0; do j=1 for words(x); #=# + word(x,j)*word(y,j); end; return #
dot.: procedure; parse arg x,y; d=dot(x,y); if d<0 then return -d; return 0
ceil: procedure; parse arg x; _=trunc(x); return _+(x>0)*(x\=_)
floor: procedure; parse arg x; _=trunc(x); return _-(x<0)*(x\=_)
v3: procedure; parse arg a b c; #=sqrt(a**2 + b**2 + c**2); return a/# b/# c/#
/*──────────────────────────────────────────────────────────────────────────────────────*/
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); h= d+6; numeric digits
m.=9; numeric form; parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g*.5'e'_%2
do j=0 while h>9; m.j= h; h= h % 2 + 1; end /*j*/
do k=j+5 to 0 by -1; numeric digits m.k; g= (g +x/g)* .5; end /*k*/; return g
/*──────────────────────────────────────────────────────────────────────────────────────*/
hitSphere: procedure expose !.; parse arg xx yy zz r,x0,y0; z= r*r -(x0-xx)**2-(y0-yy)**2
if z<0 then return 0; _= sqrt(z); !.z1= zz - _; !.z2= zz + _; return 1
/*──────────────────────────────────────────────────────────────────────────────────────*/
deathStar: procedure; parse arg k,ambient,sun /* [↓] display the deathstar to screen*/
parse var sun s1 s2 s3 /*identify the light source coördinates*/
if 5=="f5"x then shading= '.:!*oe&#%@' /*dithering chars for an EBCDIC machine*/
else shading= '·:!ºoe@░▒▓' /* " " " " ASCII " */
shadingL= length(shading) /*the number of dithering characters. */
shades.= ' '; do i=1 for shadingL; shades.i= substr(shading, i, 1)
end /*i*/
ship= 20 20 0 20 ; parse var ship shipX shipY shipZ shipR
hole= ' 1 1 -6 20' ; parse var hole holeX holeY holeZ .


do i=floor(shipY-shipR ) to ceil(shipY+shipR )+1; y= i +.5; @= /*@ is a single line of the deathstar to be displayed.*/
def normalize((x, y, z)):
len = math.sqrt(x**2 + y**2 + z**2)
do j=floor(shipX-shipR*2) to ceil(shipX+shipR*2)+1; !.= 0
x=.5 * (j-shipX+1) + shipX; $bg= 0; $pos= 0; $neg= 0 /*$BG, $POS, and $NEG are boolean values. */
return V3(x / len, y / len, z / len)
?= hitSphere(ship, x, y); b1= !.z1; b2= !.z2 /*? is boolean, "true" indicates ray hits the sphere.*/
/*$BG: if 1, its background; if zero, it's foreground.*/
if \? then $bg= 1 /*ray lands in blank space, so draw the background. */
else do; ?= hitSphere(hole, x, y); s1= !.z1; s2= !.z2
if \? then $pos= 1 /*ray hits ship but not the hole, so draw ship surface. */
else if s1>b1 then $pos=1 /*ray hits both, but ship front surface is closer. */
else if s2>b2 then $bg= 1 /*ship surface is inside hole, so show the background. */
else if s2>b1 then $neg=1 /*hole back surface is inside ship; the only place ··· */
else $pos=1 /*························ a hole surface will be shown.*/
end
select
when $bg then do; @= @' '; iterate j; end /*append a blank character to the line to be displayed. */
when $pos then vec_= v3(x-shipX y-shipY b1-shipZ)
when $neg then vec_= v3(holeX-x holeY-y holeZ-s2)
end /*select*/


b=1 +min(shadingL, max(0, trunc((1 - (dot.(sun, v3(vec_))**k + ambient)) * shadingL)))
def dot(v1, v2):
@=@ || shades.b /*B: the ray's intensity│brightness*/
d = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z
end /*j*/ /* [↑] build a line for the sphere.*/
return -d if d < 0 else 0.0


if @\='' then say strip(@, 'T') /*strip trailing blanks from line. */
def hit_sphere(sph, x0, y0):
end /*i*/ /* [↑] show all lines for sphere. */
x = x0 - sph.cx
return</syntaxhighlight>
y = y0 - sph.cy
{{out|output|text=&nbsp; when using the internal default input:}}
zsq = sph.r ** 2 - (x ** 2 + y ** 2)
(Shown at &nbsp; <big>'''<sup>1</sup>/<sub>2</sub>'''</big> &nbsp; size.)
if zsq < 0:
<pre style="font-size:50%">
return (False, 0, 0)
eeeee:::::::
szsq = math.sqrt(zsq)
eeeeeeeee··············
return (True, sph.cz - szsq, sph.cz + szsq)
ooeeeeeeeeee··················
ooooeeeeeeeee······················
oooooooeeeeeeee··························
ooooooooooeeeee······························
ººooooooooooeeee·································
ººººooooooooooee·····································
!ºººººooooooooooe·······································
!!!ºººººooooooooo:··········································
:!!!!ºººººooooooo:::···········································
:::!!!!ºººººooooo!:::::···········································
::::!!!!!ºººººooo!!!!::::············································
·::::!!!!ºººººooº!!!!!::::············································
···::::!!!!ººººººººº!!!!:::::············································
···::::!!!!ººººoººººº!!!!!::::············································
····::::!!!!ºººoooºººººº!!!!!::::············································
····::::!!!!ºoooooooººººº!!!!!:::::···········································
···::::!!!!!ooooooooooººººº!!!!!:::::··········································
:::::!!!!eeoooooooooooºººººº!!!!!:::::·········································
!!!!!eeeeeeeoooooooooooºººººº!!!!!:::::········································
eeeeeeeeeeeeooooooooooooºººººº!!!!!:::::·······································
eeeeeeeeeeeeeooooooooooooºººººº!!!!!!:::::·····································
eeeeeeeeeeeeeeooooooooooooºººººº!!!!!!:::::····································
eeeeeeeeeeeeeeooooooooooooººººººº!!!!!!:::::·································
eeeeeeeeeeeeeeeoooooooooooooºººººº!!!!!!::::::······························:
eeeeeeeeeeeeeeeoooooooooooooººººººº!!!!!!:::::::··························:
eeeeeeeeeeeeeeeeooooooooooooooººººººº!!!!!!!:::::::·····················::!
eeeeeeeeeeeeeeeeeoooooooooooooºººººººº!!!!!!!:::::::::··············::::!
eeeeeeeeeeeeeeeeeooooooooooooooºººººººº!!!!!!!!::::::::::::::::::::::!º
eeeeeeeeeeeeeeeeeeoooooooooooooooºººººººº!!!!!!!!!!:::::::::::::!!!!º
eeeeeeeeeeeeeeeeeooooooooooooooooºººººººººº!!!!!!!!!!!!!!!!!!!!!º
eeeeeeeeeeeeeeeeeeoooooooooooooooooºººººººººººº!!!!!!!!!!!!ºººº
eeeeeeeeeeeeeeeeeeooooooooooooooooooººººººººººººººººººººººo
eeeeeeeeeeeeeeeeeeeoooooooooooooooooooooººººººººººººooo
eeeeeeeeeeeeeeeeeeeeooooooooooooooooooooooooooooooo
eeeeeeeeeeeeeeeeeeeeooooooooooooooooooooooooo
eeeeeeeeeeeeeeeeeeeeeoooooooooooooooooo
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeee
</pre>


=={{header|Set lang}}==
def draw_sphere(k, ambient, light):
<syntaxhighlight lang="set_lang">set ! 32
shades = ".:!*oe&#%@"
set ! 32
pos = Sphere(20.0, 20.0, 0.0, 20.0)
set ! 46
neg = Sphere(1.0, 1.0, -6.0, 20.0)
set ! 45
set ! 126
set ! 34
set ! 34
set ! 126
set ! 45
set ! 46
set ! 10
set ! 46
set ! 39
set ! 40
set ! 95
set ! 41
set ! 32
set ! 32
set ! 32
set ! 32
set ! 32
set ! 39
set ! 46
set ! 10
set ! 124
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 124
set ! 10
set ! 39
set ! 46
set ! 32
set ! 32
set ! 32
set ! 32
set ! 32
set ! 32
set ! 32
set ! 32
set ! 46
set ! 39
set ! 10
set ! 32
set ! 32
set ! 126
set ! 45
set ! 46
set ! 95
set ! 95
set ! 46
set ! 45
set ! 126</syntaxhighlight>
Outputs:
<pre> .-~""~-.
.'(_) '.
|==========|
'. .'
~-.__.-~</pre>
(it's the best I could do!)


=={{header|Sidef}}==
for i in xrange(int(math.floor(pos.cy - pos.r)),
{{trans|Perl}}
int(math.ceil(pos.cy + pos.r) + 1)):
Writes a PGM to stdout.
y = i + 0.5
<syntaxhighlight lang="ruby">func hitf(sph, x, y) {
for j in xrange(int(math.floor(pos.cx - 2 * pos.r)),
x -= sph[0]
int(math.ceil(pos.cx + 2 * pos.r) + 1)):
y -= sph[1]
x = (j - pos.cx) / 2.0 + 0.5 + pos.cx


(h, zb1, zb2) = hit_sphere(pos, x, y)
var z = (sph[3]**2 - (x**2 + y**2))
if not h:
hit_result = 0
else:
(h, zs1, zs2) = hit_sphere(neg, x, y)
if not h:
hit_result = 1
elif zs1 > zb1:
hit_result = 1
elif zs2 > zb2:
hit_result = 0
elif zs2 > zb1:
hit_result = 2
else:
hit_result = 1


if hit_result == 0:
z < 0 && return nil
sys.stdout.write(' ')
continue
elif hit_result == 1:
vec = V3(x - pos.cx, y - pos.cy, zb1 - pos.cz)
elif hit_result == 2:
vec = V3(neg.cx-x, neg.cy-y, neg.cz-zs2)
vec = normalize(vec)


z.sqrt!
b = dot(light, vec) ** k + ambient
[sph[2] - z, sph[2] + z]
intensity = int((1 - b) * len(shades))
}
intensity = min(len(shades), max(0, intensity))
sys.stdout.write(shades[intensity])
print


light = normalize(V3(-50, 30, 50))
func normalize(v) {
v / v.abs
draw_sphere(2, 0.5, light)</lang>
}


func dot(x, y) {
=={{header|Openscad}}==
max(0, x*y)
<lang openscad>// We are performing geometric subtraction
}


var pos = [120, 120, 0, 120]
difference() {
var neg = [-77, -33, -100, 190]
var light = normalize(Vector(-12, 13, -10))


func draw(k, amb) {
// Create the primary sphere of radius 60 centred at the origin
STDOUT.binmode(':raw')
print ("P5\n", pos[0]*2 + 3, " ", pos[1]*2 + 3, "\n255\n")


for y in ((pos[1] - pos[3] - 1) .. (pos[1] + pos[3] + 1)) {
translate(v = [0,0,0]) {
var row = []
sphere(60);
for x in ((pos[0] - pos[3] - 1) .. (pos[0] + pos[3] + 1)) {
}


var hit = 0
/*Subtract an overlapping sphere with a radius of 40
The resultant hole will be smaller than this, because we only
var hs = []
var h = hitf(pos, x, y)
only catch the edge
*/


if (!h) { hit = 0; h = [0, 0] }
translate(v = [0,90,0]) {
elsif (!(hs = hitf(neg, x, y))) { hit = 1; hs = [0, 0] }
sphere(40);
elsif (hs[0] > h[0]) { hit = 1 }
}
elsif (hs[1] > h[0]) { hit = (hs[1] > h[1] ? 0 : 2) }
}</lang>
else { hit = 1 }
{{omit from|Modula-2}}


var (val, v)
=={{header|POV-Ray}}==
<lang POV-Ray>camera { perspective location <0.0 , .8 ,-3.0> look_at 0
aperture .1 blur_samples 20 variance 1/100000 focal_point 0}
light_source{< 3,3,-3> color rgb 1}


given(hit) {
sky_sphere { pigment{ color rgb <0,.2,.5>}}
when (0) { val = 0}
when (1) { v = Vector(x-pos[0], y-pos[1], h[0]-pos[2]) }
default { v = Vector(neg[0]-x, neg[1]-y, neg[2]-hs[1]) }
}


if (defined(v)) {
plane {y,-5 pigment {color rgb .54} normal {hexagon} }
v = normalize(v)
val = int((dot(v, light)**k + amb) * 255)
val = (val > 255 ? 255 : (val < 0 ? 0 : val))
}
row.append(val)
}
print 'C*'.pack(row...)
}
}


draw(2, 0.2)</syntaxhighlight>
difference {
Output image: [https://github.com/trizen/rc/blob/master/img/death_star_sidef.png here].
sphere { 0,1 }
sphere { <-1,1,-1>,1 }
texture {
pigment{ granite }
finish { phong 1 reflection {0.10 metallic 0.5} }
}
} </lang>
[[image:PovRay-deathstar.jpg]]


=={{header|Tcl}}==
=={{header|Tcl}}==
{{trans|C}}
{{trans|C}}
Note that this code has a significant amount of refactoring relative to the C version, including the addition of specular reflections and the separation of the scene code from the raytracing from the rendering.
Note that this code has a significant amount of refactoring relative to the C version, including the addition of specular reflections and the separation of the scene code from the raytracing from the rendering.
<lang tcl>package require Tcl 8.5
<syntaxhighlight lang="tcl">package require Tcl 8.5


proc normalize vec {
proc normalize vec {
Line 782: Line 2,713:
}
}
}
}
textDeathStar 3 10 0.7 0.3</lang>
textDeathStar 3 10 0.7 0.3</syntaxhighlight>
Output:
Output:
<pre>
<pre>
Line 829: Line 2,760:
{{libheader|Tk}}
{{libheader|Tk}}
[[File:Deathstar-tcl.gif|200px|thumb|Rendering of the Death Star by the Tcl solution.]]
[[File:Deathstar-tcl.gif|200px|thumb|Rendering of the Death Star by the Tcl solution.]]
<lang tcl># Render as a picture (with many hard-coded settings)
<syntaxhighlight lang="tcl"># Render as a picture (with many hard-coded settings)
package require Tk
package require Tk
proc guiDeathStar {photo diff spec lightBrightness ambient} {
proc guiDeathStar {photo diff spec lightBrightness ambient} {
Line 846: Line 2,777:
}
}
pack [label .l -image [image create photo ds]]
pack [label .l -image [image create photo ds]]
guiDeathStar ds 3 10 0.7 0.3</lang>
guiDeathStar ds 3 10 0.7 0.3</syntaxhighlight>


=={{header|VBScript}}==
{{omit from|AWK|Does not have this functionality in the language}}
ASCII graphics. Should be invoked with cscript. Modified from LUA
{{omit from|Lotus 123 Macro Scripting}}
<syntaxhighlight lang="vb">
{{omit from|ML/I}}
'deathstar ascii graphics
{{omit from|Retro}}

option explicit

const x_=0
const y_=1
const z_=2
const r_=3

function clamp(x,b,t)
if x<b then
clamp=b
elseif x>t then
clamp =t
else
clamp=x
end if
end function

function dot(v,w) dot=v(x_)*w(x_)+v(y_)*w(y_)+v(z_)*w(z_): end function

function normal (byval v)
dim ilen:ilen=1/sqr(dot(v,v)):
v(x_)=v(x_)*ilen: v(y_)=v(y_)*ilen: v(z_)=v(z_)*ilen:
normal=v:
end function

function hittest(s,x,y)
dim z
z = s(r_)^2 - (x-s(x_))^2 - (y-s(y_))^2
if z>=0 then
z=sqr(z)
hittest=array(s(z_)-z,s(z_)+z)
else
hittest=0
end if
end function
sub deathstar(pos, neg, sun, k, amb)
dim x,y,shades,result,shade,hp,hn,xx,b
shades=array(" ",".",":","!","*","o","e","&","#","%","@")
for y = pos(y_)-pos(r_)-0.5 to pos(y_)+pos(r_)+0.5
for x = pos(x_)-pos(r_)-0.5 to pos(x_)+pos(r_)+.5
hp=hittest (pos, x, y)
hn=hittest(neg,x,y)
if not isarray(hp) then
result=0
elseif not isarray(hn) then
result=1
elseif hn(0)>hp(0) then
result=1
elseif hn(1)>hp(1) then
result=0
elseif hn(1)>hp(0) then
result=2
else
result=1
end if

shade=-1
select case result
case 0
shade=0
case 1
xx=normal(array(x-pos(x_),y-pos(y_),hp(0)-pos(z_)))
'shade=clamp(1-dot(sun,xx)^k+amb,1,ubound(shades))
case 2
xx=normal(array(neg(x_)-x,neg(y_)-y,neg(z_)-hn(1)))
'shade=clamp(1-dot(sun,xx)^k+amb,1,ubound(shades))
end select
if shade <>0 then
b=dot(sun,xx)^k+amb
shade=clamp((1-b) *ubound(shades),1,ubound(shades))
end if
wscript.stdout.write string(2,shades(shade))
next
wscript.stdout.write vbcrlf
next
end sub

deathstar array(20, 20, 0, 20),array(10,10,-15,10), normal(array(-2,1,3)), 2, 0.1
</syntaxhighlight>
{{out}}
<pre>
####&&&&&&&&&&&&
%%######&&&&eeeeeeeeooooooooee&&
%%%%####&&&&eeeeeeoooooo************ooee
%%%%####%%%%%%eeoooooo******!!!!!!!!!!!!**oo
%%%%ee&&&&####%%%%%%##oo****!!!!!!!!::::::::!!!!**oo
%%%%ooooeeee&&####%%%%%%##**!!!!!!::::::::::::::::!!!!oo
%%%%!!****ooee&&&&##%%%%%%##!!!!::::::::............::::!!**
%%%%::::!!****ooee&&####%%%%%%&&!!::::....................::!!oo
%%....::::!!**ooooee&&##%%%%%%##::::........................::!!
%%........::::!!**ooee&&####%%%%##::::..........................::!!
##%%..........::!!**ooee&&&&##%%%%##::..............................::oo
%%%%..........::!!!!**ooee&&##%%%%::::..............................::!!
##%%..............::!!**ooee&&##%%%%::::................................::oo
##%%..............::!!**ooee&&##%%%%::::................................::**
%%%%............::::!!**oo&&&&##%%!!::::................................::!!
%%%%............::!!**ooee&&##%%!!!!::::..................................!!
##%%%%%%........::::!!**ooee&&##**!!!!::::..................................::**
##%%%%%%!!::::::!!!!**ooee&&##****!!!!::::..................................::**
##%%%%%%%%**********ooee&&##oo****!!!!!!::::................................::**
##%%%%%%%%%%##eeeeee&&eeeeeeoooo****!!!!::::..............................::!!**
##%%%%%%%%%%######&&&&&&eeeeoooo****!!!!::::::............................::!!**
##%%%%%%%%%%%%######&&&&eeeeoooo******!!!!::::::..........................::!!oo
&&##%%%%%%%%%%######&&&&eeeeeeoooo****!!!!!!::::::......................::::!!oo
&&##%%%%%%%%%%######&&&&&&eeeeoooooo****!!!!!!::::::..................::::!!**ee
##%%%%%%%%%%%%######&&&&eeeeeeoooo******!!!!!!::::::::..........::::::!!!!**
##%%%%%%%%%%%%######&&&&&&eeeeeeoooo******!!!!!!::::::::::::::::::::!!!!**oo
&&##%%%%%%%%%%%%######&&&&&&eeeeoooooo******!!!!!!!!::::::::::::!!!!!!**ooee
ee##%%%%%%%%%%%%########&&&&eeeeeeoooooo********!!!!!!!!!!!!!!!!!!!!****oo&&
&&##%%%%%%%%%%%%######&&&&&&eeeeeeoooooo**********!!!!!!!!!!!!******ooee
ee##%%%%%%%%%%%%%%######&&&&&&eeeeeeoooooooo********************ooooee&&
&&##%%%%%%%%%%%%########&&&&&&&&eeeeeeoooooooooo********ooooooooee&&
####%%%%%%%%%%%%########&&&&&&&&eeeeeeeeooooooooooooooooooeeee&&
ee##%%%%%%%%%%%%%%##########&&&&&&&&eeeeeeeeeeeeeeeeeeeeeeee&&##
&&##%%%%%%%%%%%%%%%%########&&&&&&&&&&eeeeeeeeeeeeee&&&&&&##
&&##%%%%%%%%%%%%%%%%##########&&&&&&&&&&&&&&&&&&&&&&####
&&##%%%%%%%%%%%%%%%%%%##############&&&&&&&&######%%
####%%%%%%%%%%%%%%%%%%######################
&&##%%%%%%%%%%%%%%%%%%%%%%%%######%%%%%%
&&##%%%%%%%%%%%%%%%%%%%%%%%%%%%%
##%%%%%%%%%%%%%%
</pre>

=={{header|Wren}}==
{{trans|Go}}
{{libheader|DOME}}
<syntaxhighlight lang="wren">import "dome" for Window
import "graphics" for Canvas, Color, ImageData
import "math" for Vector

var Normalize = Fn.new{ |vec|
var invLen = 1 / vec.dot(vec).sqrt
vec.x = vec.x * invLen
vec.y = vec.y * invLen
vec.z = vec.z * invLen
}

class Sphere {
construct new(cx, cy, cz, r) {
_cx = cx
_cy = cy
_cz = cz
_r = r
}

cx { _cx }
cy { _cy }
cz { _cz }
r { _r }

hit(x, y) {
x = x - _cx
y = y - _cy
var zsq = _r*_r - x*x - y*y
if (zsq >= 0) {
var zsqrt = zsq.sqrt
return [_cz - zsqrt, _cz + zsqrt, true]
}
return [0, 0, false]
}
}

class DeathStar {
construct new(width, height) {
Window.title = "Death star"
Window.resize(width, height)
Canvas.resize(width, height)
}

init() {
Canvas.cls(Color.white)
var dir = Vector.new(20, -40, 10)
Normalize.call(dir)
var pos = Sphere.new(220, 190, 220, 120)
var neg = Sphere.new(130, 100, 190, 100)
deathStar(pos, neg, 1.5, 0.2, dir)
}

deathStar(pos, neg, k, amb, dir) {
var w = pos.r * 4
var h = pos.r * 3
var img = ImageData.create("deathStar", w, h)
var vec = Vector.new(0, 0, 0)
for (y in pos.cy - pos.r..pos.cy + pos.r) {
for (x in pos.cx - pos.r..pos.cx + pos.r) {
var res = pos.hit(x, y)
var zb1 = res[0]
var zb2 = res[1]
var hit = res[2]
if (!hit) continue
res = neg.hit(x, y)
var zs1 = res[0]
var zs2 = res[1]
hit = res[2]
if (hit) {
if (zs1 > zb1) {
hit = false
} else if (zs2 > zb2) {
continue
}
}
if (hit) {
vec.x = neg.cx - x
vec.y = neg.cy - y
vec.z = neg.cz - zs2
} else {
vec.x = x - pos.cx
vec.y = y - pos.cy
vec.z = zb1 - pos.cz
}
Normalize.call(vec)
var s = dir.dot(vec)
if (s < 0) s = 0
var lum = 255 * (s.pow(k) + amb) / (1 + amb)
lum = lum.clamp(0, 255)
img.pset(x, y, Color.rgb(lum, lum, lum))
}
}
img.draw(pos.cx - w/2, pos.cy - h/2)
img.saveToFile("deathStar.png")
}

update() {
}

draw(alpha) {
}
}

var Game = DeathStar.new(400, 400)</syntaxhighlight>

=={{header|Yabasic}}==
<syntaxhighlight lang="yabasic">open window 100,100
window origin "cc"
backcolor 0,0,0
clear window

tonos = 100
interv = int(255 / tonos)
dim shades(tonos)

shades(1) = 255
for i = 2 to tonos
shades(i) = shades(i-1) - interv
next i

dim light(3)

light(0) = 30
light(1) = 30
light(2) = -50


sub normalize(v())
local long
long = sqrt(v(0)*v(0) + v(1)*v(1) + v(2)*v(2))
v(0) = v(0) / long
v(1) = v(1) / long
v(2) = v(2) / long
end sub

sub punto(x(), y())
local d
d = x(0)*y(0) + x(1)*y(1) + x(2)*y(2)
if d < 0 then
return -d
else
return 0
end if
end sub


//* positive shpere and negative sphere */
dim pos(3)
dim neg(3)

// x, y, z, r

pos(0) = 10
pos(1) = 10
pos(2) = 0
pos(3) = 20

neg(0) = 0
neg(1) = 0
neg(2) = -5
neg(3) = 15


sub hit_sphere(sph(), x, y)
local zsq
x = x - sph(0)
y = y - sph(1)
zsq = sph(3) * sph(3) - (x * x + y * y)
if (zsq < 0) then
return 0
else
return sqrt(zsq)
end if
end sub

sub draw_sphere(k, ambient)
local i, j, intensity, hit_result, result, b, vec(3), x, y, zb1, zb2, zs1, zs2, ini1, fin1, ini2, fin2
ini1 = int(pos(1) - pos(3))
fin1 = int(pos(1) + pos(3) + .5)
for i = ini1 to fin1
y = i + .5
ini2 = int(pos(0) - 2 * pos(3))
fin2 = int(pos(0) + 2 * pos(3) + .5)
for j = ini2 to fin2
x = (j - pos(0)) / 2 + .5 + pos(0)
// ray lands in blank space, draw bg
result = hit_sphere(pos(), x, y)
if not result then
hit_result = 0

//* ray hits pos sphere but not neg, draw pos sphere surface */
else
zb1 = pos(2) - result
zb2 = pos(2) + result
result = hit_sphere(neg(), x, y)
if not result then
hit_result = 1
else
zs1 = neg(2) - result
zs2 = neg(2) + result
if (zs1 > zb1) then
hit_result = 1
elseif (zs2 > zb2) then
hit_result = 0
elseif (zs2 > zb1) then
hit_result = 2
else
hit_result = 1
end if
end if
end if
if not hit_result then
color 0,0,0
dot x, y
else
switch(hit_result)
case 1:
vec(0) = x - pos(0)
vec(1) = y - pos(1)
vec(2) = zb1 - pos(2)
break
default:
vec(0) = neg(0) - x
vec(1) = neg(1) - y
vec(2) = neg(2) - zs2
end switch
normalize(vec())
b = (punto(light(), vec())^k) + ambient
intensity = (1 - b) * tonos
if (intensity < 1) intensity = 1
if (intensity > tonos) intensity = tonos
color shades(intensity),shades(intensity),shades(intensity)
dot x,y
end if
next j
next i
end sub
ang = 0
while(true)
//clear window
light(1) = cos(ang * 2)
light(2) = cos(ang)
light(0) = sin(ang)
normalize(light())
ang = ang + .05

draw_sphere(2, .3)
wend
</syntaxhighlight>
=={{header|Zig}}==
{{trans|C}}
Primitive ray tracing. Writes a PGM to stdout.
<syntaxhighlight lang="zig">
const std = @import("std");
const Allocator = std.mem.Allocator;
</syntaxhighlight>
<syntaxhighlight lang="zig">pub fn main() !void {
// buffer stdout --------------------------------------
const stdout_file = std.io.getStdOut().writer();
var bw = std.io.bufferedWriter(stdout_file);
const stdout = bw.writer();

// allocator ------------------------------------------
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer {
const ok = gpa.deinit();
std.debug.assert(ok == .ok);
}
const allocator = gpa.allocator();

// deathstar ------------------------------------------
var dstar = try DeathStar(f32).init(allocator);
defer dstar.deinit();

// print deathstar PGM to stdout ----------------------
const comments = [_][]const u8{
"Rosetta Code",
"DeathStar",
"https://rosettacode.org/wiki/Death_Star",
};
try dstar.print(stdout, comments[0..]);

// ----------------------------------------------------
try bw.flush();
}</syntaxhighlight>
<syntaxhighlight lang="zig">fn Vector(comptime T: type) type {
return struct {
const Self = @This();
x: T,
y: T,
z: T,

pub fn init(x: T, y: T, z: T) Self {
return Self{ .x = x, .y = y, .z = z };
}
pub fn zero() Self {
return Self{ .x = 0.0, .y = 0.0, .z = 0.0 };
}
fn dot(a: *const Self, b: *const Self) T {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
fn length(self: *const Self) T {
return std.math.sqrt(self.dot(self));
}
pub fn normalize(self: *Self) void {
const inv_length = 1 / self.length();
self.*.x *= inv_length;
self.*.y *= inv_length;
self.*.z *= inv_length;
}
};
}</syntaxhighlight>
<syntaxhighlight lang="zig">
fn SphereHit(comptime T: type) type {
return struct { z1: T, z2: T };
}</syntaxhighlight>
<syntaxhighlight lang="zig">
fn Sphere(comptime T: type) type {
return struct {
const Self = @This();
cx: T,
cy: T,
cz: T,
r: T,

pub fn init(cx: T, cy: T, cz: T, r: T) Self {
return Self{ .cx = cx, .cy = cy, .cz = cz, .r = r };
}
/// Check if a ray (x,y, -inf)->(x, y, inf) hits a sphere.
/// If so, return the intersecting z values. z1 is closer to the eye.
pub fn hit(self: *const Self, xx: T, yy: T) ?SphereHit(T) {
const x = xx - self.cx;
const y = yy - self.cy;
const zsq = self.r * self.r - x * x - y * y;
if (zsq >= 0) {
const zsqrt = std.math.sqrt(zsq);
return .{ .z1 = self.cz - zsqrt, .z2 = self.cz + zsqrt };
}
return null;
}
};
}</syntaxhighlight>
<syntaxhighlight lang="zig">
fn DeathStar(comptime T: type) type {
return struct {
const Self = @This();
allocator: Allocator,
w: usize,
h: usize,
img: ImageData(),

const Hit = enum { background, neg, pos };

pub fn init(allocator: Allocator) !Self {
var dir = Vector(T).init(20, -40, 10);
dir.normalize();
// positive sphere and negative sphere
const pos = Sphere(T).init(180, 240, 220, 120);
const neg = Sphere(T).init(60, 150, 100, 100);

const k: T = 1.5;
const amb: T = 0.2;

const w: usize = @intFromFloat(pos.r * 4);
const h: usize = @intFromFloat(pos.r * 3);
var img = try ImageData().init(allocator, "deathStar", w, h);

var vec = Vector(T).zero();

const start_y: usize = @intFromFloat(pos.cy - pos.r);
const end_y: usize = @intFromFloat(pos.cy + pos.r);
const start_x: usize = @intFromFloat(pos.cx - pos.r);
const end_x: usize = @intFromFloat(pos.cx + pos.r);

for (start_y..end_y + 1) |j| {
for (start_x..end_x + 1) |i| {
const x: T = @floatFromInt(i);
const y: T = @floatFromInt(j);

const result_pos = pos.hit(x, y);
// ray lands in blank space, show bg
if (result_pos == null)
continue;

const zb1 = result_pos.?.z1;
const zb2 = result_pos.?.z2;

const result_neg = neg.hit(x, y);

switch (calcHit(result_neg, zb1, zb2)) {
.background => continue,
.neg => {
vec.x = neg.cx - x;
vec.y = neg.cy - y;
vec.z = neg.cz - result_neg.?.z2; // zs2
},
.pos => {
vec.x = x - pos.cx;
vec.y = y - pos.cy;
vec.z = zb1 - pos.cz;
},
}
vec.normalize();
var s = dir.dot(&vec);
if (s < 0) s = 0;
const lum = 255 * (std.math.pow(T, s, k) + amb) / (1 + amb);
const lumi: u8 = @intFromFloat(std.math.clamp(lum, 0, 255));
img.pset(i, j, Gray{ .w = lumi });
}
}
return Self{ .allocator = allocator, .w = w, .h = h, .img = img };
}
pub fn deinit(self: *Self) void {
self.img.deinit();
}
pub fn print(self: *Self, writer: anytype, optional_comments: ?[]const []const u8) !void {
try self.img.print(writer, optional_comments);
}
/// Ray has hit the positive sphere.
/// How does it intersect the negative sphere ?
fn calcHit(neg_hit: ?SphereHit(T), zb1: T, zb2: T) Hit {
if (neg_hit) |result| {
const zs1 = result.z1;
const zs2 = result.z2;
if (zs1 > zb1) {
// ray hits both, but pos front surface is closer
return Hit.pos;
} else if (zs2 > zb2) {
// pos sphere surface is inside neg sphere, show bg
return Hit.background;
} else if (zs2 > zb1) {
// back surface on neg sphere is inside pos sphere,
// the only place where neg sphere surface will be shown
return Hit.neg;
} else {
return Hit.pos;
}
} else {
// ray hits pos sphere but not neg, draw pos sphere surface
return Hit.pos;
}
}
};
}</syntaxhighlight>
<syntaxhighlight lang="zig">
const Gray = struct {
w: u8,
const black = Gray{ .w = 0 };
};</syntaxhighlight>
<syntaxhighlight lang="zig">
fn ImageData() type {
return struct {
const Self = @This();
allocator: Allocator,
name: []const u8,
w: usize,
h: usize,
image: []Gray,

pub fn init(allocator: Allocator, name: []const u8, w: usize, h: usize) !Self {
const image = try allocator.alloc(Gray, h * w);
// black background fill
for (image) |*pixel| pixel.* = Gray.black;
return Self{ .allocator = allocator, .image = image, .name = name, .w = w, .h = h };
}
pub fn deinit(self: *Self) void {
self.allocator.free(self.image);
}
pub fn pset(self: *Self, x: usize, y: usize, gray: Gray) void {
self.image[x * self.w + y] = gray;
}
/// Write PGM P2 ASCII to 'writer'
pub fn print(self: *const Self, writer: anytype, optional_comments: ?[]const []const u8) !void {
try writer.print("P2\n", .{});

if (optional_comments) |lines| {
for (lines) |line|
try writer.print("# {s}\n", .{line});
}

try writer.print("{d} {d}\n{d}\n", .{ self.w, self.h, 255 });

for (self.image, 0..) |pixel, i| {
const sep = if (i % self.w == self.w - 1) "\n" else " ";
try writer.print("{d}{s}", .{ pixel.w, sep });
}
}
};
}</syntaxhighlight>

Revision as of 11:25, 28 April 2024

Task
Death Star
You are encouraged to solve this task according to the task description, using any language you may know.
Task

Display a region that consists of a large sphere with part of a smaller sphere removed from it as a result of geometric subtraction.

(This will basically produce a shape like a "death star".)


Related tasks



11l

Translation of: Python
T Sphere
   Float cx, cy, cz, r
   F (cx, cy, cz, r)
      .cx = cx
      .cy = cy
      .cz = cz
      .r = r

F dotp(v1, v2)
   V d = dot(v1, v2)
   R I d < 0 {-d} E 0.0

F hit_sphere(sph, x0, y0)
   V x = x0 - sph.cx
   V y = y0 - sph.cy
   V zsq = sph.r ^ 2 - (x ^ 2 + y ^ 2)
   I zsq < 0
      R (0B, 0.0, 0.0)
   V szsq = sqrt(zsq)
   R (1B, sph.cz - szsq, sph.cz + szsq)

F draw_sphere(k, ambient, light)
   V shades = ‘.:!*oe&#%@’
   V pos = Sphere(20.0, 20.0, 0.0, 20.0)
   V neg = Sphere(1.0, 1.0, -6.0, 20.0)

   L(i) Int(floor(pos.cy - pos.r)) .< Int(ceil(pos.cy + pos.r) + 1)
      V y = i + 0.5
      L(j) Int(floor(pos.cx - 2 * pos.r)) .< Int(ceil(pos.cx + 2 * pos.r) + 1)
         V x = (j - pos.cx) / 2.0 + 0.5 + pos.cx

         V (h, zb1, zb2) = hit_sphere(pos, x, y)
         Int hit_result
         Float zs2
         I !h
            hit_result = 0
         E
            (h, V zs1, zs2) = hit_sphere(neg, x, y)
            I !h
               hit_result = 1
            E I zs1 > zb1
               hit_result = 1
            E I zs2 > zb2
               hit_result = 0
            E I zs2 > zb1
               hit_result = 2
            E
               hit_result = 1

         V vec = (0.0, 0.0, 0.0)
         I hit_result == 0
            print(‘ ’, end' ‘’)
            L.continue
         E I hit_result == 1
            vec = (x - pos.cx, y - pos.cy, zb1 - pos.cz)
         E I hit_result == 2
            vec = (neg.cx - x, neg.cy - y, neg.cz - zs2)
         vec = normalize(vec)

         V b = dotp(light, vec) ^ k + ambient
         V intensity = Int((1 - b) * shades.len)
         intensity = min(shades.len, max(0, intensity))
         print(shades[intensity], end' ‘’)
      print()

V light = normalize((-50.0, 30.0, 50.0))
draw_sphere(2, 0.5, light)
Output:
                                    eeeee:::::::                                 
                                eeeeeeeee..............                          
                             ooeeeeeeeeee..................                      
                           ooooeeeeeeeee......................                   
                        oooooooeeeeeeee..........................                
                      ooooooooooeeeee..............................              
                    **ooooooooooeeee.................................            
                  ****ooooooooooee.....................................          
                !*****ooooooooooe.......................................         
              !!!*****ooooooooo:..........................................       
            :!!!!*****ooooooo:::...........................................      
          :::!!!!*****ooooo!:::::...........................................     
        ::::!!!!!*****ooo!!!!::::............................................    
       .::::!!!!*****oo*!!!!!::::............................................    
     ...::::!!!!*********!!!!:::::............................................   
    ...::::!!!!****o*****!!!!!::::............................................   
  ....::::!!!!***ooo******!!!!!::::............................................  
 ....::::!!!!*ooooooo*****!!!!!:::::...........................................  
...::::!!!!!oooooooooo*****!!!!!:::::..........................................  
:::::!!!!eeooooooooooo******!!!!!:::::.........................................  
!!!!!eeeeeeeooooooooooo******!!!!!:::::........................................  
eeeeeeeeeeeeoooooooooooo******!!!!!:::::.......................................  
eeeeeeeeeeeeeoooooooooooo******!!!!!!:::::.....................................  
eeeeeeeeeeeeeeoooooooooooo******!!!!!!:::::....................................  
 eeeeeeeeeeeeeeoooooooooooo*******!!!!!!:::::.................................   
 eeeeeeeeeeeeeeeooooooooooooo******!!!!!!::::::..............................:   
  eeeeeeeeeeeeeeeooooooooooooo*******!!!!!!:::::::..........................:    
  eeeeeeeeeeeeeeeeoooooooooooooo*******!!!!!!!:::::::.....................::!    
   eeeeeeeeeeeeeeeeeooooooooooooo********!!!!!!!:::::::::..............::::!     
    eeeeeeeeeeeeeeeeeoooooooooooooo********!!!!!!!!::::::::::::::::::::::!*      
     eeeeeeeeeeeeeeeeeeooooooooooooooo********!!!!!!!!!!:::::::::::::!!!!*       
       eeeeeeeeeeeeeeeeeoooooooooooooooo**********!!!!!!!!!!!!!!!!!!!!!*         
        eeeeeeeeeeeeeeeeeeooooooooooooooooo************!!!!!!!!!!!!****          
          eeeeeeeeeeeeeeeeeeoooooooooooooooooo**********************o            
            eeeeeeeeeeeeeeeeeeeooooooooooooooooooooo************ooo              
              eeeeeeeeeeeeeeeeeeeeooooooooooooooooooooooooooooooo                
                 eeeeeeeeeeeeeeeeeeeeooooooooooooooooooooooooo                   
                    eeeeeeeeeeeeeeeeeeeeeoooooooooooooooooo                      
                        eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee                          
                               eeeeeeeeeeeeeeeee                                 

Ada

Library: SDLAda
Translation of: Go
with Ada.Numerics.Elementary_Functions;
with Ada.Numerics.Generic_Real_Arrays;

with SDL.Video.Windows.Makers;
with SDL.Video.Renderers.Makers;
with SDL.Video.Palettes;
with SDL.Events.Events;

procedure Death_Star is

   Width   : constant := 400;
   Height  : constant := 400;

   package Float_Arrays is
      new Ada.Numerics.Generic_Real_Arrays (Float);
   use Ada.Numerics.Elementary_Functions;
   use Float_Arrays;

   Window   : SDL.Video.Windows.Window;
   Renderer : SDL.Video.Renderers.Renderer;

   subtype Vector_3 is Real_Vector (1 .. 3);

   type Sphere_Type is record
      Cx, Cy, Cz : Integer;
      R          : Integer;
   end record;

   function Normalize (V : Vector_3) return Vector_3 is
      (V / Sqrt (V * V));

   procedure Hit (S      :     Sphere_Type;
                  X, Y   :     Integer;
                  Z1, Z2 : out Float;
                  Is_Hit : out Boolean)
   is
      NX    : constant Integer := X - S.Cx;
      NY    : constant Integer := Y - S.Cy;
      Zsq   : constant Integer := S.R * S.R - (NX * NX + NY * NY);
      Zsqrt : Float;
   begin
      if Zsq >= 0 then
         Zsqrt  := Sqrt (Float (Zsq));
         Z1     := Float (S.Cz) - Zsqrt;
         Z2     := Float (S.Cz) + Zsqrt;
         Is_Hit := True;
         return;
      end if;
      Z1     := 0.0;
      Z2     := 0.0;
      Is_Hit := False;
   end Hit;

   procedure Draw_Death_Star (Pos, Neg : Sphere_Type;
                              K, Amb   : Float;
                              Dir      : Vector_3)
   is
      Vec      : Vector_3;
      ZB1, ZB2 : Float;
      ZS1, ZS2 : Float;
      Is_Hit   : Boolean;
      S        : Float;
      Lum      : Integer;
   begin
      for Y in Pos.Cy - Pos.R .. Pos.Cy + Pos.R loop
         for X in Pos.Cx - Pos.R .. Pos.Cx + Pos.R loop
            Hit (Pos, X, Y, ZB1, ZB2, Is_Hit);
            if not Is_Hit then
               goto Continue;
            end if;
            Hit (Neg, X, Y, ZS1, ZS2, Is_Hit);
            if Is_Hit then
               if ZS1 > ZB1 then
                  Is_Hit := False;
               elsif ZS2 > ZB2 then
                  goto Continue;
               end if;
            end if;

            if Is_Hit then
               Vec := (Float (Neg.Cx - X),
                       Float (Neg.Cy - Y),
                       Float (Neg.Cz) - ZS2);
            else
               Vec := (Float (X - Pos.Cx),
                       Float (Y - Pos.Cy),
                       ZB1 - Float (Pos.Cz));
            end if;
            S := Float'Max (0.0, Dir * Normalize (Vec));

            Lum := Integer (255.0 * (S ** K + Amb) / (1.0 + Amb));
            Lum := Integer'Max (0, Lum);
            Lum := Integer'Min (Lum, 255);

            Renderer.Set_Draw_Colour ((SDL.Video.Palettes.Colour_Component (Lum),
                                       SDL.Video.Palettes.Colour_Component (Lum),
                                       SDL.Video.Palettes.Colour_Component (Lum),
                                       255));
            Renderer.Draw (Point => (SDL.C.int (X + Width  / 2),
                                     SDL.C.int (Y + Height / 2)));
            <<Continue>>
         end loop;
      end loop;
   end Draw_Death_Star;

   procedure Wait is
      use type SDL.Events.Event_Types;
      Event : SDL.Events.Events.Events;
   begin
      loop
         while SDL.Events.Events.Poll (Event) loop
            if Event.Common.Event_Type = SDL.Events.Quit then
               return;
            end if;
         end loop;
         delay 0.100;
      end loop;
   end Wait;

   Direction : constant Vector_3    := Normalize ((20.0, -40.0, -10.0));
   Positive  : constant Sphere_Type := (0, 0, 0, 120);
   Negative  : constant Sphere_Type := (-90, -90, -30, 100);
begin
   if not SDL.Initialise (Flags => SDL.Enable_Screen) then
      return;
   end if;

   SDL.Video.Windows.Makers.Create (Win      => Window,
                                    Title    => "Death star",
                                    Position => SDL.Natural_Coordinates'(X => 10, Y => 10),
                                    Size     => SDL.Positive_Sizes'(Width, Height),
                                    Flags    => 0);
   SDL.Video.Renderers.Makers.Create (Renderer, Window.Get_Surface);
   Renderer.Set_Draw_Colour ((0, 0, 0, 255));
   Renderer.Fill (Rectangle => (0, 0, Width, Height));

   Draw_Death_Star (Positive, Negative, 1.5, 0.2, Direction);
   Window.Update_Surface;

   Wait;
   Window.Finalize;
   SDL.Finalise;
end Death_Star;

ALGOL 68

Translation of: C
Translation of: 11l
BEGIN # draw a "Death Star" - translated from the C and 11l samples #
    STRING shades = ".:!*oe&#%@";

    PROC normalize = ( []REAL v )[]REAL:
         BEGIN
            REAL len = sqrt( v[ 1 ] * v[ 1 ] + v[ 2 ] * v[ 2 ] + v[ 3 ] * v[ 3 ] );
            ( v[ 1 ] / len, v[ 2 ] / len, v[ 3 ] / len )
         END # normalize # ;

    PROC dot = ( []REAL x, y )REAL:
         BEGIN
            REAL d = x[ 1 ] * y[ 1 ] + x[ 2 ] * y[ 2 ] + x[ 3 ] * y[ 3 ];
            IF d < 0 THEN - d ELSE 0 FI
         END # dot # ;

    MODE SPHERE = STRUCT( REAL cx, cy, cz, r );

    # positive shpere and negative sphere #
    SPHERE pos = ( 20, 20, 0, 20 ), neg = ( 1, 1, -6, 20 );

    # check if a ray (x,y, -inf)->(x, y, inf) hits a sphere; if so, return #
    # the intersecting z values.  z1 is closer to the eye                  #
    PROC hit_sphere = ( SPHERE sph, REAL x in, y in, REF REAL z1, z2 )BOOL:
         IF   REAL x    = x in - cx OF sph;
              REAL y    = y in - cy OF sph;
              REAL zsq := r OF sph * r OF sph - ( x * x + y * y );
              zsq < 0
         THEN FALSE
         ELSE zsq := sqrt( zsq );
              z1  := cz OF sph - zsq;
              z2  := cz OF sph + zsq;
              TRUE
         FI # hit_sphere # ;

    PROC draw_sphere = ( REAL k, ambient, []REAL light )VOID:
         FOR i FROM ENTIER ( cy OF pos - r OF pos ) TO ENTIER ( cy OF pos + r OF pos ) + 1 DO
             REAL y := i + 0.5;
             FOR j FROM ENTIER ( cx OF pos - 2 * r OF pos ) TO ENTIER (cx OF pos + 2 * r OF pos ) + 1 DO
                 REAL x := ( j - cx OF pos ) / 2.0 + 0.5 + cx OF pos;
                 REAL zb1 := 0, zb2 := 0, zs1 := 0, zs2 := 0;
                 INT hit_result
                         = IF   NOT hit_sphere( pos, x, y, zb1, zb2 ) THEN
                               0   # ray lands in blank space, draw bg #
                           ELIF NOT hit_sphere( neg, x, y,  zs1,  zs2 ) THEN
                               1   # ray hits pos sphere but not neg, draw pos sphere surface #
                           ELIF zs1 > zb1 THEN
                               1   # ray hits both, but pos front surface is closer #
                           ELIF zs2 > zb2 THEN
                               0   # pos sphere surface is inside neg sphere, show bg #
                           ELIF zs2 > zb1 THEN
                               2   # back surface on neg sphere is inside pos sphere,      #
                                   # the only place where neg sphere surface will be shown #
                           ELSE
                               1   # show the pos sphere #
                           FI;
                 IF hit_result = 0 THEN
                     print( ( " " ) )
                 ELSE
                     []REAL vec =
                         normalize( IF hit_result = 1
                                    THEN []REAL( x   - cx OF pos
                                               , y   - cy OF pos
                                               , zb1 - cz OF pos
                                               )
                                    ELSE []REAL( cx OF neg - x
                                               , cy OF neg - y
                                               , cz OF neg - zs2
                                               )
                                    FI
                                  );
                     REAL b          = ( dot( light, vec ) ^ k ) + ambient;
                     INT  intensity := ENTIER ( ( 1 - b ) * ( ( UPB shades - LWB shades ) + 1 ) ) + 1;
                     IF   intensity < LWB shades THEN intensity := LWB shades
                     ELIF intensity > UPB shades THEN intensity := UPB shades
                     FI;
                     print( ( shades[ intensity ] ) )
                 FI
             OD;
             print( ( newline ) )
         OD # draw_sphere # ;

    BEGIN
        []REAL light = ( -50, 30, 50 );
        draw_sphere( 2, 0.5, normalize( light ) )
    END
END
Output:

Same as 11l

AutoHotkey

Library: GDIP
#NoEnv
SetBatchLines, -1
#SingleInstance, Force

; Uncomment if Gdip.ahk is not in your standard library
#Include, Gdip.ahk

; Settings
X := 200, Y := 200, Width := 200, Height := 200 ; Location and size of sphere
rotation := 60 ; degrees
ARGB := 0xFFFF0000 ; Color=Solid Red

If !pToken := Gdip_Startup() ; Start gdi+
{
	MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
	ExitApp
}
OnExit, Exit

Gui, -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs ; Create GUI
Gui, Show, NA ; Show GUI
hwnd1 := WinExist() ; Get a handle to this window we have created in order to update it later
hbm := CreateDIBSection(A_ScreenWidth, A_ScreenHeight) ; Create a gdi bitmap drawing area
hdc := CreateCompatibleDC() ; Get a device context compatible with the screen
obm := SelectObject(hdc, hbm) ; Select the bitmap into the device context
pGraphics := Gdip_GraphicsFromHDC(hdc) ; Get a pointer to the graphics of the bitmap, for use with drawing functions
Gdip_SetSmoothingMode(pGraphics, 4) ; Set the smoothing mode to antialias = 4 to make shapes appear smother

Gdip_TranslateWorldTransform(pGraphics, X, Y)
Gdip_RotateWorldTransform(pGraphics, rotation)

; Base ellipse
pBrush := Gdip_CreateLineBrushFromRect(0, 0, Width, Height, ARGB, 0xFF000000)
Gdip_FillEllipse(pGraphics, pBrush, 0, 0, Width, Height)

; First highlight ellipse
pBrush := Gdip_CreateLineBrushFromRect(Width*0.1, Height*0.01, Width*0.8, Height*0.6, 0x33FFFFFF, 0x00FFFFFF)
Gdip_FillEllipse(pGraphics, pBrush, Width*0.1, Height*0.01, Width*0.8, Height*0.6)

; Second highlight ellipse
pBrush := Gdip_CreateLineBrushFromRect(Width*0.3, Height*0.02, Width*0.3, Height*0.2, 0xBBFFFFFF, 0x00FFFFFF)
Gdip_FillEllipse(pGraphics, pBrush, Width*0.3, Height*0.02, Width*0.3, Height*0.2)


; Reset variables for smaller subtracted sphere
X-=150
Y-=10
Width*=0.5
Height*=0.4
rotation-=180

Gdip_TranslateWorldTransform(pGraphics, X, Y)
Gdip_RotateWorldTransform(pGraphics, rotation)

; Base ellipse
pBrush := Gdip_CreateLineBrushFromRect(0, 0, Width, Height, ARGB, 0xFF000000)
Gdip_FillEllipse(pGraphics, pBrush, 0, 0, Width, Height)

; First highlight ellipse
pBrush := Gdip_CreateLineBrushFromRect(Width*0.1, Height*0.01, Width*0.8, Height*0.6, 0x33FFFFFF, 0x00FFFFFF)
Gdip_FillEllipse(pGraphics, pBrush, Width*0.1, Height*0.01, Width*0.8, Height*0.6)

; Second highlight ellipse
pBrush := Gdip_CreateLineBrushFromRect(Width*0.3, Height*0.02, Width*0.3, Height*0.2, 0xBBFFFFFF, 0x00FFFFFF)
Gdip_FillEllipse(pGraphics, pBrush, Width*0.3, Height*0.02, Width*0.3, Height*0.2)


UpdateLayeredWindow(hwnd1, hdc, 0, 0, A_ScreenWidth, A_ScreenHeight)
SelectObject(hdc, obm) ; Select the object back into the hdc
Gdip_DeletePath(Path)
Gdip_DeleteBrush(pBrush)
DeleteObject(hbm) ; Now the bitmap may be deleted
DeleteDC(hdc) ; Also the device context related to the bitmap may be deleted
Gdip_DeleteGraphics(G) ; The graphics may now be deleted
Return

Exit:
; gdi+ may now be shutdown on exiting the program
Gdip_Shutdown(pToken)
ExitApp

Brlcad

# We need a database to hold the objects
opendb deathstar.g y

# We will be measuring in kilometers
units km

# Create a sphere of radius 60km centred at the origin
in sph1.s sph 0 0 0 60

# We will be subtracting an overlapping sphere with a radius of 40km
# The resultant hole will be smaller than this, because we only
# only catch the edge
in sph2.s sph 0 90 0 40

# Create a region named deathstar.r which consists of big minus small sphere
r deathstar.r u sph1.s - sph2.s

# We will use a plastic material texture with rgb colour 224,224,224
# with specular lighting value of 0.1 and no inheritance
mater deathstar.r "plastic sp=0.1" 224 224 224 0

# Clear the wireframe display and draw the deathstar
B deathstar.r

# We now trigger the raytracer to see our finished product
rt

C

Primitive ray tracing.

#include <stdio.h>
#include <math.h>
#include <unistd.h>

const char *shades = ".:!*oe&#%@";

double light[3] = { -50, 0, 50 };
void normalize(double * v)
{
	double len = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
	v[0] /= len; v[1] /= len; v[2] /= len;
}

double dot(double *x, double *y)
{
	double d = x[0]*y[0] + x[1]*y[1] + x[2]*y[2];
	return d < 0 ? -d : 0;
}

typedef struct { double cx, cy, cz, r; } sphere_t;

/* positive shpere and negative sphere */
sphere_t pos = { 20, 20, 0, 20 }, neg = { 1, 1, -6, 20 };

/* check if a ray (x,y, -inf)->(x, y, inf) hits a sphere; if so, return
   the intersecting z values.  z1 is closer to the eye */
int hit_sphere(sphere_t *sph, double x, double y, double *z1, double *z2)
{
	double zsq;
	x -= sph->cx;
	y -= sph->cy;
	zsq = sph->r * sph->r - (x * x + y * y);
	if (zsq < 0) return 0;
	zsq = sqrt(zsq);
	*z1 = sph->cz - zsq;
	*z2 = sph->cz + zsq;
	return 1;
}

void draw_sphere(double k, double ambient)
{
	int i, j, intensity, hit_result;
	double b;
	double vec[3], x, y, zb1, zb2, zs1, zs2;
	for (i = floor(pos.cy - pos.r); i <= ceil(pos.cy + pos.r); i++) {
		y = i + .5;
		for (j = floor(pos.cx - 2 * pos.r); j <= ceil(pos.cx + 2 * pos.r); j++) {
			x = (j - pos.cx) / 2. + .5 + pos.cx;

			/* ray lands in blank space, draw bg */
			if (!hit_sphere(&pos, x, y, &zb1, &zb2))
				hit_result = 0;

			/* ray hits pos sphere but not neg, draw pos sphere surface */
			else if (!hit_sphere(&neg, x, y, &zs1, &zs2))
				hit_result = 1;

			/* ray hits both, but pos front surface is closer */
			else if (zs1 > zb1) hit_result = 1;

			/* pos sphere surface is inside neg sphere, show bg */
			else if (zs2 > zb2) hit_result = 0;

			/* back surface on neg sphere is inside pos sphere,
			   the only place where neg sphere surface will be shown */
			else if (zs2 > zb1) hit_result = 2;
			else		    hit_result = 1;

			switch(hit_result) {
			case 0:
				putchar('+');
				continue;
			case 1:
				vec[0] = x - pos.cx;
				vec[1] = y - pos.cy;
				vec[2] = zb1 - pos.cz;
				break;
			default:
				vec[0] = neg.cx - x;
				vec[1] = neg.cy - y;
				vec[2] = neg.cz - zs2;
			}

			normalize(vec);
			b = pow(dot(light, vec), k) + ambient;
			intensity = (1 - b) * (sizeof(shades) - 1);
			if (intensity < 0) intensity = 0;
			if (intensity >= sizeof(shades) - 1)
				intensity = sizeof(shades) - 2;
			putchar(shades[intensity]);
		}
		putchar('\n');
	}
}

int main()
{
	double ang = 0;

	while (1) {
		printf("\033[H");
		light[1] = cos(ang * 2);
		light[2] = cos(ang);
		light[0] = sin(ang);
		normalize(light);
		ang += .05;

		draw_sphere(2, .3);
		usleep(100000);
	}
	return 0;
}

D

Translation of: C
import std.stdio, std.math, std.numeric, std.algorithm;

struct V3 {
    double[3] v;

    @property V3 normalize() pure nothrow const @nogc {
        immutable double len = dotProduct(v, v).sqrt;
        return [v[0] / len, v[1] / len, v[2] / len].V3;
    }

    double dot(in ref V3 y) pure nothrow const @nogc {
        immutable double d = dotProduct(v, y.v);
        return d < 0 ? -d : 0;
    }
}


const struct Sphere { double cx, cy, cz, r; }

void drawSphere(in double k, in double ambient, in V3 light) nothrow {
    /** Check if a ray (x,y, -inf).(x, y, inf) hits a sphere; if so,
    return the intersecting z values.  z1 is closer to the eye.*/
    static bool hitSphere(in ref Sphere sph,
                          in double x0, in double y0,
                          out double z1,
                          out double z2) pure nothrow @nogc {
        immutable double x = x0 - sph.cx;
        immutable double y = y0 - sph.cy;
        immutable double zsq = sph.r ^^ 2 - (x ^^ 2 + y ^^ 2);
        if (zsq < 0)
            return false;
        immutable double szsq = zsq.sqrt;
        z1 = sph.cz - szsq;
        z2 = sph.cz + szsq;
        return true;
    }

    immutable shades = ".:!*oe&#%@";
    // Positive and negative spheres.
    immutable pos = Sphere(20, 20, 0, 20);
    immutable neg = Sphere(1, 1, -6, 20);

    foreach (immutable int i; cast(int)floor(pos.cy - pos.r) ..
                              cast(int)ceil(pos.cy + pos.r) + 1) {
        immutable double y = i + 0.5;
    JLOOP:
        foreach (int j; cast(int)floor(pos.cx - 2 * pos.r) ..
                        cast(int)ceil(pos.cx + 2 * pos.r) + 1) {
            immutable double x = (j - pos.cx) / 2.0 + 0.5 + pos.cx;

            enum Hit { background, posSphere, negSphere }

            double zb1, zs2;
            immutable Hit hitResult = {
                double zb2, zs1;

                if (!hitSphere(pos, x, y, zb1, zb2)) {
                    // Ray lands in blank space, draw bg.
                    return Hit.background;
                } else if (!hitSphere(neg, x, y, zs1, zs2)) {
                    // Ray hits pos sphere but not neg one,
                    // draw pos sphere surface.
                    return Hit.posSphere;
                } else if (zs1 > zb1) {
                    // ray hits both, but pos front surface is closer.
                    return Hit.posSphere;
                } else if (zs2 > zb2) {
                    // pos sphere surface is inside neg sphere,
                    // show bg.
                    return Hit.background;
                } else if (zs2 > zb1) {
                    // Back surface on neg sphere is inside pos
                    // sphere, the only place where neg sphere
                    // surface will be shown.
                    return Hit.negSphere;
                } else {
                    return Hit.posSphere;
                }
            }();

            V3 vec_;
            final switch (hitResult) {
                case Hit.background:
                    ' '.putchar;
                    continue JLOOP;
                case Hit.posSphere:
                    vec_ = [x - pos.cx, y - pos.cy, zb1 - pos.cz].V3;
                    break;
                case Hit.negSphere:
                    vec_ = [neg.cx - x, neg.cy - y, neg.cz - zs2].V3;
                    break;
            }
            immutable nvec = vec_.normalize;

            immutable double b = light.dot(nvec) ^^ k + ambient;
            immutable intensity = cast(int)((1 - b) * shades.length);
            immutable normInt = min(shades.length, max(0, intensity));
            shades[normInt].putchar;
        }

        '\n'.putchar;
    }
}


void main() {
    immutable light = [-50, 30, 50].V3.normalize;
    drawSphere(2, 0.5, light);
}

The output is the same of the C version.

Delphi

Library: system.Math
Translation of: C

Translate of #C and #Go, with copy of some parts of #DWScript.

program Death_Star;

{$APPTYPE CONSOLE}

uses
  Winapi.Windows,
  System.SysUtils,
  system.Math,
  Vcl.Graphics,
  Vcl.Imaging.pngimage;

type
  TVector = array of double;

var
  light: TVector = [20, -40, -10];

function ClampInt(value, amin, amax: Integer): Integer;
begin
  Result := Max(amin, Min(amax, value))
end;

procedure Normalize(var v: TVector);
begin
  var len := Sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  v[0] := v[0] / len;
  v[1] := v[1] / len;
  v[2] := v[2] / len;
end;

function Dot(x, y: TVector): Double;
begin
  var d := x[0] * y[0] + x[1] * y[1] + x[2] * y[2];
  if d < 0 then
    Result := -d
  else
    Result := 0;
end;

type
  TSphere = record
    cx, cy, cz, r: Double;
  end;

const
  pos: TSphere = (
    cx: 0;
    cy: 0;
    cz: 0;
    r: 120
  );

const
  neg: TSphere = (
    cx: -90;
    cy: -90;
    cz: -30;
    r: 80
  );

function HitSphere(sph: TSphere; x, y: double; var z1, z2: Double): Boolean;
begin
  x := x - sph.cx;
  y := y - sph.cy;
  var zsq := sph.r * sph.r - (x * x + y * y);
  if (zsq < 0) then
    Exit(False);
  zsq := Sqrt(zsq);
  z1 := sph.cz - zsq;
  z2 := sph.cz + zsq;
  Result := True;
end;

function DeathStar(pos, neg: TSphere; k, amb: Double; light: TVector): TBitmap;
var
  w, h, yMax, xMax, s: double;
  zp1, zp2, zn1, zn2, b: Double;
  x, y: Integer;
  hit: Boolean;
  vec: TVector;
  intensity: Byte;
  ox, oy: Integer;
begin
  w := pos.r * 4;
  h := pos.r * 3;
  ox := -trunc(pos.cx - w / 2);
  oy := -trunc(pos.cy - h / 2);

  vec := [0, 0, 0];
  Result := TBitmap.Create;
  Result.SetSize(trunc(w), trunc(h));

  yMax := pos.cy + pos.r;
  for y := Trunc(pos.cy - pos.r) to Trunc(yMax) do
  begin
    xMax := pos.cx + pos.r;
    for x := trunc(pos.cy - pos.r) to trunc(xMax) do
    begin
      hit := HitSphere(pos, x, y, zp1, zp2);
      if not hit then
        continue;

      hit := HitSphere(neg, x, y, zn1, zn2);

      if hit then
      begin
        if zn1 > zp1 then
          hit := false
        else if zn2 > zp2 then
          continue;
      end;

      if hit then
      begin
        vec[0] := neg.cx - x;
        vec[1] := neg.cy - y;
        vec[2] := neg.cz - zn2;
      end
      else
      begin
        vec[0] := x - pos.cx;
        vec[1] := y - pos.cy;
        vec[2] := zp1 - pos.cz;
      end;

      Normalize(vec);

      s := max(0, dot(light, vec));

      b := Power(s, k) + amb;

      intensity := ClampInt(round(255 * b / (1 + amb)), 0, 254);

      Result.Canvas.Pixels[x + ox, y + oy] := rgb(intensity, intensity, intensity);
    end;
  end;
end;

var
  bmp: TBitmap;

begin
  Normalize(light);
  bmp := DeathStar(pos, neg, 1.2, 0.3, light);

  with TPngImage.Create do
  begin
    Assign(bmp);
    TransparentColor := clwhite;
    SaveToFile('out.png');
    bmp.Free;
    Free;
  end;
end.

DWScript

Translation of: C
const cShades = '.:!*oe&#%@';

type TVector = array [0..2] of Float;

var light : TVector = [-50.0, 30, 50];
 
procedure Normalize(var v : TVector);
begin
   var len := Sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
   v[0] /= len; v[1] /= len; v[2] /= len;
end;
 
function Dot(x, y : TVector) : Float;
begin
   var d :=x[0]*y[0] + x[1]*y[1] + x[2]*y[2];
   if d<0 then 
      Result:=-d 
   else Result:=0;
end;
 
type 
   TSphere = record
      cx, cy, cz, r : Float;
   end;
   
const big : TSphere = (cx: 20; cy: 20; cz: 0; r: 20);
const small : TSphere = (cx: 7; cy: 7; cz: -10; r: 15);
 
function HitSphere(sph : TSphere; x, y : Float; var z1, z2 : Float) : Boolean;
begin
   x -= sph.cx;
   y -= sph.cy;
   var zsq = sph.r * sph.r - (x * x + y * y);
   if (zsq < 0) then Exit False;
   zsq := Sqrt(zsq);
   z1 := sph.cz - zsq;
   z2 := sph.cz + zsq;
   Result:=True;
end;
 
procedure DrawSphere(k, ambient : Float);
var
   i, j, intensity : Integer;
   b : Float;
   x, y, zb1, zb2, zs1, zs2 : Float;
   vec : TVector;
begin
   for i:=Trunc(big.cy-big.r) to Trunc(big.cy+big.r)+1 do begin
      y := i + 0.5;
      for j := Trunc(big.cx-2*big.r) to Trunc(big.cx+2*big.r) do begin
         x := (j-big.cx)/2 + 0.5 + big.cx;
 
         if not HitSphere(big, x, y, zb1, zb2) then begin
            Print(' ');
            continue;
         end;
         if not HitSphere(small, x, y, zs1, zs2) then begin
            vec[0] := x - big.cx;
            vec[1] := y - big.cy;
            vec[2] := zb1 - big.cz;
         end else begin
            if zs1 < zb1 then begin
               if zs2 > zb2 then begin
                  Print(' ');
                  continue;
               end;
               if zs2 > zb1 then begin
                  vec[0] := small.cx - x;
                  vec[1] := small.cy - y;
                  vec[2] := small.cz - zs2;
               end else begin
                  vec[0] := x - big.cx;
                  vec[1] := y - big.cy;
                  vec[2] := zb1 - big.cz;
               end;
            end else begin
               vec[0] := x - big.cx;
               vec[1] := y - big.cy;
               vec[2] := zb1 - big.cz;
            end;
         end;
 
         Normalize(vec);
         b := Power(Dot(light, vec), k) + ambient;
         intensity := Round((1 - b) * Length(cShades));
         Print(cShades[ClampInt(intensity+1, 1, Length(cShades))]);
      end;
      PrintLn('');
   end;
end;
 
Normalize(light);
 
DrawSphere(2, 0.3);

Frink

This program not only draws a Death Star and renders it onscreen projected on the x,y, and z axes but also outputs a .stl file for 3-D printing. Frink has built-in routines for 3-D modeling.

res = 254 / in
v = callJava["frink.graphics.VoxelArray", "makeSphere", [1/2 inch res]]

dish = callJava["frink.graphics.VoxelArray", "makeSphere", [1/2 inch res]]
dish.translate[round[.45 inch res], round[.45 inch res], round[.45 inch res]]
v.remove[dish]

v.projectX[undef].show["X"]
v.projectY[undef].show["Y"]
v.projectZ[undef].show["Z"]   

filename = "DeathStar.stl"
print["Writing $filename..."]
w = new Writer[filename]
w.println[v.toSTLFormat["DeathStar", 1/(res mm)]]
w.close[]
println["done."]

Go

Output png
Translation of: C
package main

import (
    "fmt"
    "image"
    "image/color"
    "image/png"
    "math"
    "os"
)

type vector [3]float64

func (v *vector) normalize() {
    invLen := 1 / math.Sqrt(dot(v, v))
    v[0] *= invLen
    v[1] *= invLen
    v[2] *= invLen
}

func dot(x, y *vector) float64 {
    return x[0]*y[0] + x[1]*y[1] + x[2]*y[2]
}

type sphere struct {
    cx, cy, cz int
    r          int
}

func (s *sphere) hit(x, y int) (z1, z2 float64, hit bool) {
    x -= s.cx
    y -= s.cy
    if zsq := s.r*s.r - (x*x + y*y); zsq >= 0 {
        zsqrt := math.Sqrt(float64(zsq))
        return float64(s.cz) - zsqrt, float64(s.cz) + zsqrt, true
    }
    return 0, 0, false
}

func deathStar(pos, neg *sphere, k, amb float64, dir *vector) *image.Gray {
    w, h := pos.r*4, pos.r*3
    bounds := image.Rect(pos.cx-w/2, pos.cy-h/2, pos.cx+w/2, pos.cy+h/2)
    img := image.NewGray(bounds)
    vec := new(vector)
    for y, yMax := pos.cy-pos.r, pos.cy+pos.r; y <= yMax; y++ {
        for x, xMax := pos.cx-pos.r, pos.cx+pos.r; x <= xMax; x++ {
            zb1, zb2, hit := pos.hit(x, y)
            if !hit {
                continue
            }
            zs1, zs2, hit := neg.hit(x, y)
            if hit {
                if zs1 > zb1 {
                    hit = false
                } else if zs2 > zb2 {
                    continue
                }
            }
            if hit {
                vec[0] = float64(neg.cx - x)
                vec[1] = float64(neg.cy - y)
                vec[2] = float64(neg.cz) - zs2
            } else {
                vec[0] = float64(x - pos.cx)
                vec[1] = float64(y - pos.cy)
                vec[2] = zb1 - float64(pos.cz)
            }
            vec.normalize()
            s := dot(dir, vec)
            if s < 0 {
                s = 0
            }
            lum := 255 * (math.Pow(s, k) + amb) / (1 + amb)
            if lum < 0 {
                lum = 0
            } else if lum > 255 {
                lum = 255
            }
            img.SetGray(x, y, color.Gray{uint8(lum)})
        }
    }
    return img
}

func main() {
    dir := &vector{20, -40, -10}
    dir.normalize()
    pos := &sphere{0, 0, 0, 120}
    neg := &sphere{-90, -90, -30, 100}

    img := deathStar(pos, neg, 1.5, .2, dir)
    f, err := os.Create("dstar.png")
    if err != nil {
        fmt.Println(err)
        return
    }
    if err = png.Encode(f, img); err != nil {
        fmt.Println(err)
    }
    if err = f.Close(); err != nil {
        fmt.Println(err)
    }
}

Haskell

ASCII art

import Data.List (genericLength)

shades = ".:!*oe%#&@"
n = genericLength shades
dot a b = sum $ zipWith (*) a b
normalize x = (/ sqrt (x `dot` x)) <$> x

deathStar r k amb = unlines $
  [ [ if x*x + y*y <= r*r
      then let vec = normalize $ normal x y
               b = (light `dot` vec) ** k + amb
               intensity = (1 - b)*(n - 1)
           in shades !! round ((0 `max` intensity) `min` n)
      else ' '
    | y <- map (/2.12) [- 2*r - 0.5 .. 2*r + 0.5]  ]
  | x <- [ - r - 0.5 .. r + 0.5] ]
  where
    light = normalize [-30,-30,-50]
    normal x y
      | (x+r)**2 + (y+r)**2 <= r**2 = [x+r, y+r, sph2 x y]
      | otherwise = [x, y, sph1 x y]
    sph1 x y = sqrt (r*r - x*x - y*y)
    sph2 x y = r - sqrt (r*r - (x+r)**2 - (y+r)**2)
λ> putStrLn $ deathStar 10 4 0.1
                                            
                                            
               eeeeoo*&&&&&&&               
          eeeeeoooo**!&&&&&&&&&&&&          
       eeooooooo***!!&&&&&&&&&&&&&&&&       
     eooooo*****!!!::&&&&&&&&&&&&&&&&&&     
    eooo****!!!!:::.&&&&&&&&&&&&&&&&&&&&    
  eeeoo***!!!::::.&&&&&&##############&&&&  
 eeeoo***!!:::...&&&########%%%%%%%%#####&& 
 eeoo**!!!::...&&######%%%%%%%eeeeee%%%%### 
eooo**!!::..&&&#####%%%%%eeeeeooooooeeee%%#&
oo**!!:&&&&&&&####%%%%eeeoooo********oooee%#
&&&&&&&&&&&&#####%%%eeeoo****!!!!!!!!***oe%#
&&&&&&&&&&&####%%%eeeoo***!!!::::::::!!**oe#
 &&&&&&&&&&###%%%eeooo**!!:::.......::!!*oe 
 &&&&&&&&&####%%eeeoo**!!::..........::!*o% 
  &&&&&&&&####%%eeoo**!!::...........:!*o%  
    &&&&&&####%%eeoo**!!::..........:!*o    
     &&&&&&###%%%eeoo**!!::......::!*oe     
       &&&&&###%%%eeoo**!!!!:::!!!*o%       
          &&&&###%%%eeoooo****ooe%          
               &&####%%%%%%%#               
                                            
                                            

J

Translation of: Python
load'graphics/viewmat'
mag =: +/&.:*:"1
norm=: %"1 0 mag
dot =: +/@:*"1

NB. (pos;posr;neg;negr) getvec (x,y)
getvec =: 4 :0 "1
  pt =. y
  'pos posr neg negr' =. x
  if. (dot~ pt-}:pos) > *:posr do.
    0 0 0
  else.
    zb =. ({:pos) (-,+)  posr -&.:*: pt mag@:- }:pos
    if. (dot~ pt-}:neg) > *:negr do.
      (pt,{:zb) - pos
    else.
      zs =. ({:neg) (-,+) negr -&.:*: pt mag@:- }:neg
      if. zs >&{. zb do. (pt,{:zb) - pos
      elseif. zs >&{: zb do. 0 0 0
      elseif. ({.zs) < ({:zb) do. neg - (pt,{.zs)
      elseif. do. (pt,{.zb) - pos end.
    end.
  end.
)
    

NB. (k;ambient;light) draw_sphere (pos;posr;neg;negr)
draw_sphere =: 4 :0
  'pos posr neg negr' =. y
  'k ambient light' =. x
  vec=. norm y getvec ,"0// (2{.pos) +/ i: 200 j.~ 0.5+posr

  b=. (mag vec) * ambient + k * 0>. light dot vec
)

togray =: 256#. 255 255 255 <.@*"1 0 (%>./@,)

env=.(2; 0.5; (norm _50 30 50))
sph=. 20 20 0; 20;   1 1 _6; 20
'rgb' viewmat togray  env draw_sphere sph

Java

Library: JavaFX
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
public class DeathStar extends Application {

	private static final int DIVISION = 200;// the bigger the higher resolution
	float radius = 300;// radius of the sphere

	@Override
	public void start(Stage primaryStage) throws Exception {
		Point3D otherSphere = new Point3D(-radius, 0, -radius * 1.5);
		final TriangleMesh triangleMesh = createMesh(DIVISION, radius, otherSphere);
		MeshView a = new MeshView(triangleMesh);

		a.setTranslateY(radius);
		a.setTranslateX(radius);
		a.setRotationAxis(Rotate.Y_AXIS);
		Scene scene = new Scene(new Group(a));
//		uncomment if you want to move the other sphere
		
//		scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
//			Point3D sphere = otherSphere;
//
//			@Override
//			public void handle(KeyEvent e) {
//				KeyCode code = e.getCode();
//				switch (code) {
//				case UP:
//					sphere = sphere.add(0, -10, 0);
//					break;
//				case DOWN:
//					sphere = sphere.add(0, 10, 0);
//					break;
//				case LEFT:
//					sphere = sphere.add(-10, 0, 0);
//					break;
//				case RIGHT:
//					sphere = sphere.add(10, 0, 0);
//					break;
//				case W:
//					sphere = sphere.add(0, 0, 10);
//					break;
//				case S:
//					sphere = sphere.add(0, 0, -10);
//					break;
//				default:
//					return;
//				}
//				a.setMesh(createMesh(DIVISION, radius, sphere));
//
//			}
//		});

		primaryStage.setScene(scene);
		primaryStage.show();
	}

	static TriangleMesh createMesh(final int division, final float radius, final Point3D centerOtherSphere) {
		Rotate rotate = new Rotate(180, centerOtherSphere);
		final int div2 = division / 2;

		final int nPoints = division * (div2 - 1) + 2;
		final int nTPoints = (division + 1) * (div2 - 1) + division * 2;
		final int nFaces = division * (div2 - 2) * 2 + division * 2;

		final float rDiv = 1.f / division;

		float points[] = new float[nPoints * 3];
		float tPoints[] = new float[nTPoints * 2];
		int faces[] = new int[nFaces * 6];

		int pPos = 0, tPos = 0;

		for (int y = 0; y < div2 - 1; ++y) {
			float va = rDiv * (y + 1 - div2 / 2) * 2 * (float) Math.PI;
			float sin_va = (float) Math.sin(va);
			float cos_va = (float) Math.cos(va);

			float ty = 0.5f + sin_va * 0.5f;
			for (int i = 0; i < division; ++i) {
				double a = rDiv * i * 2 * (float) Math.PI;
				float hSin = (float) Math.sin(a);
				float hCos = (float) Math.cos(a);
				points[pPos + 0] = hSin * cos_va * radius;
				points[pPos + 2] = hCos * cos_va * radius;
				points[pPos + 1] = sin_va * radius;

				final Point3D point3D = new Point3D(points[pPos + 0], points[pPos + 1], points[pPos + 2]);
				double distance = centerOtherSphere.distance(point3D);
				if (distance <= radius) {
					Point3D subtract = centerOtherSphere.subtract(point3D);
					Point3D transform = rotate.transform(subtract);
					points[pPos + 0] = (float) transform.getX();
					points[pPos + 1] = (float) transform.getY();
					points[pPos + 2] = (float) transform.getZ();
					
				}
				tPoints[tPos + 0] = 1 - rDiv * i;
				tPoints[tPos + 1] = ty;
				pPos += 3;
				tPos += 2;
			}
			tPoints[tPos + 0] = 0;
			tPoints[tPos + 1] = ty;
			tPos += 2;
		}

		points[pPos + 0] = 0;
		points[pPos + 1] = -radius;
		points[pPos + 2] = 0;
		points[pPos + 3] = 0;
		points[pPos + 4] = radius;
		points[pPos + 5] = 0;
		pPos += 6;

		int pS = (div2 - 1) * division;

		float textureDelta = 1.f / 256;
		for (int i = 0; i < division; ++i) {
			tPoints[tPos + 0] = rDiv * (0.5f + i);
			tPoints[tPos + 1] = textureDelta;
			tPos += 2;
		}

		for (int i = 0; i < division; ++i) {
			tPoints[tPos + 0] = rDiv * (0.5f + i);
			tPoints[tPos + 1] = 1 - textureDelta;
			tPos += 2;
		}

		int fIndex = 0;
		for (int y = 0; y < div2 - 2; ++y) {
			for (int x = 0; x < division; ++x) {
				int p0 = y * division + x;
				int p1 = p0 + 1;
				int p2 = p0 + division;
				int p3 = p1 + division;

				int t0 = p0 + y;
				int t1 = t0 + 1;
				int t2 = t0 + division + 1;
				int t3 = t1 + division + 1;

				// add p0, p1, p2
				faces[fIndex + 0] = p0;
				faces[fIndex + 1] = t0;
				faces[fIndex + 2] = p1 % division == 0 ? p1 - division : p1;
				faces[fIndex + 3] = t1;
				faces[fIndex + 4] = p2;
				faces[fIndex + 5] = t2;
				fIndex += 6;

				// add p3, p2, p1
				faces[fIndex + 0] = p3 % division == 0 ? p3 - division : p3;
				faces[fIndex + 1] = t3;
				faces[fIndex + 2] = p2;
				faces[fIndex + 3] = t2;
				faces[fIndex + 4] = p1 % division == 0 ? p1 - division : p1;
				faces[fIndex + 5] = t1;
				fIndex += 6;
			}
		}

		int p0 = pS;
		int tB = (div2 - 1) * (division + 1);
		for (int x = 0; x < division; ++x) {
			int p2 = x, p1 = x + 1, t0 = tB + x;
			faces[fIndex + 0] = p0;
			faces[fIndex + 1] = t0;
			faces[fIndex + 2] = p1 == division ? 0 : p1;
			faces[fIndex + 3] = p1;
			faces[fIndex + 4] = p2;
			faces[fIndex + 5] = p2;
			fIndex += 6;
		}

		p0 = p0 + 1;
		tB = tB + division;
		int pB = (div2 - 2) * division;

		for (int x = 0; x < division; ++x) {
			int p1 = pB + x, p2 = pB + x + 1, t0 = tB + x;
			int t1 = (div2 - 2) * (division + 1) + x, t2 = t1 + 1;
			faces[fIndex + 0] = p0;
			faces[fIndex + 1] = t0;
			faces[fIndex + 2] = p1;
			faces[fIndex + 3] = t1;
			faces[fIndex + 4] = p2 % division == 0 ? p2 - division : p2;
			faces[fIndex + 5] = t2;
			fIndex += 6;
		}

		TriangleMesh m = new TriangleMesh();
		m.getPoints().setAll(points);
		m.getTexCoords().setAll(tPoints);
		m.getFaces().setAll(faces);

		return m;
	}

	public static void main(String[] args) {

		launch(args);
	}

}

Using Java 11

Alternatively, without using JavaFX, which has been removed from the JavaJDK since version 11.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.imageio.ImageIO;

public final class DeathStar {

	public static void main(String[] aArgs) throws IOException {
		Vector direction = new Vector(20.0, -40.0, -10.0);
		direction.normalise();
		Sphere positive = new Sphere(0, 0, 0, 120);
		Sphere negative = new Sphere(-90, -90, -30, 100);

		BufferedImage image = deathStar(positive, negative, direction, 1.5, 0.5);
		
		ImageIO.write(image, "png", new File("DeathStarJava.png"));
	}
	
	private static BufferedImage deathStar(
			Sphere aPositive, Sphere aNegative, Vector aDirection, double aShadow, double aBrightness) {
		final int width = aPositive.radius * 4;
		final int height = aPositive.radius * 3;
		BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics graphics = result.getGraphics();
        graphics.setColor(Color.CYAN);
        graphics.fillRect(0, 0, width, height);
        
		Vector ray = new Vector(0.0, 0.0, 0.0);
		final int deltaX = aPositive.x - width / 2;
		final int deltaY = aPositive.y - height / 2;

		double xMax = aPositive.x + aPositive.radius;
		double yMax = aPositive.y + aPositive.radius;
		for ( int y = aPositive.y - aPositive.radius; y < yMax; y++ ) {
		    for ( int x = aPositive.x - aPositive.radius; x < xMax; x++ ) {
		    	List<Object> contacts = aPositive.contact(x, y);
		    	final double zb1 = (double) contacts.get(0);
		    	final int zb2 = (int) contacts.get(1);
		    	final boolean positiveHit = (boolean) contacts.get(2);
		    	if ( ! positiveHit ) {
		    		continue;
		    	}
	       		contacts = aNegative.contact(x, y);
	       		final double zs1 = (double) contacts.get(0);
	       		final int zs2 = (int) contacts.get(1);
	       		boolean negativeHit = (boolean) contacts.get(2);
	       		if ( negativeHit ) {
	       			if ( zs1 > zb1 ) {
	       				negativeHit = false;
	       			} else if ( zs2 > zb2 ) {
	       				continue;
	       			}
	       		}
	       		
		       	if ( negativeHit ) {
		       		ray.x = aNegative.x - x;
		       		ray.y = aNegative.y - y;
		       		ray.z = aNegative.z - zs2;
		       	} else {
		       		ray.x = x - aPositive.x;
		       		ray.y = y - aPositive.y;
		       		ray.z = zb1 - aPositive.z;
		       	}
		       	ray.normalise();
		       	double rayComponent = ray.scalarProduct(aDirection);
		       	if ( rayComponent < 0 ) { 
		       		rayComponent = 0;
		       	}
		       	int color = (int) ( 255 * ( Math.pow(rayComponent, aShadow) + aBrightness) / ( 1 + aBrightness ) );
		       	if ( color < 0 ) {
		       		color = 0;
		       	} else if ( color > 255 ) {
		       		color = 255;
		       	}
		       	result.setRGB(x - deltaX, y - deltaY, color);
		    }
		}
		return result;
	}	
	
	private static class Vector {
		
		public Vector(double aX, double aY, double aZ) {
			x = aX; y = aY; z = aZ;
		}
		
		public double scalarProduct(Vector aOther) {
			return x * aOther.x + y * aOther.y + z * aOther.z;
		}
		
		public Vector normalise() {
			final double magnitude = Math.sqrt(this.scalarProduct(this));
			return new Vector(x /= magnitude, y /= magnitude, z /= magnitude);
		}
		
		private double x, y, z;
		
	}
	
	private static class Sphere {
		
		public Sphere(int aX, int aY, int aZ, int aRadius) {
			x = aX; y = aY; z = aZ; radius = aRadius;
		}
		
		public List<Object> contact(int aX, int aY) {
			final int xx = aX - x;
			final int yy = aY - y;
			final int zSquared = radius * radius - ( xx * xx + yy * yy );
			if ( zSquared >= 0 ) {
				final double zz = Math.sqrt(zSquared);
				return List.of(z - zz, z, true);
			}
			return List.of( 0.0, 0, false );
		}	
		
		private int x, y, z, radius;
		
	}

}
Output:

Media:DeathStarJava.png

JavaScript

Layer circles and gradients to achieve result similar to that of the Wikipedia page for the Death Star.

<!DOCTYPE html>
<html>
<body style="margin:0">
  <canvas id="myCanvas" width="250" height="250" style="border:1px solid #d3d3d3;">
    Your browser does not support the HTML5 canvas tag.
  </canvas>
  <script>
    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");
    //Fill the canvas with a dark gray background
    ctx.fillStyle = "#222222";
    ctx.fillRect(0,0,250,250);

    // Create radial gradient for large base circle
    var grd = ctx.createRadialGradient(225,175,190,225,150,130);
    grd.addColorStop(0,"#EEEEEE");
    grd.addColorStop(1,"black");
    //Apply gradient and fill circle
    ctx.fillStyle = grd;
    ctx.beginPath();
    ctx.arc(125,125,105,0,2*Math.PI);
    ctx.fill();
    
    // Create linear gradient for small inner circle
    var grd = ctx.createLinearGradient(75,90,102,90);
    grd.addColorStop(0,"black");
    grd.addColorStop(1,"gray");
    //Apply gradient and fill circle
    ctx.fillStyle = grd;
    ctx.beginPath();
    ctx.arc(90,90,30,0,2*Math.PI);
    ctx.fill();
    
    //Add another small circle on top of the previous one to enhance the "shadow"
    ctx.fillStyle = "black";
    ctx.beginPath();
    ctx.arc(80,90,17,0,2*Math.PI);
    ctx.fill();
  </script> 
</body>
</html>

Julia

# run in REPL
using GLMakie

function deathstar()
    n = 60
    θ = [0; (0.5: n - 0.5) / n; 1]
    φ = [(0: 2n - 2) * 2 / (2n - 1); 2]
    # if x is +0.9 radius units, replace it with the coordinates of sphere surface
    # at (1.2,0,0) center, radius 0.5 units
    x = [(x1 = cospi(φ)*sinpi(θ)) > 0.9 ? 1.2 - x1 * 0.5 : x1 for θ in θ, φ in φ]
    y = [sinpi(φ)*sinpi(θ) for θ in θ, φ in φ]
    z = [cospi(θ) for θ in θ, φ in φ]
    scene = Scene(backgroundcolor=:black)
    surface!(scene, x, y, z, color = rand(RGBAf0, 124, 124), show_axis=false)
    return scene
end

scene = deathstar()

LSL

Rez a box on the ground, raise it up a few meters, add the following as a New Script.

default {
    state_entry() {
        llSetPrimitiveParams([PRIM_NAME, "RosettaCode DeathStar"]);
        llSetPrimitiveParams([PRIM_DESC, llGetObjectName()]);
        llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_SPHERE, PRIM_HOLE_CIRCLE, <0.0, 1.0, 0.0>, 0.0, <0.0, 0.0, 0.0>, <0.12, 1.0, 0.0>]);
        llSetPrimitiveParams([PRIM_ROTATION, <-0.586217, 0.395411, -0.586217, 0.395411>]);
        llSetPrimitiveParams([PRIM_TEXTURE, ALL_SIDES, TEXTURE_BLANK, ZERO_VECTOR, ZERO_VECTOR, 0.0]);
        llSetPrimitiveParams([PRIM_TEXT, llGetObjectName(), <1.0, 1.0, 1.0>, 1.0]);
        llSetPrimitiveParams([PRIM_COLOR, ALL_SIDES, <0.5, 0.5, 0.5>, 1.0]);
        llSetPrimitiveParams([PRIM_BUMP_SHINY, ALL_SIDES, PRIM_SHINY_HIGH, PRIM_BUMP_NONE]);
        llSetPrimitiveParams([PRIM_SIZE, <10.0, 10.0, 10.0>]);
        llSetPrimitiveParams([PRIM_OMEGA, <0.0, 0.0, 1.0>, 1.0, 1.0]);
    }
}

Output: Death Star

Lua

Translation of: C
function V3(x,y,z) return {x=x,y=y,z=z} end
function dot(v,w) return v.x*w.x + v.y*w.y + v.z*w.z end
function norm(v) local m=math.sqrt(dot(v,v)) return V3(v.x/m, v.y/m, v.z/m) end
function clamp(n,lo,hi) return math.floor(math.min(math.max(lo,n),hi)) end
function hittest(s, x, y)
  local z = s.r^2 - (x-s.x)^2 - (y-s.y)^2
  if z >= 0 then
    z = math.sqrt(z)
    return true, s.z-z, s.z+z
  end
  return false, 0, 0
end

function deathstar(pos, neg, sun, k, amb)
  shades = {[0]=" ",".",":","!","*","o","e","&","#","%","@"}
  for y = pos.x-pos.r-0.5, pos.x+pos.r+0.5 do
    for x = pos.x-pos.r-0.5, pos.x+pos.r+0.5, 0.5 do
      local hitpos, pz1, pz2 = hittest(pos, x, y)
      local result, hitneg, nz1, nz2 = 0
      if hitpos then
        hitneg, nz1, nz2 = hittest(neg, x, y)
        if not hitneg or nz1 > pz1 then result = 1
        elseif nz2 > pz2 then result = 0
        elseif nz2 > pz1 then result = 2
        else result = 1
        end
      end
      local shade = 0
      if result > 0 then
        if result == 1 then
          shade = clamp((1-dot(sun, norm(V3(x-pos.x, y-pos.y, pz1-pos.z)))^k+amb) * #shades, 1, #shades)
        else
          shade = clamp((1-dot(sun, norm(V3(neg.x-x, neg.y-y, neg.z-nz2)))^k+amb) * #shades, 1, #shades)
        end
      end
      io.write(shades[shade])
    end
    io.write("\n")
  end
end

deathstar({x=20, y=20, z=0, r=20}, {x=10, y=10, z=-15, r=10}, norm(V3(-2,1,3)), 2, 0.1)
Output:
                                         @@@%%%%%%%%%#########%
                                 @@@@@%%%%%%#######&&&&&&&&&&&&&&&&&&##
                            @@@@@@%%%%%%######&&&&&&&eeeeeeeeeeeeeeeeeeeee&&
                       @@@@@@@@@@@@@@@@@@@&&&&&&eeeeeeeoooooooooooooooooooooeee&
                    @@@@@&####%%%%@@@@@@@@@@@@%eeeeoooooooo*******************oooee
                 @@@@eeee&&&&####%%%@@@@@@@@@@@@%oooooo********!!!!!!!!!!!!!!*****oooe
               @@@**ooooeeee&&&####%%%@@@@@@@@@@@%oo*******!!!!!!!!!!!!!!!!!!!!!!!****oo&
             @@@!!!****ooooeee&&&###%%%%@@@@@@@@@@%*****!!!!!!!!:::::::::::::::::!!!!!**ooe
           @@@:::!!!!!****oooeee&&###%%%%@@@@@@@@@%***!!!!!!!::::::::::::::::::::::::!!!***oe
         @@@@::::::::!!!***oooeee&&&##%%%%@@@@@@@@@**!!!!!!!:::::::::............::::::!!!**oo
        @@@.......::::!!!!***ooeee&&###%%%@@@@@@@@@*!!!!!!::::::::..................:::::!!!**oe
      %@@@@.........::::!!!**oooee&&&##%%%@@@@@@@@*!!!!!!::::::::......................::::!!!*oe
     %@@@@...........:::!!!***ooeee&&###%%%@@@@@@**!!!!!!:::::::........................::::!!!*oo
    %@@@@@...........:::!!!***ooeee&&###%%@@@@@@***!!!!!!:::::::.........................::::!!!*oe
    @@@@@@..........::::!!!**oooee&&&##%%%@@@@@****!!!!!!:::::::..........................::::!!**oe
   %@@@@@@::::...:::::!!!!***ooeee&&###%%@@@@o*****!!!!!!:::::::..........................::::!!!**o
   @@@@@@@@!!!:::::!!!!!***oooee&&&##%%%@@oooo******!!!!!!:::::::.........................:::::!!**oe
  %@@@@@@@@@o****!******ooooeee&&###%%%eeeooooo*****!!!!!!!:::::::........................::::!!!**oe
  %@@@@@@@@@@@eeoooooooeeeee&&&##%%%&eeeeeeooooo*****!!!!!!!::::::::.....................:::::!!!**oo&
  %@@@@@@@@@@@@@@@@##&&&#####%###&&&&&eeeeeoooooo******!!!!!!:::::::::..................:::::!!!!**oe&
  %@@@@@@@@@@@@@@@@@@@%%%%%%######&&&&&eeeeeoooooo******!!!!!!!:::::::::::...........:::::::!!!!***oe&
  %%@@@@@@@@@@@@@@@@@@@%%%%%%######&&&&&eeeeeeooooo*******!!!!!!!::::::::::::::::::::::::::!!!!***ooe&
  #%@@@@@@@@@@@@@@@@@@@%%%%%%%######&&&&&eeeeeeoooooo*******!!!!!!!!::::::::::::::::::::!!!!!!***ooee
   %%@@@@@@@@@@@@@@@@@@@%%%%%%%######&&&&&&eeeeeeoooooo*******!!!!!!!!!!!!::::::::::!!!!!!!!****ooee&
   #%@@@@@@@@@@@@@@@@@@@@%%%%%%%######&&&&&&eeeeeeooooooo*********!!!!!!!!!!!!!!!!!!!!!!!!****oooee&
    %%@@@@@@@@@@@@@@@@@@@@@%%%%%%%######&&&&&&eeeeeeeooooooo**********!!!!!!!!!!!!!!!*******ooooee&#
    &%%@@@@@@@@@@@@@@@@@@@@@%%%%%%%#######&&&&&&eeeeeeeooooooooo*************************oooooeee&#
     #%%@@@@@@@@@@@@@@@@@@@@@@%%%%%%%#######&&&&&&&eeeeeeeooooooooooo****************ooooooeeee&&#
      &%%@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%#######&&&&&&&&eeeeeeeeeoooooooooooooooooooooooooeeeee&&##
        #%%@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%########&&&&&&&&eeeeeeeeeeeeoooooooooooooeeeeeeee&&&##%
         #%%@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########&&&&&&&&&&eeeeeeeeeeeeeeeeeeeeeeee&&&&&##%
           #%%@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%#########&&&&&&&&&&&&&&&&eeeee&&&&&&&&&&####%%
             #%%@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%%###########&&&&&&&&&&&&&&&&&&&&######%%%
               #%%@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%%%#############################%%%%@
                 #%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%%%%%%%###############%%%%%%%@
                    #%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@
                       #%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%@@@@@@@@@
                            %%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                                 %@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                                         @@@@@@@@@@@@@@@@@@@@@@

Maple

with(plots):
with(plottools):
plots:-display(
   implicitplot3d(x^2 + y^2 + z^2 = 1, x = -1..0.85, y = -1..1, z = -1..1, style = surface, grid = [50,50,50]),
   translate(rotate(implicitplot3d(x^2 + y^2 + z^2 = 1, x = 0.85..1, y = -1..1, z = -1..1, style = surface, grid = [50,50,50]), 0, Pi, 0), 1.70, 0, 0),
axes = none, scaling = constrained, color = gray)

Mathematica / Wolfram Language

RegionPlot3D[x^2 + y^2 + z^2 < 1 && (x + 1.7)^2 + y^2 + z^2 > 1, 
{x, -1, 1}, {y, -1, 1}, {z, -1, 1}, 
Boxed -> False, Mesh -> False, Axes -> False, Background -> Black, PlotPoints -> 100]

Nim

Translation of: Go
Library: nimPNG

The result is written in a PNG file. For this purpose, we used the modules “bitmap” and “grayscale_image” created for the tasks “Bitmap” and “Grayscale image”. To write the PNG file, we use the third party library “nimPNG”.

import math

import bitmap, grayscale_image, nimPNG

type

  Vector = array[3, float]

  Sphere = object
    cx, cy, cz: int
    r: int

#---------------------------------------------------------------------------------------------------

func dot(x, y: Vector): float {.inline.} =
  x[0] * y[0] + x[1] * y[1] + x[2] * y[2]

#---------------------------------------------------------------------------------------------------

func normalize(v: var Vector) =
  let invLen = 1 / sqrt(dot(v, v))
  v[0] *= invLen
  v[1] *= invLen
  v[2] *= invLen

#---------------------------------------------------------------------------------------------------

func hit(s: Sphere; x, y: int): tuple[z1, z2: float; hit: bool] =
  let x = x - s.cx
  let y = y - s.cy
  let zsq = s.r * s.r - (x * x + y * y)
  if zsq >= 0:
    let zsqrt = sqrt(zsq.toFloat)
    result = (s.cz.toFloat - zsqrt, s.cz.toFloat, true)
  else:
    result = (0.0, 0.0, false)

#---------------------------------------------------------------------------------------------------

func deathStar(pos, neg: Sphere; k, amb: float; dir: Vector): GrayImage =

  let w = pos.r * 4
  let h = pos.r * 3
  result = newGrayImage(w, h)
  var vect: Vector
  let deltaX = pos.cx - w div 2
  let deltaY = pos.cy - h div 2

  let xMax = pos.cx + pos.r
  let yMax = pos.cy + pos.r
  for y in (pos.cy - pos.r)..yMax:
    for x in (pos.cx - pos.r)..xMax:
      let (zb1, zb2, posHit) = pos.hit(x, y)
      if not posHit: continue
      var (zs1, zs2, negHit) = neg.hit(x, y)
      if negHit:
        if zs1 > zb1: negHit = false
        elif zs2 > zb2: continue
      if negHit:
        vect[0] = (neg.cx - x).toFloat
        vect[1] = (neg.cy - y).toFloat
        vect[2] = neg.cz.toFloat - zs2
      else:
        vect[0] = (x - pos.cx).toFloat
        vect[1] = (y - pos.cy).toFloat
        vect[2] = zb1 - pos.cz.toFloat
      vect.normalize()
      var s = dot(dir, vect)
      if s < 0: s = 0
      var lum = (255 * (s.pow(k) + amb) / (1 + amb)).toInt
      if lum < 0: lum = 0
      elif lum > 255: lum = 255
      result[x - deltaX, y - deltaY] = Luminance(lum)

#———————————————————————————————————————————————————————————————————————————————————————————————————

var dir: Vector = [float 20, -40, -10]
dir.normalize()
let pos = Sphere(cx: 0, cy: 0, cz: 0, r: 120)
let neg = Sphere(cx: -90, cy: -90, cz: -30, r: 100)

let grayImage = deathStar(pos, neg, 1.5, 0.2, dir)

# Save to PNG. We convert to an RGB image then transform the pixels
# in a sequence of bytes (actually a copy) in order to call "savePNG24".
let rgbImage = grayImage.toImage
var data = newSeqOfCap[byte](rgbImage.pixels.len * 3)
for color in rgbImage.pixels:
  data.add([color.r, color.g, color.b])
echo savePNG24("death_star.png", data, rgbImage.w, rgbImage.h)

Openscad

// We are performing geometric subtraction

difference() {

  // Create the primary sphere of radius 60 centred at the origin

  translate(v = [0,0,0]) {
    sphere(60);
  }

  /*Subtract an overlapping sphere with a radius of 40
     The resultant hole will be smaller than this, because we only
     only catch the edge
  */

  translate(v = [0,90,0]) {
    sphere(40);
  }
}

Perl

Writes a PGM to stdout.

use strict;

sub sq {
	my $s = 0;
	$s += $_ ** 2 for @_;
	$s;
}

sub hit {
	my ($sph, $x, $y) = @_;
	$x -= $sph->[0];
	$y -= $sph->[1];

	my $z = sq($sph->[3]) - sq($x, $y);
	return	if $z < 0;

	$z = sqrt $z;
	return $sph->[2] - $z, $sph->[2] + $z;
}

sub normalize {
	my $v = shift;
	my $n = sqrt sq(@$v);
	$_ /= $n for @$v;
	$v;
}

sub dot {
	my ($x, $y) = @_;
	my $s = $x->[0] * $y->[0] + $x->[1] * $y->[1] + $x->[2] * $y->[2];
	$s > 0 ? $s : 0;
}

my $pos = [ 120, 120, 0, 120 ];
my $neg = [ -77, -33, -100, 190 ];
my $light = normalize([ -12, 13, -10 ]);
sub draw {
	my ($k, $amb) = @_;
	binmode STDOUT, ":raw";
	print "P5\n", $pos->[0] * 2 + 3, " ", $pos->[1] * 2 + 3, "\n255\n";
	for my $y (($pos->[1] - $pos->[3] - 1) .. ($pos->[1] + $pos->[3] + 1)) {
		my @row = ();
		for my $x (($pos->[0] - $pos->[3] - 1) .. ($pos->[0] + $pos->[3] + 1)) {
			my ($hit, @hs) = 0;
			my @h = hit($pos, $x, $y);

			if (!@h) { $hit = 0 }
			elsif (!(@hs = hit($neg, $x, $y))) { $hit = 1 }
			elsif ($hs[0] > $h[0]) { $hit = 1 }
			elsif ($hs[1] > $h[0]) { $hit = $hs[1] > $h[1] ? 0 : 2 }
			else { $hit = 1 }

			my ($val, $v);
			if ($hit == 0) { $val = 0 }
			elsif ($hit == 1) {
				$v = [	$x - $pos->[0],
					$y - $pos->[1],
					$h[0] - $pos->[2] ];
			} else {
				$v = [	$neg->[0] - $x,
					$neg->[1] - $y,
					$neg->[2] - $hs[1] ];
			}
			if ($v) {
				normalize($v);
				$val = int((dot($v, $light) ** $k + $amb) * 255);
				$val = ($val > 255) ? 255 : ($val < 0) ? 0 : $val;
			}
			push @row, $val;
		}
		print pack("C*", @row);
	}
}

draw(2, 0.2);

Phix

Translation of: Go
Library: Phix/pGUI
Library: Phix/online

You can run this online here. Note it is rather slow to redraw fullscreen.

--
-- demo\rosetta\DeathStar.exw
-- ==========================
--
--  Translated from Go.
--
with javascript_semantics
include pGUI.e

constant title = "Death Star"
Ihandle dlg, canvas
cdCanvas cddbuffer, cdcanvas

function dot(sequence x, sequence y)
    return sum(sq_mul(x,y))
end function

function normalize(sequence v)
    atom len = sqrt(dot(v, v))
    if len=0 then return {0,0,0} end if
    return sq_mul(v,1/len)
end function

enum X,Y,Z

function hit(sequence s, atom x, y, r)
    x -= s[X]
    y -= s[Y]
    atom zsq := r*r - (x*x + y*y)
    if zsq >= 0 then
        atom zsqrt := sqrt(zsq)
        return {s[Z] - zsqrt, s[Z] + zsqrt, true}
    end if
    return {0, 0, false}
end function
 
procedure deathStar(integer width, height, atom k, atom amb, sequence direction)

    atom t0 = time()+1, t1 = t0,
         lmul = 255/(1+amb)
    integer r = floor((min(width,height)-40)/2),
           cx = floor(width/2),
           cy = floor(height/2)
    sequence pos = {0,0,0},
             neg = {r*-3/4,r*-3/4,r*-1/4}

    for y = -r to +r do
        if time()>t1 then
            -- Let the user know we aren't completely dead just yet
            IupSetStrAttribute(dlg,"TITLE","%s - drawing (%d%%)",{title,100*(y+r)/(2*r)})
            t1 = time()+1
            --
            -- Hmm, not entirely sure why this is needed, but without it 
            --  after ~7 seconds the window gets a "(Not Responding)" and
            --  then something decides to force a full repaint, which at 
            --  fullscreen will never finish in < 7s on this ancient box.
            -- I suppose this is the corrollary to the above, this time
            --  letting Windows 10 know the process is not quite dead...
            --  Currently and possibly forever neither of these routines
            --  exist in pGUI.js, the browser is more forgiving anyway.
            --
            if platform()!=JS then
                if IupLoopStep()=IUP_CLOSE then
                    IupExitLoop()
                    exit
                end if
            end if
        end if
        for x = -r to +r do
            atom {zb1, zb2, hit1} := hit(pos, x, y, r)
            if hit1 then
                atom {zs1, zs2, hit2} := hit(neg, x, y, r/2)
                if not hit2 or zs2<=zb2 then
                    bool dish = hit2 and zs1<=zb1
                    sequence vec = iff(dish?sq_sub(neg,{x,y,zs2}):{x,y,zb1})
                    atom s = dot(direction, normalize(vec)),
                         l = iff(s<=0?0:power(s,k))
                    integer lum = and_bits(#FF,lmul*(l+amb))
                    cdCanvasPixel(cddbuffer, cx+x, cy-y, lum*#10101)
                end if
            end if
        end for
    end for
    if t1!=t0 then
        IupSetStrAttribute(dlg,"TITLE",title)
    end if
end procedure

function redraw_cb(Ihandle /*ih*/, integer /*posx*/, /*posy*/)
    integer {width, height} = IupGetIntInt(canvas, "DRAWSIZE")
    cdCanvasActivate(cddbuffer)
    cdCanvasClear(cddbuffer) 
    deathStar(width, height, 1.5, 0.2, normalize({20, -40, -10}))
    cdCanvasFlush(cddbuffer)
    return IUP_DEFAULT
end function

function map_cb(Ihandle ih)
    cdcanvas = cdCreateCanvas(CD_IUP, ih)
    cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
    cdCanvasSetBackground(cddbuffer, CD_BLACK)
    return IUP_DEFAULT
end function

procedure main()
    IupOpen()
    canvas = IupCanvas("RASTERSIZE=340x340")
    IupSetCallbacks(canvas, {"MAP_CB", Icallback("map_cb"),
                             "ACTION", Icallback("redraw_cb")})
    dlg = IupDialog(canvas,`TITLE="%s"`,{title})

    IupMap(dlg)
    IupSetAttribute(canvas, "RASTERSIZE", NULL) -- release the minimum limitation
    IupShow(dlg)
    if platform()!=JS then
        IupMainLoop()
        IupClose()
    end if
end procedure

main()

POV-Ray

camera { perspective location  <0.0 , .8 ,-3.0> look_at 0
         aperture .1 blur_samples 20 variance 1/100000 focal_point 0}
                            
light_source{< 3,3,-3> color rgb 1}

sky_sphere { pigment{ color rgb <0,.2,.5>}}

plane {y,-5 pigment {color rgb .54} normal {hexagon} }

difference {
 sphere { 0,1 }
 sphere { <-1,1,-1>,1 }
  texture { 
    pigment{ granite } 
    finish { phong 1 reflection {0.10 metallic 0.5} }
  } 
}

Python

Translation of: C
import sys, math, collections

Sphere = collections.namedtuple("Sphere", "cx cy cz r")
V3 = collections.namedtuple("V3", "x y z")

def normalize((x, y, z)):
    len = math.sqrt(x**2 + y**2 + z**2)
    return V3(x / len, y / len, z / len)

def dot(v1, v2):
    d = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z
    return -d if d < 0 else 0.0

def hit_sphere(sph, x0, y0):
    x = x0 - sph.cx
    y = y0 - sph.cy
    zsq = sph.r ** 2 - (x ** 2 + y ** 2)
    if zsq < 0:
        return (False, 0, 0)
    szsq = math.sqrt(zsq)
    return (True, sph.cz - szsq, sph.cz + szsq)

def draw_sphere(k, ambient, light):
    shades = ".:!*oe&#%@"
    pos = Sphere(20.0, 20.0, 0.0, 20.0)
    neg = Sphere(1.0, 1.0, -6.0, 20.0)

    for i in xrange(int(math.floor(pos.cy - pos.r)),
                    int(math.ceil(pos.cy + pos.r) + 1)):
        y = i + 0.5
        for j in xrange(int(math.floor(pos.cx - 2 * pos.r)),
                        int(math.ceil(pos.cx + 2 * pos.r) + 1)):
            x = (j - pos.cx) / 2.0 + 0.5 + pos.cx

            (h, zb1, zb2) = hit_sphere(pos, x, y)
            if not h:
                hit_result = 0
            else:
                (h, zs1, zs2) = hit_sphere(neg, x, y)
                if not h:
                    hit_result = 1
                elif zs1 > zb1:
                    hit_result = 1
                elif zs2 > zb2:
                    hit_result = 0
                elif zs2 > zb1:
                    hit_result = 2
                else:
                    hit_result = 1

            if hit_result == 0:
                sys.stdout.write(' ')
                continue
            elif hit_result == 1:
                vec = V3(x - pos.cx, y - pos.cy, zb1 - pos.cz)
            elif hit_result == 2:
                vec = V3(neg.cx-x, neg.cy-y, neg.cz-zs2)
            vec = normalize(vec)

            b = dot(light, vec) ** k + ambient
            intensity = int((1 - b) * len(shades))
            intensity = min(len(shades), max(0, intensity))
            sys.stdout.write(shades[intensity])
        print

light = normalize(V3(-50, 30, 50))
draw_sphere(2, 0.5, light)

Q

write an image in BMP format:

/ https://en.wikipedia.org/wiki/BMP_file_format
/ BITMAPINFOHEADER / RGB24

/ generate a header

genheader:{[w;h]
   0x424d, "x"$(f2i4[54+4*h*w],0,0,0,0,54,0,0,0,40,0,0,0,
                f2i4[h],f2i4[w],1,0,24,0,0,0,0,0,
                f2i4[h*((w*3)+((w*3)mod 4))],
                19,11,0,0,19,11,0,0,0,0,0,0,0,0,0,0)};

/ generate a raster line at a vertical position

genrow:{[w;y;fcn]
    row:enlist 0i;xx:0i;do[w;row,:fcn[xx;y];xx+:1i];row,:((w mod 4)#0i);1_row};

/ generate a bitmap

genbitmap:{[w;h;fcn]
    ary:enlist 0i;yy:0i;do[h;ary,:genrow[w;yy;fcn];yy+:1i];"x"$1_ary};

/ deal with endianness
/ might need to reverse last line if host computer is not a PC

f2i4:{[x] r:x;
  s0:r mod 256;r-:s0; r%:256;
  s1:r mod 256;r-:s1; r%:256;
  s2:r mod 256;r-:s2; r%:256;
  s3:r mod 256;
  "h"$(s0,s1,s2,s3)}

/ compose and write a file

writebmp:{[w;h;fcn;fn] 
    fn 1: (genheader[h;w],genbitmap[w;h;fcn])};

/ / usage example:
/ w:400;
/ h:300;
/ fcn:{x0:x-w%2;y0:y-h%2;r:175;$[(r*r)>((x0*x0)+(y0*y0));(0;0;255);(0;255;0)]};
/ fn:`:demo.bmp;
/ writebmp[w;h;fcn;fn];

Create the death star image:

w:400; h:300; r:150; l:-0.5 0.7 0.5
sqrt0:{$[x>0;sqrt x;0]};

/ get x,y,z position of point on sphere given x,y,r

z:{[x;y;r]sqrt0((r*r)-((x*x)+(y*y)))};

/ get diffused light at point on sphere

is:{[x;y;r]
   z0:z[x;y;r];
   s:(x;y;z0)%r;
   $[z0>0;i:0.5*1+(+/)(s*l);i:0];
   i};

/ get pixel value at given image position

fcn:{[xpx;ypx]
   x:xpx-w%2;
   y:ypx-h%2;
   z1:z[x;y;r];
   x2:x+190;
   z2:170-z[x2;y;r];
   $[(r*r)<((x*x)+(y*y));
      $[y>-50;
          i:3#0;
          i:200 100 50];
      $[z2>z1;
         i:3#is[x;y;r]*140;
         i:3#is[(-1*x2);(-1*y);r]*120]
   ];
   "i"$i};

/ do it ...

\l bmp.q
fn:`:demo.bmp;
writebmp[w;h;fcn;fn];

(converted to JPG ...)

Racket

#lang racket
(require plot)
(plot3d (polar3d (λ (φ θ) (real-part (- (sin θ) (sqrt (- (sqr 1/3) (sqr (cos θ)))))))
                 #:samples 100 #:line-style 'transparent #:color 9)
        #:altitude 60 #:angle 80
        #:height  500 #:width 400
        #:x-min  -1/2 #:x-max 1/2
        #:y-min  -1/2 #:y-max 1/2
        #:z-min     0 #:z-max 1)

Raku

(formerly Perl 6)

Translation of: C

Reimplemented to output a .pgm image.

Works with: Rakudo version 2018.10
class sphere {
   has $.cx; # center x coordinate
   has $.cy; # center y coordinate
   has $.cz; # center z coordinate
   has $.r;  # radius
}

my $depth = 255;     # image color depth

my $width = my $height = 255; # dimensions of generated .pgm; must be odd

my $s = ($width - 1)/2;  # scaled dimension to build geometry

my @light = normalize([ 4, -1, -3 ]);

# positive sphere at origin
my $pos = sphere.new(
    cx => 0,
    cy => 0,
    cz => 0,
    r  => $s.Int
);

# negative sphere offset to upper left
my $neg = sphere.new(
    cx => (-$s*.90).Int,
    cy => (-$s*.90).Int,
    cz => (-$s*.3).Int,
    r  => ($s*.7).Int
);

sub MAIN ($outfile = 'deathstar-perl6.pgm') {
    spurt $outfile, ("P5\n$width $height\n$depth\n"); # .pgm header
    my $out = open( $outfile, :a, :bin ) orelse .die;
    say 'Working...';
    $out.write( Blob.new( |draw_ds(3, .15) ) );
    say 'File written.';
    $out.close;
}

sub draw_ds ( $k, $ambient ) {
    my @pixels[$height];

    (($pos.cy - $pos.r) .. ($pos.cy + $pos.r)).race.map: -> $y {
        my @row[$width];
        (($pos.cx - $pos.r) .. ($pos.cx + $pos.r)).map: -> $x {
            # black if we don't hit positive sphere, ignore negative sphere
            if not hit($pos, $x, $y, my $posz) {
                @row[$x + $s] = 0;
                next;
            }
            my @vec;
            # is front of positive sphere inside negative sphere?
            if hit($neg, $x, $y, my $negz) and $negz.min < $posz.min < $negz.max {
                # make black if whole positive sphere eaten here
                if $negz.min < $posz.max < $negz.max { @row[$x + $s] = 0; next; }
                # render inside of negative sphere
                @vec = normalize([$neg.cx - $x, $neg.cy - $y, -$negz.max - $neg.cz]);
            }
            else {
                # render outside of positive sphere
                @vec = normalize([$x - $pos.cx, $y - $pos.cy,  $posz.max - $pos.cz]);
            }
            my $intensity = dot(@light, @vec) ** $k + $ambient;
            @row[$x + $s] = ($intensity * $depth).Int min $depth;
        }
         @pixels[$y + $s] = @row;
    }
    flat |@pixels.map: *.list;
}

# normalize a vector
sub normalize (@vec) { @vec »/» ([+] @vec »*« @vec).sqrt }

# dot product of two vectors
sub dot (@x, @y) { -([+] @x »*« @y) max 0 }

# are the coordinates within the radius of the sphere?
sub hit ($sphere, $x is copy, $y is copy, $z is rw) {
    $x -= $sphere.cx;
    $y -= $sphere.cy;
    my $z2 = $sphere.r * $sphere.r - $x * $x - $y * $y;
    return False if $z2 < 0;
    $z2 = $z2.sqrt;
    $z = $sphere.cz - $z2 .. $sphere.cz + $z2;
    True;
}

REXX

Translation of: D

(Apologies for the comments making the lines so wide, but it was easier to read and compare to the original   D   source.)

/*REXX program displays a sphere with another sphere subtracted where it's superimposed.*/
call deathStar   2,   .5,   v3('-50  30  50')
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
dot:   #=0;  do j=1  for words(x);  #=# + word(x,j)*word(y,j);  end; return #
dot.:  procedure; parse arg x,y; d=dot(x,y); if d<0  then return -d; return 0
ceil:  procedure; parse arg x;   _=trunc(x);                         return _+(x>0)*(x\=_)
floor: procedure; parse arg x;   _=trunc(x);                         return _-(x<0)*(x\=_)
v3:    procedure; parse arg a b c;      #=sqrt(a**2 + b**2 + c**2);  return a/#  b/#  c/#
/*──────────────────────────────────────────────────────────────────────────────────────*/
sqrt:  procedure; parse arg x; if x=0  then return 0;  d=digits();  h= d+6; numeric digits
       m.=9; numeric form; parse value format(x,2,1,,0) 'E0' with g 'E' _ .; g=g*.5'e'_%2
         do j=0  while h>9;      m.j= h;              h= h % 2 + 1;    end /*j*/
         do k=j+5  to 0  by -1;  numeric digits m.k;  g= (g +x/g)* .5; end /*k*/; return g
/*──────────────────────────────────────────────────────────────────────────────────────*/
hitSphere: procedure expose !.; parse arg xx yy zz r,x0,y0;  z= r*r -(x0-xx)**2-(y0-yy)**2
           if z<0  then return 0;  _= sqrt(z);  !.z1= zz - _;    !.z2= zz + _;    return 1
/*──────────────────────────────────────────────────────────────────────────────────────*/
deathStar: procedure; parse arg k,ambient,sun    /* [↓]  display the deathstar to screen*/
parse var  sun   s1 s2 s3                        /*identify the light source coördinates*/
if 5=="f5"x  then shading= '.:!*oe&#%@'          /*dithering chars for an EBCDIC machine*/
             else shading= '·:!ºoe@░▒▓'          /*    "       "    "   "  ASCII    "   */
shadingL= length(shading)                        /*the number of dithering characters.  */
shades.= ' ';            do i=1  for shadingL;    shades.i= substr(shading, i, 1)
                         end   /*i*/
ship=  20   20  0 20  ;           parse var  ship    shipX  shipY  shipZ  shipR
hole= ' 1    1 -6 20' ;           parse var  hole    holeX  holeY  holeZ  .

  do   i=floor(shipY-shipR  )  to ceil(shipY+shipR  )+1;    y= i +.5;   @= /*@   is a single line of the deathstar to be displayed.*/
    do j=floor(shipX-shipR*2)  to ceil(shipX+shipR*2)+1;    !.= 0
    x=.5 * (j-shipX+1) + shipX;       $bg= 0;    $pos= 0;    $neg= 0       /*$BG,  $POS,  and  $NEG  are boolean values.           */
    ?= hitSphere(ship, x, y);                    b1= !.z1;   b2= !.z2      /*?  is boolean,  "true"  indicates ray hits the sphere.*/
                                                                           /*$BG:  if 1, its background;  if zero, it's foreground.*/
    if \? then $bg= 1                                                      /*ray lands in blank space, so draw the background.     */
          else do; ?= hitSphere(hole, x, y);     s1= !.z1;   s2= !.z2
               if \? then $pos= 1                                          /*ray hits ship but not the hole, so draw ship surface. */
                     else if s1>b1 then $pos=1                             /*ray hits both, but ship front surface is closer.      */
                                   else if s2>b2 then $bg= 1               /*ship surface is inside hole,  so show the background. */
                                                 else if s2>b1 then $neg=1 /*hole back surface is inside ship;  the only place ··· */
                                                               else $pos=1 /*························ a hole surface will be shown.*/
               end
        select
        when $bg   then do;   @= @' ';    iterate j;     end               /*append a blank character to the line to be displayed. */
        when $pos  then vec_= v3(x-shipX  y-shipY  b1-shipZ)
        when $neg  then vec_= v3(holeX-x  holeY-y  holeZ-s2)
        end    /*select*/

    b=1 +min(shadingL, max(0, trunc((1 - (dot.(sun, v3(vec_))**k + ambient)) * shadingL)))
    @=@ || shades.b                                 /*B:  the ray's intensity│brightness*/
    end      /*j*/                                  /* [↑]  build a line for the sphere.*/

  if @\=''  then say strip(@, 'T')                  /*strip trailing blanks from line.  */
  end        /*i*/                                  /* [↑]  show all lines for sphere.  */
return
output   when using the internal default input:

(Shown at   1/2   size.)

                                    eeeee:::::::
                                eeeeeeeee··············
                             ooeeeeeeeeee··················
                           ooooeeeeeeeee······················
                        oooooooeeeeeeee··························
                      ooooooooooeeeee······························
                    ººooooooooooeeee·································
                  ººººooooooooooee·····································
                !ºººººooooooooooe·······································
              !!!ºººººooooooooo:··········································
            :!!!!ºººººooooooo:::···········································
          :::!!!!ºººººooooo!:::::···········································
        ::::!!!!!ºººººooo!!!!::::············································
       ·::::!!!!ºººººooº!!!!!::::············································
     ···::::!!!!ººººººººº!!!!:::::············································
    ···::::!!!!ººººoººººº!!!!!::::············································
  ····::::!!!!ºººoooºººººº!!!!!::::············································
 ····::::!!!!ºoooooooººººº!!!!!:::::···········································
···::::!!!!!ooooooooooººººº!!!!!:::::··········································
:::::!!!!eeoooooooooooºººººº!!!!!:::::·········································
!!!!!eeeeeeeoooooooooooºººººº!!!!!:::::········································
eeeeeeeeeeeeooooooooooooºººººº!!!!!:::::·······································
eeeeeeeeeeeeeooooooooooooºººººº!!!!!!:::::·····································
eeeeeeeeeeeeeeooooooooooooºººººº!!!!!!:::::····································
 eeeeeeeeeeeeeeooooooooooooººººººº!!!!!!:::::·································
 eeeeeeeeeeeeeeeoooooooooooooºººººº!!!!!!::::::······························:
  eeeeeeeeeeeeeeeoooooooooooooººººººº!!!!!!:::::::··························:
  eeeeeeeeeeeeeeeeooooooooooooooººººººº!!!!!!!:::::::·····················::!
   eeeeeeeeeeeeeeeeeoooooooooooooºººººººº!!!!!!!:::::::::··············::::!
    eeeeeeeeeeeeeeeeeooooooooooooooºººººººº!!!!!!!!::::::::::::::::::::::!º
     eeeeeeeeeeeeeeeeeeoooooooooooooooºººººººº!!!!!!!!!!:::::::::::::!!!!º
       eeeeeeeeeeeeeeeeeooooooooooooooooºººººººººº!!!!!!!!!!!!!!!!!!!!!º
        eeeeeeeeeeeeeeeeeeoooooooooooooooooºººººººººººº!!!!!!!!!!!!ºººº
          eeeeeeeeeeeeeeeeeeooooooooooooooooooººººººººººººººººººººººo
            eeeeeeeeeeeeeeeeeeeoooooooooooooooooooooººººººººººººooo
              eeeeeeeeeeeeeeeeeeeeooooooooooooooooooooooooooooooo
                 eeeeeeeeeeeeeeeeeeeeooooooooooooooooooooooooo
                    eeeeeeeeeeeeeeeeeeeeeoooooooooooooooooo
                        eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
                               eeeeeeeeeeeeeeeee

Set lang

set ! 32
set ! 32
set ! 46
set ! 45
set ! 126
set ! 34
set ! 34
set ! 126
set ! 45
set ! 46
set ! 10
set ! 46
set ! 39
set ! 40
set ! 95
set ! 41
set ! 32
set ! 32
set ! 32
set ! 32
set ! 32
set ! 39
set ! 46
set ! 10
set ! 124
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 61
set ! 124
set ! 10
set ! 39
set ! 46
set ! 32
set ! 32
set ! 32
set ! 32
set ! 32
set ! 32
set ! 32
set ! 32
set ! 46
set ! 39
set ! 10
set ! 32
set ! 32
set ! 126
set ! 45
set ! 46
set ! 95
set ! 95
set ! 46
set ! 45
set ! 126

Outputs:

  .-~""~-.
.'(_)     '.
|==========|
'.        .'
  ~-.__.-~

(it's the best I could do!)

Sidef

Translation of: Perl

Writes a PGM to stdout.

func hitf(sph, x, y) {
    x -= sph[0]
    y -= sph[1]

    var z = (sph[3]**2 - (x**2 + y**2))

    z < 0 && return nil

    z.sqrt!
    [sph[2] - z, sph[2] + z]
}

func normalize(v) {
    v / v.abs
}

func dot(x, y) {
    max(0, x*y)
}

var pos = [120, 120, 0, 120]
var neg = [-77, -33, -100, 190]
var light = normalize(Vector(-12, 13, -10))

func draw(k, amb) {
    STDOUT.binmode(':raw')
    print ("P5\n", pos[0]*2 + 3, " ", pos[1]*2 + 3, "\n255\n")

    for y in ((pos[1] - pos[3] - 1) .. (pos[1] + pos[3] + 1)) {
        var row = []
        for x in ((pos[0] - pos[3] - 1) .. (pos[0] + pos[3] + 1)) {

            var hit = 0
            var hs = []
            var h = hitf(pos, x, y)

            if    (!h)                      { hit = 0; h  = [0, 0] }
            elsif (!(hs = hitf(neg, x, y))) { hit = 1; hs = [0, 0] }
            elsif (hs[0] > h[0])            { hit = 1 }
            elsif (hs[1] > h[0])            { hit = (hs[1] > h[1] ? 0 : 2) }
            else                            { hit = 1 }

            var (val, v)

            given(hit) {
                when (0) { val = 0}
                when (1) { v = Vector(x-pos[0], y-pos[1], h[0]-pos[2]) }
                default  { v = Vector(neg[0]-x, neg[1]-y, neg[2]-hs[1]) }
            }

            if (defined(v)) {
                v = normalize(v)
                val = int((dot(v, light)**k + amb) * 255)
                val = (val > 255 ? 255 : (val < 0 ? 0 : val))
            }
            row.append(val)
        }
        print 'C*'.pack(row...)
    }
}

draw(2, 0.2)

Output image: here.

Tcl

Translation of: C

Note that this code has a significant amount of refactoring relative to the C version, including the addition of specular reflections and the separation of the scene code from the raytracing from the rendering.

package require Tcl 8.5

proc normalize vec {
    upvar 1 $vec v
    lassign $v x y z
    set len [expr {sqrt($x**2 + $y**2 + $z**2)}]
    set v [list [expr {$x/$len}] [expr {$y/$len}] [expr {$z/$len}]]
    return
}

proc dot {a b} {
    lassign $a ax ay az
    lassign $b bx by bz
    return [expr {-($ax*$bx + $ay*$by + $az*$bz)}]
}

# Intersection code; assumes that the vector is parallel to the Z-axis
proc hitSphere {sphere x y z1 z2} {
    dict with sphere {
	set x [expr {$x - $cx}]
	set y [expr {$y - $cy}]
	set zsq [expr {$r**2 - $x**2 - $y**2}]
	if {$zsq < 0} {return 0}
	upvar 1 $z1 _1 $z2 _2
	set zsq [expr {sqrt($zsq)}]
	set _1 [expr {$cz - $zsq}]
	set _2 [expr {$cz + $zsq}]
	return 1
    }
}

# How to do the intersection with our scene
proc intersectDeathStar {x y vecName} {
    global big small
    if {![hitSphere $big $x $y zb1 zb2]} {
	# ray lands in blank space
	return 0
    }
    upvar 1 $vecName vec
    # ray hits big sphere; check if it hit the small one first
    set vec [if {
	![hitSphere $small $x $y zs1 zs2] || $zs1 > $zb1 || $zs2 <= $zb1
    } then {
	dict with big {
	    list [expr {$x - $cx}] [expr {$y - $cy}] [expr {$zb1 - $cz}]
	}
    } else {
	dict with small {
	    list [expr {$cx - $x}] [expr {$cy - $y}] [expr {$cz - $zs2}]
	}
    }]
    normalize vec
    return 1
}

# Intensity calculators for different lighting components
proc diffuse {k intensity L N} {
    expr {[dot $L $N] ** $k * $intensity}
}
proc specular {k intensity L N S} {
    # Calculate reflection vector
    set r [expr {2 * [dot $L $N]}]
    foreach l $L n $N {lappend R [expr {$l-$r*$n}]}
    normalize R
    # Calculate the specular reflection term
    return [expr {[dot $R $S] ** $k * $intensity}]
}

# Simple raytracing engine that uses parallel rays
proc raytraceEngine {diffparms specparms ambient intersector shades renderer fx tx sx fy ty sy} {
    global light
    for {set y $fy} {$y <= $ty} {set y [expr {$y + $sy}]} {
	set line {}
	for {set x $fx} {$x <= $tx} {set x [expr {$x + $sx}]} {
	    if {![$intersector $x $y vec]} {
		# ray lands in blank space
		set intensity end
	    } else {
		# ray hits something; we've got the normalized vector
		set b [expr {
		    [diffuse {*}$diffparms $light $vec]
		    + [specular {*}$specparms $light $vec {0 0 -1}]
		    + $ambient
		}]
		set intensity [expr {int((1-$b) * ([llength $shades]-1))}]
		if {$intensity < 0} {
		    set intensity 0
		} elseif {$intensity >= [llength $shades]-1} {
		    set intensity end-1
		}
	    }
	    lappend line [lindex $shades $intensity]
	}
	{*}$renderer $line
    }
}

# The general scene settings
set light {-50 30 50}
set big   {cx 20 cy 20 cz 0   r 20}
set small {cx 7  cy 7  cz -10 r 15}
normalize light

# Render as text
proc textDeathStar {diff spec lightBrightness ambient} {
    global big
    dict with big {
	raytraceEngine [list $diff $lightBrightness] \
	    [list $spec $lightBrightness] $ambient intersectDeathStar \
	    [split ".:!*oe&#%@ " {}] {apply {l {puts [join $l ""]}}} \
	    [expr {$cx+floor(-$r)}] [expr {$cx+ceil($r)+0.5}] 0.5 \
	    [expr {$cy+floor(-$r)+0.5}] [expr {$cy+ceil($r)+0.5}] 1
    }
}
textDeathStar 3 10 0.7 0.3

Output:

                                #######&eeeeeeeee                                 
                         ee&&&&&&########%eeoooooooooooe                          
                     **oooee&&&&&&########%ooooo**********oo                      
                  !!!***oooee&&&&&&########%********!!!!!!!!***                   
               !!!!!!!****ooee&&&&&&#######%*****!!!!!!!!!!!!!!!**                
             ::::!!!!!!***oooee&&&&&&######***!!!!!!!::::::::::::!!*              
           :::::::!!!!!!***ooeee&&&&&&#####**!!!!!!:::::::::::::::::!*            
         ::::::::::!!!!!***oooee&&&&&&####*!!!!!!::::::::.........::::!*          
        ::::::::::!!!!!!***oooeee&&&&&&###!!!!!!:::::::..............:::!         
      ..:::::::::!!!!!!****oooeee&&&&&&##!!!!!!::::::..................::!*       
     ...::::::::!!!!!!****ooooeee&&&&&&!!!!!!:::::::....................::!*      
    ....::::::!!!!!!*****ooooeeee&&&&&!!!!!!:::::::......................::!*     
   ....::::::!!!!!*****oooooeeeee&&&&!!!!!!::::::::.......................::!*    
   ...::::::!!!!!*****oooooeeeee&&&!!!!!!:::::::::.........................::!    
  ...:::::!!!!!*****oooooeeeeee&&!!!!!!!:::::::::..........................::!*   
  ..:::::!!!!!****oooooeeeeee&&&!!!!!!!::::::::::..........................::!!   
 .::::::!!!!*****ooooeeeeee&&*!!!!!!!::::::::::::.........................:::!!*  
 :::::!!!!!****oooooeeeee&&**!!!!!!!::::::::::::::.......................::::!!*  
 !!!!!!!!****oooooeeeee&****!!!!!!!::::::::::::::::::..................::::::!!*  
 #!!!******oooooeeeeeoo*****!!!!!!!:::::::::::::::::::::::::::::::::::::::::!!!*  
 ##oooooooooooeeeeeeoooo****!!!!!!!:::::::::::::::::::::::::::::::::::::::!!!!**  
 %#####eeee&&&&&&&eeeooo****!!!!!!!!:::::::::::::::::::::::::::::::::::!!!!!!**o  
 %#########&&&&&&&&eeeooo****!!!!!!!!!::::::::::::::::::!!!!!!!!!!!!!!!!!!!****o  
 %##########&&&&&&&&eeeooo****!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!****ooe  
  %##########&&&&&&&&eeeooo*****!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!**********ooo   
  %%##########&&&&&&&&eeeoooo*****!!!!!!!!!!!!!!!!!!!*********************ooooe   
   %%##########&&&&&&&&eeeoooo***************************************oooooooee    
   @%###########&&&&&&&&&eeeooooo*************************ooooooooooooooooeee&    
    @%###########&&&&&&&&&eeeeoooooo*************ooooooooooooooooooooooeeeee&     
     @%%##########&&&&&&&&&&eeeeoooooooooooooooooooooooooooooooeeeeeeeeeee&&      
      @%%###########&&&&&&&&&&eeeeeoooooooooooooooooooeeeeeeeeeeeeeeeeee&&&       
        %%############&&&&&&&&&&eeeeeeeeeeooeeeeeeeeeeeeeeeeeeeeeeee&&&&&         
         @%%###########&&&&&&&&&&&&eeeeeeeeeeeeeeeeeeeeeeeeee&&&&&&&&&&&          
           %%############&&&&&&&&&&&&&&eeeeeeeeeeeeeee&&&&&&&&&&&&&&&&            
             %%############&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&              
               %%#############&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                
                  %%#############&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                   
                     %##############&&&&&&&&&&&&&&&&&&&&&&&&                      
                         %##############&&&&&&&&&&&&&&&&                          
                                #################                                 

To render it as an image, we just supply different code to map the intensities to displayable values:

Library: Tk
Rendering of the Death Star by the Tcl solution.
# Render as a picture (with many hard-coded settings)
package require Tk
proc guiDeathStar {photo diff spec lightBrightness ambient} {
    set row 0
    for {set i 255} {$i>=0} {incr i -1} {
	lappend shades [format "#%02x%02x%02x" $i $i $i]
    }
    raytraceEngine [list $diff $lightBrightness] \
	[list $spec $lightBrightness] $ambient intersectDeathStar \
	$shades {apply {l {
	    upvar 2 photo photo row row
	    $photo put [list $l] -to 0 $row
	    incr row
	    update
	}}} 0 40 0.0625 0 40 0.0625
}
pack [label .l -image [image create photo ds]]
guiDeathStar ds 3 10 0.7 0.3

VBScript

ASCII graphics. Should be invoked with cscript. Modified from LUA

'deathstar ascii graphics

option explicit               

const x_=0
const y_=1
const z_=2
const r_=3

function clamp(x,b,t) 
  if x<b then 
     clamp=b 
  elseif x>t then
    clamp =t 
  else 
    clamp=x 
  end if 
end function

function dot(v,w) dot=v(x_)*w(x_)+v(y_)*w(y_)+v(z_)*w(z_): end function

function normal (byval v) 
    dim ilen:ilen=1/sqr(dot(v,v)): 
    v(x_)=v(x_)*ilen: v(y_)=v(y_)*ilen: v(z_)=v(z_)*ilen:
    normal=v:
end function

function hittest(s,x,y)
   dim z
   z = s(r_)^2 - (x-s(x_))^2 - (y-s(y_))^2
   if z>=0  then
     z=sqr(z)
     hittest=array(s(z_)-z,s(z_)+z)
   else
     hittest=0
  end if
end function
            
sub deathstar(pos, neg, sun, k, amb)
  dim x,y,shades,result,shade,hp,hn,xx,b 
  shades=array(" ",".",":","!","*","o","e","&","#","%","@")
  for y = pos(y_)-pos(r_)-0.5 to pos(y_)+pos(r_)+0.5 
    for x = pos(x_)-pos(r_)-0.5 to pos(x_)+pos(r_)+.5
      hp=hittest (pos, x, y)
      hn=hittest(neg,x,y)
      if not  isarray(hp) then
         result=0
      elseif not isarray(hn) then
        result=1
      elseif hn(0)>hp(0)  then
        result=1        
      elseif  hn(1)>hp(1) then
        result=0
      elseif hn(1)>hp(0) then
        result=2
      else
        result=1
      end if

      shade=-1
      select case result
      case 0
        shade=0        
      case 1
        xx=normal(array(x-pos(x_),y-pos(y_),hp(0)-pos(z_)))
        'shade=clamp(1-dot(sun,xx)^k+amb,1,ubound(shades))
      case 2
        xx=normal(array(neg(x_)-x,neg(y_)-y,neg(z_)-hn(1)))
        'shade=clamp(1-dot(sun,xx)^k+amb,1,ubound(shades))
      end select
      if shade <>0 then
        b=dot(sun,xx)^k+amb
        shade=clamp((1-b) *ubound(shades),1,ubound(shades))        
      end if       
      wscript.stdout.write string(2,shades(shade))
    next
    wscript.stdout.write vbcrlf
  next
end sub

deathstar array(20, 20, 0, 20),array(10,10,-15,10), normal(array(-2,1,3)), 2, 0.1
Output:
                                 ####&&&&&&&&&&&&
                         %%######&&&&eeeeeeeeooooooooee&&
                     %%%%####&&&&eeeeeeoooooo************ooee
                   %%%%####%%%%%%eeoooooo******!!!!!!!!!!!!**oo
               %%%%ee&&&&####%%%%%%##oo****!!!!!!!!::::::::!!!!**oo
             %%%%ooooeeee&&####%%%%%%##**!!!!!!::::::::::::::::!!!!oo
           %%%%!!****ooee&&&&##%%%%%%##!!!!::::::::............::::!!**
         %%%%::::!!****ooee&&####%%%%%%&&!!::::....................::!!oo
         %%....::::!!**ooooee&&##%%%%%%##::::........................::!!
       %%........::::!!**ooee&&####%%%%##::::..........................::!!
     ##%%..........::!!**ooee&&&&##%%%%##::..............................::oo
     %%%%..........::!!!!**ooee&&##%%%%::::..............................::!!
   ##%%..............::!!**ooee&&##%%%%::::................................::oo
   ##%%..............::!!**ooee&&##%%%%::::................................::**
   %%%%............::::!!**oo&&&&##%%!!::::................................::!!
   %%%%............::!!**ooee&&##%%!!!!::::..................................!!
 ##%%%%%%........::::!!**ooee&&##**!!!!::::..................................::**
 ##%%%%%%!!::::::!!!!**ooee&&##****!!!!::::..................................::**
 ##%%%%%%%%**********ooee&&##oo****!!!!!!::::................................::**
 ##%%%%%%%%%%##eeeeee&&eeeeeeoooo****!!!!::::..............................::!!**
 ##%%%%%%%%%%######&&&&&&eeeeoooo****!!!!::::::............................::!!**
 ##%%%%%%%%%%%%######&&&&eeeeoooo******!!!!::::::..........................::!!oo
 &&##%%%%%%%%%%######&&&&eeeeeeoooo****!!!!!!::::::......................::::!!oo
 &&##%%%%%%%%%%######&&&&&&eeeeoooooo****!!!!!!::::::..................::::!!**ee
   ##%%%%%%%%%%%%######&&&&eeeeeeoooo******!!!!!!::::::::..........::::::!!!!**
   ##%%%%%%%%%%%%######&&&&&&eeeeeeoooo******!!!!!!::::::::::::::::::::!!!!**oo
   &&##%%%%%%%%%%%%######&&&&&&eeeeoooooo******!!!!!!!!::::::::::::!!!!!!**ooee
   ee##%%%%%%%%%%%%########&&&&eeeeeeoooooo********!!!!!!!!!!!!!!!!!!!!****oo&&
     &&##%%%%%%%%%%%%######&&&&&&eeeeeeoooooo**********!!!!!!!!!!!!******ooee
     ee##%%%%%%%%%%%%%%######&&&&&&eeeeeeoooooooo********************ooooee&&
       &&##%%%%%%%%%%%%########&&&&&&&&eeeeeeoooooooooo********ooooooooee&&
         ####%%%%%%%%%%%%########&&&&&&&&eeeeeeeeooooooooooooooooooeeee&&
         ee##%%%%%%%%%%%%%%##########&&&&&&&&eeeeeeeeeeeeeeeeeeeeeeee&&##
           &&##%%%%%%%%%%%%%%%%########&&&&&&&&&&eeeeeeeeeeeeee&&&&&&##
             &&##%%%%%%%%%%%%%%%%##########&&&&&&&&&&&&&&&&&&&&&&####
               &&##%%%%%%%%%%%%%%%%%%##############&&&&&&&&######%%
                   ####%%%%%%%%%%%%%%%%%%######################
                     &&##%%%%%%%%%%%%%%%%%%%%%%%%######%%%%%%
                         &&##%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                                 ##%%%%%%%%%%%%%%

Wren

Translation of: Go
Library: DOME
import "dome" for Window
import "graphics" for Canvas, Color, ImageData
import "math" for Vector

var Normalize = Fn.new{ |vec|
    var invLen = 1 / vec.dot(vec).sqrt
    vec.x = vec.x * invLen
    vec.y = vec.y * invLen
    vec.z = vec.z * invLen
}

class Sphere {
    construct new(cx, cy, cz, r) {
        _cx = cx
        _cy = cy
        _cz = cz
        _r  = r
    }

    cx { _cx }
    cy { _cy }
    cz { _cz }
    r  { _r  }

    hit(x, y) {
        x = x - _cx
        y = y - _cy
        var zsq = _r*_r - x*x - y*y
        if (zsq >= 0) {
            var zsqrt = zsq.sqrt
            return [_cz - zsqrt, _cz + zsqrt, true]
        }
        return [0, 0, false]
    }
}

class DeathStar {
    construct new(width, height) {
        Window.title = "Death star"
        Window.resize(width, height)
        Canvas.resize(width, height)
    }

    init() {
        Canvas.cls(Color.white)
        var dir = Vector.new(20, -40, 10)
        Normalize.call(dir)
        var pos = Sphere.new(220, 190, 220, 120)
        var neg = Sphere.new(130, 100, 190, 100)
        deathStar(pos, neg, 1.5, 0.2, dir)
    }

    deathStar(pos, neg, k, amb, dir) {
        var w = pos.r * 4
        var h = pos.r * 3
        var img = ImageData.create("deathStar", w, h)
        var vec = Vector.new(0, 0, 0)
        for (y in pos.cy - pos.r..pos.cy + pos.r) {
            for (x in pos.cx - pos.r..pos.cx + pos.r) {
                var res = pos.hit(x, y)
                var zb1 = res[0]
                var zb2 = res[1]
                var hit = res[2]
                if (!hit) continue
                res = neg.hit(x, y)
                var zs1 = res[0]
                var zs2 = res[1]
                hit = res[2]
                if (hit) {
                    if (zs1 > zb1) {
                        hit = false
                    } else if (zs2 > zb2) {
                        continue
                    }
                }
                if (hit) {
                    vec.x = neg.cx - x
                    vec.y = neg.cy - y
                    vec.z = neg.cz - zs2
                } else {
                    vec.x = x - pos.cx
                    vec.y = y - pos.cy
                    vec.z = zb1 - pos.cz
                }
                Normalize.call(vec)
                var s = dir.dot(vec)
                if (s < 0) s = 0
                var lum = 255 * (s.pow(k) + amb) / (1 + amb)
                lum = lum.clamp(0, 255)
                img.pset(x, y, Color.rgb(lum, lum, lum))
            }
        }
        img.draw(pos.cx - w/2, pos.cy - h/2)
        img.saveToFile("deathStar.png")
    }

    update() {
    }

    draw(alpha) {
    }
}

var Game = DeathStar.new(400, 400)

Yabasic

open window 100,100
window origin "cc"
backcolor 0,0,0
clear window

tonos = 100
interv = int(255 / tonos)
dim shades(tonos)

shades(1) = 255
for i = 2 to tonos
	shades(i) = shades(i-1) - interv
next i

dim light(3)

light(0) = 30
light(1) = 30
light(2) = -50


sub normalize(v())
    local long
	
    long = sqrt(v(0)*v(0) + v(1)*v(1) + v(2)*v(2))
    v(0) = v(0) / long
    v(1) = v(1) / long
    v(2) = v(2) / long
end sub

 
sub punto(x(), y())
    local d
        
    d = x(0)*y(0) + x(1)*y(1) + x(2)*y(2)
    if d < 0 then
    	return -d
    else
    	return 0
    end if
end sub


//* positive shpere and negative sphere */
dim pos(3)
dim neg(3)

// x, y, z, r

pos(0) = 10
pos(1) = 10
pos(2) = 0
pos(3) = 20

neg(0) = 0
neg(1) = 0
neg(2) = -5
neg(3) = 15


sub hit_sphere(sph(), x, y)
	local zsq
	
	x = x - sph(0)
	y = y - sph(1)
	zsq = sph(3) * sph(3) - (x * x + y * y)
	if (zsq < 0) then
		return 0
	else
		return sqrt(zsq)
	end if
end sub

 
sub draw_sphere(k, ambient)
    local i, j, intensity, hit_result, result, b, vec(3), x, y, zb1, zb2, zs1, zs2, ini1, fin1, ini2, fin2
	
    ini1 = int(pos(1) - pos(3))
    fin1 = int(pos(1) + pos(3) + .5)
    for i = ini1 to fin1
        y = i + .5
        ini2 = int(pos(0) - 2 * pos(3))
        fin2 = int(pos(0) + 2 * pos(3) + .5)
        for j = ini2 to fin2
            x = (j - pos(0)) / 2 + .5 + pos(0)
            
            // ray lands in blank space, draw bg
            result = hit_sphere(pos(), x, y)
            
            if not result then
		hit_result = 0

		//* ray hits pos sphere but not neg, draw pos sphere surface */
	    else
		zb1 = pos(2) - result
		zb2 = pos(2) + result
		result = hit_sphere(neg(), x, y)
		if not result then
		    hit_result = 1
		else
		    zs1 = neg(2) - result
		    zs2 = neg(2) + result
		    if (zs1 > zb1) then
			hit_result = 1
		    elseif (zs2 > zb2) then
			hit_result = 0
		    elseif (zs2 > zb1) then
			hit_result = 2
		    else
			hit_result = 1
		    end if
		end if
	    end if
	  
  	    if not hit_result then
  	        color 0,0,0
  	        dot x, y
  	    else
	        switch(hit_result)
	        case 1:
		    vec(0) = x - pos(0)
		    vec(1) = y - pos(1)
		    vec(2) = zb1 - pos(2)
		    break
	        default:
		    vec(0) = neg(0) - x
		    vec(1) = neg(1) - y
		    vec(2) = neg(2) - zs2
	        end switch
				
                normalize(vec())
                b = (punto(light(), vec())^k) + ambient
                intensity = (1 - b) * tonos
                if (intensity < 1) intensity = 1
                if (intensity > tonos) intensity = tonos
                color shades(intensity),shades(intensity),shades(intensity)
                dot x,y
            end if
        next j
    next i
end sub
 
 
ang = 0
 
while(true)
	//clear window
	light(1) = cos(ang * 2)
	light(2) = cos(ang)
	light(0) = sin(ang)
	normalize(light())
	ang = ang + .05

	draw_sphere(2, .3)
wend

Zig

Translation of: C

Primitive ray tracing. Writes a PGM to stdout.

const std = @import("std");
const Allocator = std.mem.Allocator;
pub fn main() !void {
    // buffer stdout --------------------------------------
    const stdout_file = std.io.getStdOut().writer();
    var bw = std.io.bufferedWriter(stdout_file);
    const stdout = bw.writer();

    // allocator ------------------------------------------
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer {
        const ok = gpa.deinit();
        std.debug.assert(ok == .ok);
    }
    const allocator = gpa.allocator();

    // deathstar ------------------------------------------
    var dstar = try DeathStar(f32).init(allocator);
    defer dstar.deinit();

    // print deathstar PGM to stdout ----------------------
    const comments = [_][]const u8{
        "Rosetta Code",
        "DeathStar",
        "https://rosettacode.org/wiki/Death_Star",
    };
    try dstar.print(stdout, comments[0..]);

    // ----------------------------------------------------
    try bw.flush();
}
fn Vector(comptime T: type) type {
    return struct {
        const Self = @This();
        x: T,
        y: T,
        z: T,

        pub fn init(x: T, y: T, z: T) Self {
            return Self{ .x = x, .y = y, .z = z };
        }
        pub fn zero() Self {
            return Self{ .x = 0.0, .y = 0.0, .z = 0.0 };
        }
        fn dot(a: *const Self, b: *const Self) T {
            return a.x * b.x + a.y * b.y + a.z * b.z;
        }
        fn length(self: *const Self) T {
            return std.math.sqrt(self.dot(self));
        }
        pub fn normalize(self: *Self) void {
            const inv_length = 1 / self.length();
            self.*.x *= inv_length;
            self.*.y *= inv_length;
            self.*.z *= inv_length;
        }
    };
}
fn SphereHit(comptime T: type) type {
    return struct { z1: T, z2: T };
}
fn Sphere(comptime T: type) type {
    return struct {
        const Self = @This();
        cx: T,
        cy: T,
        cz: T,
        r: T,

        pub fn init(cx: T, cy: T, cz: T, r: T) Self {
            return Self{ .cx = cx, .cy = cy, .cz = cz, .r = r };
        }
        /// Check if a ray (x,y, -inf)->(x, y, inf) hits a sphere.
        /// If so, return the intersecting z values. z1 is closer to the eye.
        pub fn hit(self: *const Self, xx: T, yy: T) ?SphereHit(T) {
            const x = xx - self.cx;
            const y = yy - self.cy;
            const zsq = self.r * self.r - x * x - y * y;
            if (zsq >= 0) {
                const zsqrt = std.math.sqrt(zsq);
                return .{ .z1 = self.cz - zsqrt, .z2 = self.cz + zsqrt };
            }
            return null;
        }
    };
}
fn DeathStar(comptime T: type) type {
    return struct {
        const Self = @This();
        allocator: Allocator,
        w: usize,
        h: usize,
        img: ImageData(),

        const Hit = enum { background, neg, pos };

        pub fn init(allocator: Allocator) !Self {
            var dir = Vector(T).init(20, -40, 10);
            dir.normalize();
            // positive sphere and negative sphere
            const pos = Sphere(T).init(180, 240, 220, 120);
            const neg = Sphere(T).init(60, 150, 100, 100);

            const k: T = 1.5;
            const amb: T = 0.2;

            const w: usize = @intFromFloat(pos.r * 4);
            const h: usize = @intFromFloat(pos.r * 3);
            var img = try ImageData().init(allocator, "deathStar", w, h);

            var vec = Vector(T).zero();

            const start_y: usize = @intFromFloat(pos.cy - pos.r);
            const end_y: usize = @intFromFloat(pos.cy + pos.r);
            const start_x: usize = @intFromFloat(pos.cx - pos.r);
            const end_x: usize = @intFromFloat(pos.cx + pos.r);

            for (start_y..end_y + 1) |j| {
                for (start_x..end_x + 1) |i| {
                    const x: T = @floatFromInt(i);
                    const y: T = @floatFromInt(j);

                    const result_pos = pos.hit(x, y);
                    // ray lands in blank space, show bg
                    if (result_pos == null)
                        continue;

                    const zb1 = result_pos.?.z1;
                    const zb2 = result_pos.?.z2;

                    const result_neg = neg.hit(x, y);

                    switch (calcHit(result_neg, zb1, zb2)) {
                        .background => continue,
                        .neg => {
                            vec.x = neg.cx - x;
                            vec.y = neg.cy - y;
                            vec.z = neg.cz - result_neg.?.z2; // zs2
                        },
                        .pos => {
                            vec.x = x - pos.cx;
                            vec.y = y - pos.cy;
                            vec.z = zb1 - pos.cz;
                        },
                    }
                    vec.normalize();
                    var s = dir.dot(&vec);
                    if (s < 0) s = 0;
                    const lum = 255 * (std.math.pow(T, s, k) + amb) / (1 + amb);
                    const lumi: u8 = @intFromFloat(std.math.clamp(lum, 0, 255));
                    img.pset(i, j, Gray{ .w = lumi });
                }
            }
            return Self{ .allocator = allocator, .w = w, .h = h, .img = img };
        }
        pub fn deinit(self: *Self) void {
            self.img.deinit();
        }
        pub fn print(self: *Self, writer: anytype, optional_comments: ?[]const []const u8) !void {
            try self.img.print(writer, optional_comments);
        }
        /// Ray has hit the positive sphere.
        /// How does it intersect the negative sphere ?
        fn calcHit(neg_hit: ?SphereHit(T), zb1: T, zb2: T) Hit {
            if (neg_hit) |result| {
                const zs1 = result.z1;
                const zs2 = result.z2;
                if (zs1 > zb1) {
                    // ray hits both, but pos front surface is closer
                    return Hit.pos;
                } else if (zs2 > zb2) {
                    // pos sphere surface is inside neg sphere, show bg
                    return Hit.background;
                } else if (zs2 > zb1) {
                    // back surface on neg sphere is inside pos sphere,
                    // the only place where neg sphere surface will be shown
                    return Hit.neg;
                } else {
                    return Hit.pos;
                }
            } else {
                // ray hits pos sphere but not neg, draw pos sphere surface
                return Hit.pos;
            }
        }
    };
}
const Gray = struct {
    w: u8,
    const black = Gray{ .w = 0 };
};
fn ImageData() type {
    return struct {
        const Self = @This();
        allocator: Allocator,
        name: []const u8,
        w: usize,
        h: usize,
        image: []Gray,

        pub fn init(allocator: Allocator, name: []const u8, w: usize, h: usize) !Self {
            const image = try allocator.alloc(Gray, h * w);
            // black background fill
            for (image) |*pixel| pixel.* = Gray.black;
            return Self{ .allocator = allocator, .image = image, .name = name, .w = w, .h = h };
        }
        pub fn deinit(self: *Self) void {
            self.allocator.free(self.image);
        }
        pub fn pset(self: *Self, x: usize, y: usize, gray: Gray) void {
            self.image[x * self.w + y] = gray;
        }
        /// Write PGM P2 ASCII to 'writer'
        pub fn print(self: *const Self, writer: anytype, optional_comments: ?[]const []const u8) !void {
            try writer.print("P2\n", .{});

            if (optional_comments) |lines| {
                for (lines) |line|
                    try writer.print("# {s}\n", .{line});
            }

            try writer.print("{d} {d}\n{d}\n", .{ self.w, self.h, 255 });

            for (self.image, 0..) |pixel, i| {
                const sep = if (i % self.w == self.w - 1) "\n" else " ";
                try writer.print("{d}{s}", .{ pixel.w, sep });
            }
        }
    };
}