Task: Death Star





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;
	float radius = 300;

	@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));

		

































		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;

				
				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;

				
				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);
	}

}







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;