// gputrace.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "gputrace.h"

#include "C:\\proj\\sdk\\glew\\include\\GL\\glew.h"

#pragma comment (lib, "opengl32.lib")
#include <GL/gl.h>
//#include <GL/glext.h>

const char *vsh ="\
           varying vec3 s[4];\
           varying vec3 rings[11]; \
           void main() {\
           gl_Position = gl_Vertex; \
           s[0] = vec3(0);          \
           float t = abs(gl_Vertex.x * .001); \
           s[3] = vec3(sin(t), cos (t), 0); \
           t = abs(gl_Vertex.x * .0003); \
           s[2] = vec3(sin(t), cos (t), 0); \
           vec2 p = vec2 (s[3].x * s[2].x + s[3].z * s[2].y, -s[3].x*s[2].y + s[3].z * s[2].x); \
           s[3].xz = p; \
           /*s[2] = s[3].zzx;*/ \
           t = -t * .1; \
           s[1].x = abs (gl_Vertex.x * .001); \
           for (int i = 0; i < 11; ++i) { \
           float a = float (i) / 7. * 6.28; \
           rings[i] = .4*vec3 (cos (a+t), -.25/.4, sin (a+t)); } \
    }";

const char *fsh = "\
            varying vec3 s[4]; \
           varying vec3 rings[11]; \
\
float sphere(vec3 p, vec3 c, float sr) { \
                float r = length(c-p); \
                return r-sr;                \
            }   \
\
float plane(vec3 p, vec3 n, float d) {\
p.y += .05 * sin (length(p)*12 + s[3].x*1.5); \
return dot (p, n) - d; \
} \
float ring(vec3 p) { \
  float d = sphere (p, rings[0], 0.1); \
  for (int i = 1; i < 7; ++i) \
  d = min (d, sphere (p, rings[i], 0.1));\
    return d;\
    }\
            float distance(vec3 p) { \
                return min (        \
                    min (   \
                        min (   \
                            sphere (p, vec3 (0, 0, 0), 0.25),   \
                            ring (p)),  \
                        plane (p, vec3 (0, 1, 0), -0.35)),  \
                    min (   \
                        sphere (p, s[3]*0.4, 0.2),  \
                        sphere (p, -s[3]*0.4, 0.15))    \
                        ); \
            } \
            vec3 normal (vec3 p) \
            {   \
                float ep = .00001; \
                vec3 n = vec3 (distance (vec3 (p.x + ep, p.y, p.z)) - distance (vec3 (p.x - ep, p.y, p.z)), \
                               distance (vec3 (p.x, p.y + ep, p.z)) - distance (vec3 (p.x, p.y - ep, p.z)), \
                               distance (vec3 (p.x, p.y, p.z + ep)) - distance (vec3 (p.x, p.y, p.z - ep)));    \
               n = normalize (n);\
               return n; \
               } \
               vec3 diffuse (vec3 p) \
               {    \
                 return vec3 (1.); \
               } \
               float ao (vec3 p, vec3 n) \
               {    \
                    float a = 1.;\
                    for (int i = 1; i < 4; ++i) {\
                        vec3 s = p + i * .05 * n;\
                        float d = distance (s);\
                        a -= 10. * pow (.5, i) * (.05 * i - d);\
                    }\
                    return min (1., max (0., a)); \
               }    \
            vec4 shade(vec3 eyevec, vec3 p, float r, float cost) \
            {   \
                /*return vec4 (0, cost, 0.5, 1);*/ \
                /*return vec4 (0, 1, 0, 1);*/ \
                /*return vec4 (frac(p*10.), 1);*/ \
                \
                /*float dp = plane (p, vec3 (0, 1, 0), -0.35);\
                float dr = r;   \
                vec3  dpp = p;  \
                */\
                vec3 n = normal (p);    \
               /*return vec4 ( n*.5+.5, 1);*/ \
               vec3 light = vec3 (1, 1, -3); \
               vec3 l = normalize (light - p); \
               float dfs = diffuse (p) * max (0., dot (n, l)); /* half life2 -> */ /*float dfs = .7*diffuse (p) * (.5+.5*dot (n, l));*/ \
               dfs *= ao (p, n); \
               \
               vec3 ref = reflect(eyevec, n);   \
               vec3 oldp = p; \
               p += 0.025 * ref;    \
               vec4 refl = vec4 (0);    \
               for (int i =0; i < 32; ++i) {\
                r = distance(p);\
                if (r < 0) { p += r*.5*ref; n = normal(p); l = normalize(light-p); float dfs2 = max (0., /*(.5+.5* */ dot (n, l)) * ao (p, n); dfs += dfs2*dfs2 * .4; break; } \
                oldp = p; \
                p += max (.0125, r) * ref;  \
                if (p.z > 0.5) break; \
                } \
               \
               vec3 rgb = vec3 (dfs, dfs, dfs); \
               /*if (abs (dp - dr) < .01) { \
                   rgb.r *= step (0.5, frac (dpp.x));   \
                   rgb.g *= step (0.5, frac (dpp.z));   \
               }*/  \
               return refl + vec4 (rgb, 1); \
            }   \
                \
            void main() { \
            vec3 px= gl_FragCoord.xyz;  \
            px.x /= 1024.; px.y /= 1024.; \
            /*px.x /= 512.; px.y /= 512.;*/ \
            px = px * 2 - 1; px.z = 0; px.y -= 0.25; px.x *= 0.85; \
            vec3 p=vec3(0,14.5,-20), d = normalize(px*.85 -p);  \
    \
    /*gl_FragColor= vec4 (d.z, d.z, 1, 1); return;*/ \
            float r; vec3 oldp = p; \
            vec3 origin = p; \
            for (int i =0; i < 64; ++i) {\
                r = distance(p);\
                if (r < 0) { gl_FragColor=shade(d, oldp+r*.5*d, r, i/64.); return; } \
                oldp = p; \
                float minstep = .0125;  \
                /*minstep *= max (1., .5*length(p-origin));*/   \
                p += max (minstep, r) * d;  \
                /*r = distance(p);\
                gl_FragColor=vec4 (0, r, 0, 1); return;*/ \
                if (p.z > .7) { gl_FragColor=vec4(0.1,0.1,0.1,1); return; }  \
                }\
\
gl_FragColor=vec4(1,0.2,0,1);\
    }";


