6
\$\begingroup\$

It's getting to be that time of year, and I figured I might as well post the first winter-themed question :)

Your challenge is to build a snowman.

How, you ask? Well, you decide! You can do ASCII art, you can animate it, you can golf the code, you can make the code that generates the snowman itself a snowman, you can generate a colored image; be creative!

This is a , so the answer with the most upvotes at the end of December will win. (If an answer surpasses the winner in upvotes, then it will become the new winner.) The winning answer will get the magical green check mark!

\$\endgroup\$
5
  • 6
    \$\begingroup\$ Yeah, let us post more "draw a symbol, the unicode character is allowed and mark it as popularity-contest". I learn to hate popularity-contest \$\endgroup\$ Dec 6, 2013 at 9:07
  • \$\begingroup\$ @JohannesKuhn I was really intending for some interesting answers, like animated colored snowmans or something, to come up. :( Maybe I should disallow the unicode character and delete my answer, but I really just posted it so that nobody else would :P \$\endgroup\$
    – Doorknob
    Dec 6, 2013 at 13:07
  • 1
    \$\begingroup\$ As it currently stands, you win your own contest with the fastest gun in the west. \$\endgroup\$ Dec 6, 2013 at 13:45
  • 1
    \$\begingroup\$ The failings of the StackExchange code golf community are hardly good reason to hate a fun seasonal challenge. Plus, the real answers take longer to make, so naturally the mediocre answers will be some of the first to come in. \$\endgroup\$
    – Stuntddude
    Dec 6, 2013 at 23:15
  • \$\begingroup\$ I'm voting to close this question as off-topic and too old to migrate because the winning condition indicates that the challenge concluded on December 31, 2013, nearly 4 years ago \$\endgroup\$ Aug 2, 2017 at 20:38

6 Answers 6

13
\$\begingroup\$

JavaScript/HTML: 454 Characters

Thanks @Doorknob for the idea

Snowman Sitting in the Snow

Here it is running: http://jsfiddle.net/au35H/1/

Code-golfed:

<html><head><script>(function(){for(var f=[".",",","*"," "," "],e=["&#9731;",2],n=[16,8],t=[],r,u,i=0;i<n[1];i++){for(r=[],u=0;u<n[0];u++)r.push(" ");t.push(r)}setInterval(function(){for(var r=[],u=[],i=0;i<n[1];i++)r.push(t[i].join(""));for(document.body.innerHTML=r.join("\n"),i=0;i<n[0];i++)u.push(f[Math.floor(Math.random()*f.length)]);t.pop(),t.splice(0,0,u),t[n[1]-1][e[1]]=e[0]},500)})();</script><body style="font:80px monospace;white-space:pre">
\$\endgroup\$
2
  • \$\begingroup\$ That's cute ^.^ \$\endgroup\$
    – Cruncher
    Dec 6, 2013 at 14:36
  • \$\begingroup\$ Wow, very nice! This is the kind of thing I was looking for :-) \$\endgroup\$
    – Doorknob
    Dec 6, 2013 at 16:24
11
\$\begingroup\$

I just know someone is going to post this eventually, so 1 character in HTML:

