import React from 'react';
import { useSelector } from '../../app/store';
import { selectLoaded } from '../loader/fileSlice';
import styles from './Intro.module.css';
import { FileInputLink } from '../loader/FileInputLink';
import { Link } from '../history/Link';

const SHARK_URL =
  '?url=%2Fmodels%2Fshark_ag.raw&cpx=2&cpy=0&cpz=12&ctx=2&cty=0&ctz=0&oox=0&' +
  'ooy=270&ooz=0&oc=c0c0c0&lpx=2&lpy=0&lpz=12';
const MEW_URL =
  '?url=%2Fmodels%2FMew_lp.raw&cpx=0&cpy=7.5&cpz=5&ctx=0&cty=7.5&ctz=0&' +
  'oox=90&ooy=0&ooz=0&oc=f5c7d4&lpx=0&lpy=7.5&lpz=5';
const MEWTWO_URL =
  '?url=%2Fmodels%2FMewtwo_lp.raw&cpx=0&cpy=9&cpz=18&ctx=0&cty=9&ctz=0&' +
  'oox=90&ooy=0&ooz=0&oc=ded8e2&lpx=0&lpy=9&lpz=18';
const CHIEF_URL =
  '?url=%2Fmodels%2Fchief_ag.raw&cpx=0&cpy=38&cpz=70&ctx=0&cty=38&ctz=0&' +
  'far=150&oox=270&ooy=0&ooz=0&oc=68763b&lpx=0&lpy=38&lpz=70';
const EIFFEL_URL =
  '?url=%2Fmodels%2Feiffel_ag.raw&cpx=0&cpy=50&cpz=105&ctx=0&cty=50&ctz=0&' +
  'far=200&oc=cbb697&lpx=0&lpy=50&lpz=105';