PIXELFORMATDESCRIPTOR pfd =
{ 0, 1, PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, 32, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0 };

DEVMODE dmScreenSettings = { 0,0,0,sizeof(DEVMODE),0,DM_PELSWIDTH|DM_PELSHEIGHT,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1024,768,0,0,0,0,0,0,0,0,0,0};

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    HRESULT HR = ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);
    //HDC hDC = GetDC(CreateWindow("edit",0,/*WS_POPUP |*/ WS_VISIBLE /*| WS_MAXIMIZE*/, 0, 0, 512, 512, 0, 0, 0, 0));
    HDC hDC = GetDC(CreateWindow("edit",0,/*WS_POPUP |*/ WS_VISIBLE /*| WS_MAXIMIZE*/, 0, 0, 1024, 1024, 0, 0, 0, 0));
    //HDC hDC = GetDC(CreateWindow("edit",0,WS_POPUP | WS_VISIBLE | WS_MAXIMIZE, 0, 0, 1920, 1200, 0, 0, 0, 0));
    SetPixelFormat(hDC, ChoosePixelFormat(hDC, &pfd), &pfd);
    wglMakeCurrent(hDC, wglCreateContext(hDC));
    ShowCursor(0);
    GLuint p = ((PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram"))();
    GLuint s = ((PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader"))(GL_VERTEX_SHADER);

    ((PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource"))(s, 1, &vsh, 0);
    ((PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader"))(s);
    ((PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader"))(p,s);
    s = ((PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader"))(GL_FRAGMENT_SHADER);
    ((PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource"))(s,1,&fsh,0);
    ((PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader"))(s);
    ((PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader"))(p,s);
    ((PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram"))(p);
    ((PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram"))(p);

loop:
    MSG msg;
    if (PeekMessage (&msg, 0, 0, 0, 1))
        ;
    int t = GetTickCount();
    glRecti (t, t, -t, -t);
    //glRecti (-512, -384, 512, 386);
    SwapBuffers(hDC);
    if (GetAsyncKeyState(VK_ESCAPE)) ExitProcess(0);
    goto loop;

    return 0;
}