(That's a Unicode snowman; U+2603)

It's pretty hard to see, so here's 23 characters:

<p style=font-size:99>☃

Renders as this on my browser:

screenshot

Or, I could be evil and use the deprecated and terrible font tag for 15 characters:

<font size=99>☃

It renders smaller for some reason.

another screenshot

(of course, these HTML files aren't valid, but latest Chrome (31.0.1650.57 as of writing) gladly accepts them)

\$\endgroup\$
9
  • 2
    \$\begingroup\$ If you ever need a unicode snowman, there's this site: unicodesnowmanforyou.com :) \$\endgroup\$ Dec 6, 2013 at 8:41
  • 1
    \$\begingroup\$ For heaven's sake, why does a unicode snowman even exist... \$\endgroup\$
    – Cruncher
    Dec 6, 2013 at 14:37
  • 1
    \$\begingroup\$ @Cruncher there's also the poor fellow U+26C4 SNOWMAN WITHOUT SNOW, and also: fileformat.info/info/unicode/char/1f5fd/index.htm :-) \$\endgroup\$
    – FireFly
    Dec 6, 2013 at 15:30
  • 4
    \$\begingroup\$ Stop upvoting this! :-P I just posted this so that nobody else would...it was not meant to be a real answer \$\endgroup\$
    – Doorknob
    Dec 6, 2013 at 16:09
  • 1
    \$\begingroup\$ @Doorknob would you like me to downvote to counteract upvotes? ^_^ \$\endgroup\$
    – Justin
    Dec 12, 2013 at 7:34
11
\$\begingroup\$

Polyglot, 1 character

8

Sorry.

\$\endgroup\$
4
  • \$\begingroup\$ Works in PowerShell. \$\endgroup\$
    – Iszi
    Dec 6, 2013 at 3:12
  • \$\begingroup\$ @Iszi works on anything that allows character 8 - eight :-) \$\endgroup\$
    – Tomas
    Feb 2, 2014 at 16:43
  • 1
    \$\begingroup\$ @Tomas No, it works on anything that allows the character 8 and will print that character without any other syntax required. \$\endgroup\$
    – Iszi
    Feb 3, 2014 at 4:58
  • \$\begingroup\$ Works in JavaScript... Gets my vote... \$\endgroup\$ Mar 4, 2014 at 22:28
8
\$\begingroup\$

MSBuild

Save the following project file as snowman:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="x">
  <Target Name="x">
    <Exec Command="start http://unicodesnowmanforyou.com"/> 
  </Target>
</Project>

The task was to build a snowman, so:

msbuild snowman

enter image description here

\$\endgroup\$
8
\$\begingroup\$

This is a bit of a cheat as it is mostly reusing some existing code, but it's a slightly modified version of a C++ AMP realtime GPU path tracer I wrote.

GPU Pathtraced Snowman

Most of the interesting code is here but there's some utility code in a couple of other files for setting up D3D, setting up the window etc.

#include "app.h"

#include "d3d11device.h"

#include <vector>
#include <fstream>
#include <chrono>
#include <iostream>
#include <initializer_list>
#include <random>
#include <cassert>
#include <cmath>

#include <amp.h>
#include <amp_graphics.h>

#include <Xinput.h>

#include <amputils.h>

using namespace std;
using namespace renderer;
using namespace concurrency;
using namespace concurrency::direct3d;
using namespace concurrency::graphics;
using namespace concurrency::graphics::direct3d;
using namespace concurrency::fast_math;
using namespace DirectX;
using namespace amputils;

namespace {

template<typename T, size_t N>
size_t ArraySize(T (&)[N]) {
    return N;
}

vector<char> LoadFile(const char* filename) {
    ifstream file(filename, ios_base::binary);
    return vector<char>(istreambuf_iterator<char>(file), (istreambuf_iterator<char>()));
}

struct SimpleVertex
{
    float x, y, z;
};

class Sphere
{
public:
    Sphere(const Vector3& center_, float radius_) restrict(amp, cpu) : center(center_), radius(radius_) {}

    Vector3 GetCenter() const restrict(amp, cpu) { return center; }
    float GetRadius() const restrict(amp, cpu) { return radius; }

    // Used for sampling a light from a point
    Vector3 Sample(const Vector3& p, float u1, float u2, Vector3& normal) const restrict(amp, cpu);

    float Pdf(const Vector3& p, const Vector3& /*wi*/) const restrict(amp, cpu) {
        Vector3 pToCenter = center - p;
        float sinThetaMax2 = radius * radius / Dot(pToCenter, pToCenter);
        float cosThetaMax = sqrt(max(0.1f, 1.f - sinThetaMax2));
        return UniformConePdf(cosThetaMax);
    }

private:
    Vector3 center;
    float radius;
};

class DifferentialGeometry
{
public:
    DifferentialGeometry() restrict(amp, cpu) : p(0.0f), n(0.0f) {}
    DifferentialGeometry(const Vector3& p_, const Vector3& n_) restrict(amp, cpu) : p(p_), n(n_) {}

    const Vector3& GetPoint() const restrict(amp, cpu) { return p; }
    const Vector3& GetNormal() const restrict(amp, cpu) { return n; }

private:
    Vector3 p;
    Vector3 n;
};

bool IntersectP(const Ray& ray, const Sphere& sphere, float& t) restrict(amp, cpu)
{
    const auto v = ray.GetOrigin() - sphere.GetCenter();
    const auto a = Dot(ray.GetDirection(), ray.GetDirection());
    const auto minusB = -2.f * Dot(ray.GetDirection(), v);
    const auto c = Dot(v, v) - Square(sphere.GetRadius());
    const auto discrim = (Square(minusB) - 4.f * a * c);
    if (discrim < 0.f) {
        return false;
    }

    const auto sqrtDiscrim = sqrt(discrim);
    const auto tMax = minusB + sqrtDiscrim;
    if (tMax < 0.f) {
        return false;
    }

    const auto denominator = 1.f / (2.f * a);
    const auto tMin = minusB - sqrtDiscrim;
    t = (tMin < 0.f ? tMax : tMin) * denominator;
    return true;
}

bool Intersect(const Ray& ray, const Sphere& sphere, float& t, DifferentialGeometry& dg) restrict(amp, cpu)
{
    const auto v = ray.GetOrigin() - sphere.GetCenter();
    const auto a = Dot(ray.GetDirection(), ray.GetDirection());
    const auto minusB = -2.f * Dot(ray.GetDirection(), v);
    const auto c = Dot(v, v) - Square(sphere.GetRadius());
    const auto discrim = (Square(minusB) - 4.f * a * c);
    if (discrim < 0.f) {
        return false;
    }

    const auto sqrtDiscrim = sqrt(discrim);
    const auto tMax = minusB + sqrtDiscrim;
    if (tMax < 0.f) {
        return false;
    }

    const auto denominator = 1.f / (2.f * a);
    const auto tMin = minusB - sqrtDiscrim;
    t = (tMin < 0.f ? tMax : tMin) * denominator;
    Vector3 p = ray(t);
    dg = DifferentialGeometry(p, Normalize(p - sphere.GetCenter()));
    return true;
}

inline Vector3 Sphere::Sample(const Vector3& p, float u1, float u2, Vector3& normal) const restrict(amp, cpu) {
    Vector3 pToCenter = center - p;
    Vector3 wc = Normalize(pToCenter);
    Vector3 wcX(0.0f), wcY(0.0f);
    CoordinateSystem(wc, wcX, wcY);
    float sinThetaMax2 = radius * radius / Dot(pToCenter, pToCenter);
    float cosThetaMax = sqrt(max(0.1f, 1.f - sinThetaMax2));
    float tHit;
    DifferentialGeometry dg;
    Ray r(p, UniformSampleCone(u1, u2, cosThetaMax, wcX, wcY, wc));
    if (!Intersect(r, *this, tHit, dg))
        tHit = Dot(pToCenter, Normalize(r.GetDirection()));
    normal = dg.GetNormal();
    return dg.GetPoint();
}

class Primitive
{
public:
    Primitive(const Sphere& s_, const Vector3& color_) restrict(amp, cpu) : s(s_), color(color_) {}

    const Sphere& GetSphere() const restrict(amp, cpu) { return s; }
    const Vector3& GetColor() const restrict(amp, cpu) { return color; }

private:
    Sphere s;
    Vector3 color;
};

struct CameraSample
{
    CameraSample(float x_, float y_) restrict(amp, cpu) : x(x_), y(y_) {}
    float x, y;
};

class StratifiedSampler
{
public:
    explicit StratifiedSampler(int n) restrict(amp, cpu) : mN(n) {}

    int GetNumSamples() const restrict(amp, cpu) { return mN * mN; } 
    CameraSample Sample2D(amputils::Rng& rng, int i) restrict(amp, cpu) {
        float dxy = 1.0f / mN;
        float xOff = static_cast<float>(i % mN);
        float yOff = static_cast<float>(i / mN);
        return CameraSample((xOff + rng.GetUniform()) * dxy, (yOff + rng.GetUniform()) * dxy);
    }

private:
    StratifiedSampler& operator=(const StratifiedSampler&);

    int mN;
};

class Camera
{
public:
    Camera(int filmWidth, int filmHeight)
        : mPos(0.0f, 0.0f, -20.0f),
          mYaw(0.0f),
          mPitch(0.0f),
          mWorldToCamera(XMMatrixLookAtLH(XMVectorReplicate(0.0f), XMVectorReplicate(1.0f), XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f))),
          mCameraToWorld(XMMatrixInverse(nullptr, mWorldToCamera.GetXMMATRIX())),
          mProjection(XMMatrixPerspectiveFovLH(3.1415f * 0.333f, 1.0f, 1e-2f, 1e3f)),
          mInverseProjection(XMMatrixInverse(nullptr, mProjection.GetXMMATRIX())),
          mFilmWidth(filmWidth),
          mFilmHeight(filmHeight)
    {
        UpdateMatrices();
    }

    const Matrix4& GetWorldToCamera() const restrict(amp, cpu) { return mWorldToCamera; }
    const Matrix4& GetCameraToWorld() const restrict(amp, cpu) { return mCameraToWorld; }
    const Matrix4& GetProjection() const restrict(amp, cpu) { return mProjection; }
    const Matrix4& GetInverseProjection() const restrict(amp, cpu) { return mInverseProjection; }

    void RotateCam(float yaw, float pitch)
    {
        mYaw += yaw;
        mPitch = Clamp(mPitch + pitch, 3.14f * -0.45f, 3.14f * 0.45f);
        UpdateMatrices();
    }

    void TranslateCam(const Vector3& trans)
    {
        mPos += trans;
        UpdateMatrices();
    }

    Ray GenerateRay(int x, int y, int i, StratifiedSampler& samp, amputils::Rng& rng) const restrict(amp, cpu) {
        auto camSamp = samp.Sample2D(rng, i);
        const float fx = (camSamp.x + float(x)) / float(mFilmWidth);
        const float fy = (camSamp.y + float(y)) / float(mFilmHeight);
        const Vector4 rayFilm(2.0f * fx - 1.0f, 2.0f * fy - 1.0f, 0.0f, 1.0f);
        const Vector4 rayFilmCam = Project(rayFilm, GetInverseProjection());
        const Vector4 rayFilmWorld = Transform(rayFilmCam, GetCameraToWorld());
        const Vector4 rayStartWorld(mPos.x(), mPos.y(), mPos.z(), 1.0f);
        const Vector4 rayDirection(rayFilmWorld - rayStartWorld);
        return Ray(Vector3(rayStartWorld.e(0), rayStartWorld.e(1), rayStartWorld.e(2)), Vector3(rayDirection.e(0), rayDirection.e(1), rayDirection.e(2)));
    }

private:
    void UpdateMatrices()
    {
        XMMATRIX cam = XMMatrixLookAtLH(XMVectorSet(mPos.x(), mPos.y(), mPos.z(), 1.0f), XMVectorSet(mPos.x(), mPos.y(), mPos.z() + 1.0f, 1.0f), XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f));
        XMMATRIX rot = XMMatrixMultiply(XMMatrixRotationY(mYaw), XMMatrixRotationX(mPitch));
        mWorldToCamera = XMMatrixMultiply(cam, rot);
        mCameraToWorld = XMMatrixInverse(nullptr, mWorldToCamera.GetXMMATRIX());
    }

    Vector3 mPos;
    float mYaw, mPitch;

    Matrix4 mWorldToCamera;
    Matrix4 mCameraToWorld;
    Matrix4 mProjection;
    Matrix4 mInverseProjection;

    int mFilmWidth, mFilmHeight;
};