export function Intro() {
  const hide = useSelector(selectLoaded);
  if (hide) {
    return null;
  }
  return (
    <div className={styles.container}>
      <h1>Rishov Sarkar&rsquo;s Software 3D Renderer</h1>
      <p>
        This is the first project for the Professor Aaron Lanterman&rsquo;s
        Summer 2020 offering of Georgia Tech&rsquo;s ECE 4795: GPU Programming
        for Video Games.
      </p>
      <p>
        My implementation of this project is written in{' '}
        <a
          href="https://www.typescriptlang.org/"
          target="_blank"
          rel="noopener noreferrer"
        >
          TypeScript
        </a>{' '}
        using the{' '}
        <a
          href="https://reactjs.org/"
          target="_blank"
          rel="noopener noreferrer"
        >
          React framework
        </a>{' '}
        and{' '}
        <a
          href="https://redux.js.org/"
          target="_blank"
          rel="noopener noreferrer"
        >
          Redux
        </a>{' '}
        for state management.
      </p>
      <h2>Usage</h2>
      <p>It&rsquo;s simple!</p>
      <ol>
        <li>
          To load a model, drag a model file onto this page, or just{' '}
          <FileInputLink>click here to select a model file</FileInputLink>. You
          can also choose a preset below.
        </li>
        <li>Drag the model around or play with the controls on the left.</li>
        <li>???</li>
        <li>Profit!</li>
      </ol>
      <h3>Presets</h3>
      <p>
        These presets load the specified model with hand-tuned parameters that
        make them easy to view. A small image of the rendered output is shown
        below each as a preview.
      </p>
      <ul>
        <li>
          <Link href={SHARK_URL}>
            Shark
            <br />
            <img
              src="/renders/shark.png"
              alt="3-D rendered shark"
              height={200}
            />
          </Link>
        </li>
        <li>
          <Link href={MEW_URL}>
            Mew
            <br />
            <img src="/renders/mew.png" alt="3-D rendered Mew" height={200} />
          </Link>
        </li>
        <li>
          <Link href={MEWTWO_URL}>
            Mewtwo
            <br />
            <img
              src="/renders/mewtwo.png"
              alt="3-D rendered Mewtwo"
              height={200}
            />
          </Link>
        </li>
        <li>
          <Link href={CHIEF_URL}>
            Chief
            <br />
            <img
              src="/renders/chief.png"
              alt="3-D rendered Chief"
              height={200}
            />
          </Link>
        </li>
        <li>
          <Link href={EIFFEL_URL}>
            Eiffel
            <br />
            <img
              src="/renders/eiffel.png"
              alt="3-D rendered Eiffel Tower"
              height={200}
            />
          </Link>
        </li>
      </ul>
      <h2>Technical Details</h2>
      <p>
        You can download this project&rsquo;s source code{' '}
        <a href="/assets/source.zip">here</a>.
      </p>
      <h3>Code Highlights</h3>
      <p>
        For this project, I decided to write a custom <code>Matrix</code> class
        inspired by Python&rsquo;s{' '}
        <a href="https://numpy.org/" target="_blank" rel="noopener noreferrer">
          NumPy
        </a>{' '}
        library. In particular, my matrix class supports{' '}
        <a
          href="https://numpy.org/doc/1.18/user/theory.broadcasting.html"
          target="_blank"
          rel="noopener noreferrer"
        >
          broadcasting
        </a>{' '}
        and{' '}
        <a
          href={
            'https://numpy.org/doc/1.18/reference/internals.html' +
            '#internal-organization-of-numpy-arrays'
          }
          target="_blank"
          rel="noopener noreferrer"
        >
          strided arrays
        </a>
        , which I use throughout the code. The code for this matrix class can be
        found in <code>src/util/matrix.ts</code>. (Sidenote: when reading matrix
        code, please note that I use <code>multiply()</code> to refer to matrix
        multiplication and <code>scale()</code> to refer to elementwise
        multiplication.)
      </p>
      <p>
        My <code>Transform3D</code> class is a utility class with static methods
        to create 3-D transformation matrices, such as translations, rotations,
        and look-at matrices. These transforms all assume a{' '}
        <strong>left-handed coordinate system</strong>, where the positive
        z-axis points into the screen. You can find the code in{' '}
        <code>src/util/transform3d.ts</code>.
      </p>
      <p>
        <code>src/features/loader/fileSlice.ts</code> takes care of loading
        model files and parsing them into 2-D arrays, which become matrices in
        later parts of the code.
      </p>
      <p>
        <code>src/features/canvas/rendererSlice.ts</code> contains the code that
        defines the state of all parts of the 3-D renderer besides the model
        itself. This is where you&rsquo;ll find, for example, the code that
        updates the camera position when you drag the mouse.
      </p>
      <p>
        Last but not least, the <code>Canvas</code> React component, defined in{' '}
        <code>src/features/canvas/Canvas.tsx</code>, is where the magic happens.
        This file takes the vertices directly from the file that was loaded in
        and applies all the necessary transforms before painting them to a 2-D{' '}
        <a
          href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API"
          target="_blank"
          rel="noopener noreferrer"
        >
          <code>&lt;canvas&gt;</code>
        </a>
        . This includes the code to compute the world transform, view transform,
        projection transform, and viewport transform, as well as the code to
        calculate lighting information for each triangle and the code to clip
        out-of-bounds triangles.
      </p>
      <h3>Running Locally</h3>
      <p>
        To build and run this project locally, you&rsquo;ll need to have Node.js
        installed. You can download it{' '}
        <a
          href="https://nodejs.org/en/download/"
          target="_blank"
          rel="noopener noreferrer"
        >
          here
        </a>
        .
      </p>
      <p>
        Node.js comes with the package manager{' '}
        <a
          href="https://www.npmjs.com/get-npm"
          target="_blank"
          rel="noopener noreferrer"
        >
          npm
        </a>
        , and this is sufficient for building and running the project. However,
        I personally use and recommend the{' '}
        <a
          href="https://classic.yarnpkg.com/en/"
          target="_blank"
          rel="noopener noreferrer"
        >
          yarn
        </a>{' '}
        package manager. In my experience, yarn is faster in running commands,
        faster in installing packages, and has nicer UX.
      </p>
      <p>Now, once you&rsquo;re set up:</p>
      <ol>
        <li>
          From the project directory, run <code>yarn install</code> or{' '}
          <code>npm install</code> to install dependencies.
        </li>
        <li>
          Run <code>yarn start</code> or <code>npm start</code> to start a
          development server on{' '}
          <a
            href="http://localhost:3000/"
            target="_blank"
            rel="noopener noreferrer"
          >
            http://localhost:3000/
          </a>
          .
        </li>
        <li>
          You can now make changes to the code, if you&rsquo;d like. Changes
          will show up in real time on the development server.
        </li>
        <li>
          If you&rsquo;d like to export to a static site for publishing on a
          platform like{' '}
          <a
            href="https://pages.github.com/"
            target="_blank"
            rel="noopener noreferrer"
          >
            GitHub Pages
          </a>{' '}
          or{' '}
          <a
            href="https://www.netlify.com/"
            target="_blank"
            rel="noopener noreferrer"
          >
            Netlify
          </a>
          , run <code>yarn build</code> or <code>npm run build</code> to
          generate the static site in the project&rsquo;s <code>build/</code>{' '}
          directory.
        </li>
      </ol>
    </div>
  );
}