class Scene;

class SceneView
{
public:
    int GetNumPrims() const restrict(amp, cpu) { return prims.extent.size(); }
    const Primitive& GetPrim(int i) const restrict(amp, cpu) { return prims[i]; }

    const Camera& GetCamera() const restrict(amp, cpu) { return camera; }

    const Primitive& GetLight() const restrict(amp, cpu) { return light; }

private:
    friend class Scene;
    explicit SceneView(const Camera& camera_, const vector<Primitive>& prims_, const Primitive& light_)
        : camera(camera_),
          prims(prims_.size(), prims_),
          light(light_)
    {
    }

    Camera camera;
    array_view<const Primitive> prims;
    Primitive light;
};

class Scene
{
public:
    explicit Scene(int filmWidth, int filmHeight, const initializer_list<Primitive>& prims_) 
        : camera(filmWidth, filmHeight), 
          prims(prims_.begin(), prims_.end()),
          light(Sphere(Vector3(50.0f, 50.0f, -50.0f), 5.0f), Vector3(0.75f, 0.75f, 0.67f))
    {
    }

    SceneView GetView() const 
    {
        return SceneView(camera, prims, light);
    }

    Camera& GetCamera() { return camera; }
    const Camera& GetCamera() const { return camera; }

    const Primitive& GetLight() const { return light; }

    Primitive& GetPrimitive(int i) { return prims[i]; }

private:
    Camera camera;
    vector<Primitive> prims;
    Primitive light;
};

}

Scene MakeScene(int filmWidth, int filmHeight)
{
    auto prims = {
        Primitive(Sphere(Vector3(0.0f, 0.0f, 1100.0f), 1000.0f), Vector3(0.61f, 0.78f, 1.0f)),
        Primitive(Sphere(Vector3(0.0f, -1010.0f, 0.0f), 1000.0f), Vector3(0.85f, 0.85f, 0.85f)), 
        Primitive(Sphere(Vector3(-2.0f, -6.5f, 2.0f), 4.0f), Vector3(0.85f, 0.85f, 0.85f)),
        Primitive(Sphere(Vector3(-2.0f, -1.5f, 2.0f), 3.0f), Vector3(0.85f, 0.85f, 0.85f)),
        Primitive(Sphere(Vector3(-2.0f, 2.8f, 2.0f), 2.0f), Vector3(0.85f, 0.85f, 0.85f)),
        Primitive(Sphere(Vector3(-2.0f, 2.8f, 0.0f), 0.2f), Vector3(0.05f, 0.05f, 0.05f)),
        Primitive(Sphere(Vector3(-2.5f, 3.5f, 0.3f), 0.2f), Vector3(0.05f, 0.05f, 0.05f)),
        Primitive(Sphere(Vector3(-1.5f, 3.5f, 0.3f), 0.2f), Vector3(0.05f, 0.05f, 0.05f))
    };
    return Scene(filmWidth, filmHeight, prims);
}

class App : public IApp {
public:
    App(void* hwnd, int width, int height);
    ~App();
    void Update(bool mouseButtons[2], int mouseX, int mouseY) override;

private:
    void UpdateControllerState();
    void UpdateTexture(unsigned t);

    Device mDevice;

    // No copy or assignment
    App(const App&);
    App operator=(const App&);

    ID3D11VertexShaderPtr mVs;
    ID3D11PixelShaderPtr mPs;

    accelerator_view mAcceleratorView;
    texture<float_4, 2> mAmpTex;
    ID3D11Texture2DPtr mD3dTex;
    ID3D11ShaderResourceViewPtr mTexView;
    ID3D11SamplerStatePtr mSamplerState;
    ID3D11InputLayoutPtr mInputLayout;
    ID3D11BufferPtr mQuadVertexBuffer;
    ID3D11BufferPtr mQuadIndexBuffer;

    chrono::time_point<chrono::high_resolution_clock> mLastFrameTime;

    Scene mScene;

    XINPUT_STATE mControllerState;

    vector<amputils::Rng::SeedValue> mRngSeeds;
};

App::App(void* hwnd, int width, int height) :
    mDevice(hwnd, width, height),
    mAcceleratorView(create_accelerator_view(mDevice.GetD3D11Device())),
    mAmpTex(width, height, mAcceleratorView),
    mD3dTex(get_texture(mAmpTex)),
    mLastFrameTime(chrono::high_resolution_clock::now()),
    mScene(MakeScene(width, height)),
    mRngSeeds(mAmpTex.extent.size())
{
    auto vs = LoadFile("simplevs.cso");
    mDevice.GetD3D11Device()->CreateVertexShader(vs.data(), vs.size(), nullptr, &mVs);

    auto ps = LoadFile("simpleps.cso");
    mDevice.GetD3D11Device()->CreatePixelShader(ps.data(), ps.size(), nullptr, &mPs);

    CD3D11_SHADER_RESOURCE_VIEW_DESC resViewDesc(mD3dTex, D3D11_SRV_DIMENSION_TEXTURE2D);
    mDevice.GetD3D11Device()->CreateShaderResourceView(mD3dTex, &resViewDesc, &mTexView);

    CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT);
    mDevice.GetD3D11Device()->CreateSamplerState(&samplerDesc, &mSamplerState);

    D3D11_INPUT_ELEMENT_DESC elems[] = {
        { "SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
    };
    mDevice.GetD3D11Device()->CreateInputLayout(elems, ArraySize(elems), vs.data(), vs.size(), &mInputLayout);

    SimpleVertex quadVerts[] = {
        { -1.0f, 1.0f, 0.0f },
        { 1.0f, 1.0f, 0.0f },
        { 1.0f, -1.0f, 0.0f },
        { -1.0f, -1.0f, 0.0f },
    };
    CD3D11_BUFFER_DESC vbDesc(sizeof(quadVerts), D3D11_BIND_VERTEX_BUFFER);
    D3D11_SUBRESOURCE_DATA vbData = { quadVerts, 0, 0 };
    mDevice.GetD3D11Device()->CreateBuffer(&vbDesc, &vbData, &mQuadVertexBuffer);

    uint16_t quadIndices[] = { 0, 1, 2, 2, 3, 0 };
    CD3D11_BUFFER_DESC ibDesc(sizeof(quadIndices), D3D11_BIND_INDEX_BUFFER);
    D3D11_SUBRESOURCE_DATA ibData = { quadIndices, 0, 0 };
    mDevice.GetD3D11Device()->CreateBuffer(&ibDesc, &ibData, &mQuadIndexBuffer);

    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<unsigned int> dis;
    for_each(begin(mRngSeeds), end(mRngSeeds), [&gen, &dis](amputils::Rng::SeedValue& seedValue) {
        seedValue = amputils::Rng::SeedValue(dis(gen), dis(gen), dis(gen), dis(gen));
    });

    amputils::Rng rng(amputils::Rng::SeedValue(dis(gen), dis(gen), dis(gen), dis(gen)));
    StratifiedSampler sampler(4);
    for (int i = 0; i < sampler.GetNumSamples(); ++i) {
        auto samp = sampler.Sample2D(rng, i);
        cout << samp.x << ", " << samp.y << "\n";
    }
}

App::~App() {
}

bool IsShadowed(const Ray& ray, const SceneView& scene) restrict(amp, cpu)
{
    auto lightT = FLT_MAX;
    if (!IntersectP(ray, scene.GetLight().GetSphere(), lightT))
        return true;

    for (auto i = decltype(scene.GetNumPrims())(0); i < scene.GetNumPrims(); ++i)
    {
        const auto& sphere = scene.GetPrim(i).GetSphere();
        float t = FLT_MAX;
        if (IntersectP(ray, sphere, t) && t < lightT) {
            return true;
        }
    }
    return false;
}

template<int RecursionDepth>
inline Vector3 TraceRay(const Ray& ray, const SceneView& scene, Rng& rng, int sampIdx) restrict(amp, cpu)
{
    Vector3 color(0.1f, 0.1f, 0.25f);
    auto nearestT = FLT_MAX;
    DifferentialGeometry nearestDg;
    Vector3 nearestDiffuseColor(0.0f);

    for (auto i = decltype(scene.GetNumPrims())(0); i < scene.GetNumPrims(); ++i)
    {
        const auto& sphere = scene.GetPrim(i).GetSphere();
        float t = FLT_MAX;
        DifferentialGeometry dg;
        if (Intersect(ray, sphere, t, dg) && t < nearestT) {
            nearestT = t;
            nearestDg = dg;
            nearestDiffuseColor = scene.GetPrim(i).GetColor();
        }
    }

    if (nearestT < FLT_MAX) {
        // Direct lighting
        StratifiedSampler sampler(4);
        auto samp = sampler.Sample2D(rng, sampIdx);
        Vector3 lightNormal(0.0f);
        const auto lightPos = scene.GetLight().GetSphere().Sample(nearestDg.GetPoint(), samp.x, samp.y, lightNormal);
        const auto L = Normalize(lightPos - nearestDg.GetPoint());
        if (IsShadowed(Ray(nearestDg.GetPoint() + L * 1e-3f, L), scene))
            color = Vector3(0.0f);
        else
            color = nearestDiffuseColor * Dot(nearestDg.GetNormal(), L) * scene.GetLight().GetColor();

        // Indirect lighting
        auto indirectSamp = sampler.Sample2D(rng, sampIdx);
        auto indirectDirLocal = CosineSampleHemisphere(indirectSamp.x, indirectSamp.y);
        Vector3 normalZ = nearestDg.GetNormal();
        Vector3 normalX(0.0f), normalY(0.0f);
        CoordinateSystem(normalZ, normalX, normalY);
        auto indirectDirWorld = normalX * indirectDirLocal.x() + normalY * indirectDirLocal.y() + normalZ * indirectDirLocal.z();
        Ray indirectRay(nearestDg.GetPoint() + nearestDg.GetNormal() * 1e-3f, indirectDirWorld);
        auto indirectColor = TraceRay<RecursionDepth - 1>(indirectRay, scene, rng, sampIdx) * CosineHemispherePdf(Dot(indirectDirWorld, nearestDg.GetNormal()), 0.0f);
        color += indirectColor * nearestDiffuseColor;
    }

    return color;
}

template<>
inline Vector3 TraceRay<0>(const Ray& /*ray*/, const SceneView& /*scene*/, Rng& /*rng*/, int /*sampIdx*/) restrict(amp, cpu)
{
    return Vector3(0.0f);
}

const int Height = 512;
const int Width = 512;

inline float_4 RaytraceScene(int x, int y, const SceneView& scene, Rng& rng) restrict (amp, cpu)
{
    float_4 totalIrradiance = 0.0f;
    StratifiedSampler sampler(4);
    for (int samp = 0; samp < sampler.GetNumSamples(); ++samp)
    {
        auto ray = scene.GetCamera().GenerateRay(x, y, samp, sampler, rng);
        totalIrradiance += ToFloat4(TraceRay<4>(ray, scene, rng, samp));
    }
    totalIrradiance *= 1.0f / sampler.GetNumSamples();
    return totalIrradiance;
}

void App::UpdateTexture(unsigned t)
{
    auto sceneView = mScene.GetView();
    auto ampTexView = writeonly_texture_view<float_4, 2>(mAmpTex);
    auto rngSeedsView = array_view<const amputils::Rng::SeedValue, 2>(ampTexView.extent, mRngSeeds);
    parallel_for_each(mAcceleratorView, mAmpTex.extent, [ampTexView, sceneView, t, rngSeedsView](index<2> idx) restrict(amp) {
        //Rng::SeedValue rngSeed(rngSeedsView[idx].z1 + t, rngSeedsView[idx].z2 + t, rngSeedsView[idx].z3 + t, rngSeedsView[idx].z4 + t);
        Rng rng(rngSeedsView[idx]);
        ampTexView.set(idx, RaytraceScene(idx[1], idx[0], sceneView, rng));
    });
}

void App::UpdateControllerState()
{
    for (DWORD i = 0; i < 4; ++i)
    {
        // Simply get the state of the controller from XInput.
        ZeroMemory(&mControllerState, sizeof(mControllerState));
        DWORD dwResult = XInputGetState(i, &mControllerState);

        if (dwResult == ERROR_SUCCESS)
            return;
    }
}

float GetThumbstickAmount(const int rawVal)
{
    const int inputDeadzone = static_cast<int>(0.24f * float(0x7FFF)); // Default to 24% of the +/- 32767 range.
    const int deadzoneVal = abs(rawVal) < inputDeadzone ? 0 : rawVal + inputDeadzone * Sign(rawVal);
    return float(deadzoneVal) / float(0x7FFF - inputDeadzone);
}

void App::Update(bool /*mouseButtons*/[2], int /*mouseX*/, int /*mouseY*/) 
{
    static const auto startTime = chrono::high_resolution_clock::now();
    auto frameTime = chrono::high_resolution_clock::now();
    auto frameMs = chrono::duration_cast<chrono::milliseconds>(frameTime - mLastFrameTime);
    //float frameS = chrono::duration_cast<chrono::milliseconds>(frameTime - startTime).count() * 1e-3f;
    mLastFrameTime = frameTime;

    UpdateControllerState();
    float xRot = GetThumbstickAmount(mControllerState.Gamepad.sThumbRX) * float(frameMs.count()) * -1e-3f;
    float yRot = GetThumbstickAmount(mControllerState.Gamepad.sThumbRY) * float(frameMs.count()) * 1e-3f;
    mScene.GetCamera().RotateCam(xRot, yRot);
    Vector4 camForward = mScene.GetCamera().GetCameraToWorld().GetRow(2);
    Vector4 camStrafe = mScene.GetCamera().GetCameraToWorld().GetRow(0);
    float forward = GetThumbstickAmount(mControllerState.Gamepad.sThumbLY) * float(frameMs.count()) * 5e-3f; 
    float strafe = GetThumbstickAmount(mControllerState.Gamepad.sThumbLX) * float(frameMs.count()) * 5e-3f;
    Vector4 camTranslate = camForward * forward + camStrafe * strafe;
    mScene.GetCamera().TranslateCam(Vector3(camTranslate.x(), camTranslate.y(), camTranslate.z()));

    /*
    auto movingSpherePos = Vector3(sin(frameS), cos(frameS), cos(frameS)) * 5.0f;
    mScene.GetPrimitive(6) = Primitive(Sphere(movingSpherePos, 3.0f), Vector3(0.6f, 0.6f, 0.05f));
    */

    UpdateTexture(static_cast<unsigned>(frameTime.time_since_epoch().count()));

    mDevice.ClearDefaultRenderTarget();
    mDevice.SetDefaultRenderTarget();

    ID3D11DeviceContextPtr deviceContext;
    mDevice.GetD3D11Device()->GetImmediateContext(&deviceContext);

    deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    deviceContext->IASetInputLayout(mInputLayout);
    deviceContext->IASetIndexBuffer(mQuadIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
    ID3D11Buffer* vbs[] = { mQuadVertexBuffer.GetInterfacePtr() };
    UINT strides[] = { sizeof(SimpleVertex) };
    UINT offsets[] = { 0 };
    deviceContext->IASetVertexBuffers(0, ArraySize(vbs), vbs, strides, offsets);
    deviceContext->VSSetShader(mVs, nullptr, 0);
    deviceContext->PSSetShader(mPs, nullptr, 0);
    ID3D11ShaderResourceView* srvs[] = { mTexView.GetInterfacePtr() };
    deviceContext->PSSetShaderResources(0, ArraySize(srvs), srvs);
    ID3D11SamplerState* samplers[] = { mSamplerState.GetInterfacePtr() };
    deviceContext->PSSetSamplers(0, ArraySize(samplers), samplers);
    deviceContext->DrawIndexed(6, 0, 0);
    ID3D11ShaderResourceView* emptySrvs[] = { nullptr };
    deviceContext->PSSetShaderResources(0, ArraySize(emptySrvs), emptySrvs);

    mDevice.Present();

    cout << frameMs.count() << endl;
}

unique_ptr<IApp> CreateApp(void* hwnd, int width, int height) {
    return unique_ptr<IApp>(new App(hwnd, width, height));
}
\$\endgroup\$
1
  • \$\begingroup\$ How can anyone not love this?! \$\endgroup\$
    – user9206
    Oct 1, 2014 at 6:08
7
\$\begingroup\$

Befunge 93

>"  )__:__(  @"v 
v"@'--( : )--'"<
>"   )^_^(   @"v
v"@   _[_]_   "<
>"     _     @"v
@    v_v#!-"@":<
     >$ 91+,:!v
       >,: !#v_^
^            <

Ouput:

     _     
   _[_]_   
   (^_^)   
'--( : )--'
  (__:__)  

Change one character for infinite snowmen:

>"  )__:__(  @"v 
v"@'--( : )--'"<
>"   )^_^(   @"v
v"@   _[_]_   "<
>"     _     @"v
@    v_v#!-"@":<
     >$ 91+,:!v
       >,: !#v_^
v            <

How it works: stores the characters in the snowman on the stack. @ symbolizes a new line. Then, loops through all the characters; if it is an @, print a new line: 91+,, otherwise, print the character. Then, it checks if the end has been reached. If it has, it exits the loop: #v_^.


Ascii art versions

          >")__:__(  @"v 
          v            <
          >            v
       vv"@'--( : )--'"<vv
         v              v_
        >"   )"     "^"   v
      v"@   ""("   "^""_" <
      >"   "              v
        v     "_[_]_"     <<
        >>                v
          v               <
  _       >"  ":"@  ":  ::v       _
 | |     v    ::    :"  _"<      | |
 | |=====>                 v=====| |
  =======v   "@"    +0     <=======|
         >>               v
          v               <
         %v<   o     o    <v
        %v<    0     0     &%
        %>                  v
        v    "@"     :      <
        >>                 v
         v +0+0:,+19$<_v#!-<
    _____>0+!#v_v#+0!:,<@@@@ _____
    @@@@@@@$0 <@>0+0+0+0+0+ ^@@@@@

Outputs the exact same thing. Can also be changed to infinite snowman:

          >")__:__(  @"v 
          v            <
          >            v
       vv"@'--( : )--'"<vv
         v              v_
        >"   )"     "^"   v
      v"@   ""("   "^""_" <
      >"   "              v
        v     "_[_]_"     <<
        >>                v
          v               <
  _       >"  ":"@  ":  ::v       _
 | |     v    ::    :"  _"<      | |
 | |=====>                 v=====| |
  =======v   "@"    +0     <=======|
         >>               v
          v               <
         %v<   o     o    <v
        %v<    0     0     &%
        %>                  v
        v    "@"     :      <
        >>                 v
         v +0+0:,+19$<_v#!-<
    _____>0+!#v_v#+0!:,<@@@@ _____
    @@@@@@v$0 <@>0+0+0+0+0+ ^@@@@@
\$\endgroup\$
3
  • 1
    \$\begingroup\$ My favorite part is v_v#!, the code that branches for the @ character. \$\endgroup\$
    – Justin
    Dec 6, 2013 at 18:35
  • 2
    \$\begingroup\$ I love the ASCII art versions :D \$\endgroup\$
    – Doorknob
    Dec 9, 2013 at 14:10
  • 1
    \$\begingroup\$ @Doorknob I spent hours on it. I kept coding it wrong and had to debug. I thought that it does not look too much like a snowman (I'm not good at ascii art), but I just had to try. \$\endgroup\$
    – Justin
    Dec 12, 2013 at 7:36

Not the answer you're looking for? Browse other questions tagged or ask your own question.