From 9c89460e136ed6c6c43704d9a3a15105e0f006b0 Mon Sep 17 00:00:00 2001
From: chai <chaifix@163.com>
Date: Sat, 22 Feb 2020 18:17:06 +0800
Subject: *wog

---
 src/config.h                        |   8 +
 src/core/device.c                   |   1 +
 src/core/rasterizer.c               |  14 +-
 src/core/shader.h                   |   1 +
 src/core/vert.h                     |   5 +-
 src/example/01_dot/01_dot.c         |   1 -
 src/example/02_cube/02_cube.c       |   1 -
 src/example/03_texture/03_texture.c |   9 +-
 src/example/04_bloom/04_bloom.c     |   1 -
 src/example/example.h               |  10 +-
 src/extend/mesh.h                   |   1 +
 src/extern/wog.c                    | 666 ++++++++++++++++++++++++++++++++++++
 src/extern/wog.h                    | 140 ++++++++
 src/main.c                          |  54 ++-
 src/math/mat.c                      |   2 +-
 src/math/math.h                     |   1 +
 src/math/vec4.c                     |   9 +
 src/shaders/common.h                |  45 ++-
 src/window.h                        |   8 +
 19 files changed, 908 insertions(+), 69 deletions(-)
 create mode 100644 src/config.h
 create mode 100644 src/extern/wog.c
 create mode 100644 src/extern/wog.h
 create mode 100644 src/window.h

diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..43c45af
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,8 @@
+#ifndef _SOFTSHADEROOM_CONFIG_H_
+#define _SOFTSHADEROOM_CONFIG_H_
+
+#define WIN32 1 
+
+#define PLATFORM WIN32
+
+#endif
\ No newline at end of file
diff --git a/src/core/device.c b/src/core/device.c
index 23e4bb3..70ae11f 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -500,6 +500,7 @@ static void render_prims_triangle(uint varying_flag) {
 
 		/*back face culling*/
 		if (ssr_isenable(ENABLE_BACKFACECULL)) {
+			/*cull in ndc*/
 			float w0 = 1 / c0->w, w1 = 1 / c1->w, w2 = 1 / c2->w;
 			Vec3 ab, ac;
 			ab.x = c1->x * w1 - c0->x * w0;
diff --git a/src/core/rasterizer.c b/src/core/rasterizer.c
index a7d3544..d6a9fc1 100644
--- a/src/core/rasterizer.c
+++ b/src/core/rasterizer.c
@@ -92,17 +92,17 @@ void ssrR_triangle(
 ) {
 	ssr_assert(CA && CB && CC && program);
 
-	Vec3 SA, SB, SC;
-	vec4_dividew(CA, &SA); ssrU_viewport(&SA, &SA);
-	vec4_dividew(CB, &SB); ssrU_viewport(&SB, &SB);
-	vec4_dividew(CC, &SC); ssrU_viewport(&SC, &SC);
+	Vec4 SA, SB, SC;
+	vec4_dividewnoz(CA, &SA); ssrU_viewport(&SA, &SA);
+	vec4_dividewnoz(CB, &SB); ssrU_viewport(&SB, &SB);
+	vec4_dividewnoz(CC, &SC); ssrU_viewport(&SC, &SC);
 
 /*
 	puttriangle(&SA, &SB, &SC, 0xffff0000);
 	return;
 */
 
-	Vec3 *sa = &SA, *sb = &SB, *sc = &SC, *tmp; 
+	Vec4 *sa = &SA, *sb = &SB, *sc = &SC, *tmp; 
 	Vec4 *v4tmp; 
 	uint itmp;
 #define swap(t, a, b) {t = a; a = b; b = t;} /*sort in y axis*/
@@ -163,7 +163,9 @@ void ssrR_triangle(
 			vec3_scale(&bc, 1.f / (bc.x + bc.y + bc.z), &bc);                 \
 			/*early depth testing*/																			      \
 			if(depth_test){											                              \
-				depth = bc.x*sa->z+bc.y*sb->z+bc.z*sc->z;                       \
+				depth = bc.x*sa->z + bc.y*sb->z + bc.z*sc->z;										\
+				depth /= bc.x*sa->w + bc.y*sb->w + bc.z*sc->w;									\
+				/*depth = bc.x*sa->z+bc.y*sb->z+bc.z*sc->z;*//*wrong*/          \
 				pass_depth_test = ssr_testdepth(p.x, p.y, depth);					      \
 			}																														      \
 			/*early stencil testing*/																			    \
diff --git a/src/core/shader.h b/src/core/shader.h
index 3737e8c..26606b8 100644
--- a/src/core/shader.h
+++ b/src/core/shader.h
@@ -152,6 +152,7 @@ typedef struct {
 	byte* output; /*fragment-in*/
 } ActiveReg;
 
+/*interpolation registers*/
 Register registers[REG_TOTAL];
 ActiveReg active_regs[REG_TOTAL];
 
diff --git a/src/core/vert.h b/src/core/vert.h
index 8578d87..6c968b5 100644
--- a/src/core/vert.h
+++ b/src/core/vert.h
@@ -22,16 +22,15 @@ Color color32_tocolor(Color32* c);
 void color_tocolor32(Color c, Color32* out);
 void color32_saturate(Color32* c);
 
-/*readonly*/
 typedef struct Vert {
 	uint index;
 	Vec3 position;
 	Vec3 normal;
-	Vec4 tangent;
+	Vec4 tangent; // w for handness
 	Vec2 texcoord;
 	Color color;
 /*
-	Vec2 texcoord1;
+	Vec2 texcoord1; // for lightmap
 	Vec4 joint;
 	Vec4 weight;
 */
diff --git a/src/example/01_dot/01_dot.c b/src/example/01_dot/01_dot.c
index e2902ca..3305137 100644
--- a/src/example/01_dot/01_dot.c
+++ b/src/example/01_dot/01_dot.c
@@ -10,7 +10,6 @@ void onloaddot(void* data) {
 }
 
 void oneventdot(void* data) {
-	SDL_Event* e = (SDL_Event*)data;
 }
 
 void onupdatedot(void*data) {
diff --git a/src/example/02_cube/02_cube.c b/src/example/02_cube/02_cube.c
index 4e540e0..7e0840e 100644
--- a/src/example/02_cube/02_cube.c
+++ b/src/example/02_cube/02_cube.c
@@ -26,7 +26,6 @@ void onloadcube(void* data) {
 }
 
 void oneventcube(void* data) {
-	SDL_Event* e = (SDL_Event*)data;
 }
 
 float _t = 0;
diff --git a/src/example/03_texture/03_texture.c b/src/example/03_texture/03_texture.c
index ab39298..f10c41a 100644
--- a/src/example/03_texture/03_texture.c
+++ b/src/example/03_texture/03_texture.c
@@ -40,7 +40,7 @@ static Mesh* yingham_mesh;
 static Texture* cyborg_albedo;
 static Mesh* cyborg_mesh;
 
-void onloadtexture(void* data) {
+void onload_texture(void* data) {
 	ssr_matrixmode(MATRIX_PROJECTION);
 	ssr_loadidentity();
 	ssr_perspective(90, ssr_getaspect(), 0.1, 10);
@@ -66,14 +66,13 @@ void onloadtexture(void* data) {
 	cyborg_mesh = mesh_loadfromobj("res/cyborg/cyborg.obj");
 }
 
-void oneventtexture(void* data) {
-	SDL_Event* e = (SDL_Event*)data;
+void onevent_texture(void* data) {
 }
 
 static float _t = 0;
 static Quat q;
 
-void onupdatetexture(void*data) {
+void onupdate_texture(void*data) {
 	uint dt = *(uint*)data;
 	_t += dt / 1000.f;
 
@@ -100,7 +99,7 @@ void onupdatetexture(void*data) {
 	ssr_setuniformmat4(0, &world2object);
 }
 
-void ondrawtexture(void*data) {
+void ondraw_texture(void*data) {
 	ssr_clearcolor(0xff202020);
 	ssr_cleardepth();
 	ssr_clearstencil(0);
diff --git a/src/example/04_bloom/04_bloom.c b/src/example/04_bloom/04_bloom.c
index 4a79669..037a9e1 100644
--- a/src/example/04_bloom/04_bloom.c
+++ b/src/example/04_bloom/04_bloom.c
@@ -58,7 +58,6 @@ void onloadbloom(void* data) {
 }
 
 void oneventbloom(void* data) {
-	SDL_Event* e = (SDL_Event*)data;
 }
 
 static float _t = 0;
diff --git a/src/example/example.h b/src/example/example.h
index 6cb9a64..bcf9ebc 100644
--- a/src/example/example.h
+++ b/src/example/example.h
@@ -3,13 +3,13 @@
 
 #include "../ssr.h"
 #include "../util/type.h"
-#include "SDL2/SDL.h"
+//#include "SDL2/SDL.h"
 
 #define EXAMPLE(i)\
-extern void onload##i(void*);\
-extern void onevent##i(void*);\
-extern void onupdate##i(void*);\
-extern void ondraw##i(void*);
+extern void onload_##i(void*);\
+extern void onevent_##i(void*);\
+extern void onupdate_##i(void*);\
+extern void ondraw_##i(void*);
 
 #define EXAMPLECUR       texture
 
diff --git a/src/extend/mesh.h b/src/extend/mesh.h
index 2c52669..aa2a398 100644
--- a/src/extend/mesh.h
+++ b/src/extend/mesh.h
@@ -3,6 +3,7 @@
 
 #include "../core/vert.h"
 
+//
 typedef struct Mesh {
 	Vert* vertices; uint vert_count;
 	uint* triangles; uint tris_count;
diff --git a/src/extern/wog.c b/src/extern/wog.c
new file mode 100644
index 0000000..7b8af8d
--- /dev/null
+++ b/src/extern/wog.c
@@ -0,0 +1,666 @@
+/**
+* Copyright (c) 2015~2017 chai(neonum)
+*
+* This library is free software; you can redistribute it and/or modify it
+* under the terms of the MIT license. See LICENSE for details.
+*/
+
+#include "wog.h"
+#include <windows.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <memory.h>
+#include <assert.h>
+
+#if WOG_API == WOG_GL
+#include <gl/GL.h>
+#include <gl/GLU.h>
+#endif
+
+
+#if WOG_API == WOG_GL
+/**
+* We need opengl32.lib and glu32.lib for using opengl functions on 
+* windows platform. 
+*/
+#pragma comment( lib, "opengl32.lib" )                                        
+#pragma comment( lib, "glu32.lib" )                                            
+#endif
+
+#define WINDOW_CLASS "WOG_WND"
+
+#define heap_alloc(T, C)  (T*)malloc(sizeof(T)*(C))
+#define stack_alloc(T, C) (T*)alloca(sizeof(T)*(C))
+#define zero_mem(I, L)    memset(I, 0, L)
+
+#define max(a, b) (a < b ? b : a) 
+#define min(a, b)  (a < b ? a : b)  
+#define clamp(x, minv, maxv)  (max(minv, min(x, maxv)))
+
+typedef struct wog_Window
+{
+    HWND  hwnd; // Window handler 
+    HDC   hdc;  // Device Context
+#if WOG_API == WOG_GDI 
+		wog_Surface* surface; // render buffer
+#endif
+}wog_Window;
+
+#if WOG_API == WOG_GL 
+typedef struct wog_GLContext
+{
+    HGLRC hrc; // Rendering Context
+}wog_GLContext;
+#endif
+
+
+void wog_handleEvent(wog_Window* window, MSG* msg, wog_Event* e)
+{
+    UINT uMsg;
+    WPARAM wParam;
+    LPARAM lParam;
+    uMsg = msg->message;
+    wParam = msg->wParam;
+    lParam = msg->lParam;
+    HWND hWnd = window->hwnd;
+
+    switch (uMsg)
+    {
+    case WM_SYSCOMMAND:
+    {
+        switch (wParam)
+        {
+        case SC_SCREENSAVE:
+        case SC_MONITORPOWER:
+            return ;
+        }
+        break;
+    }
+    return ;
+
+    case WM_CLOSE:
+    {
+        zero_mem(e, sizeof(wog_Event));
+        e->type = WOG_ECLOSE;
+        return ;
+    }
+
+    case WM_KEYDOWN:
+        if ((wParam >= 0) && (wParam <= 255))
+        {
+            zero_mem(e, sizeof(wog_Event));
+            e->type = WOG_EKEYDOWN;
+            e->key = wParam;
+
+            return ;
+        }
+        break;
+
+    case WM_KEYUP:
+        if ((wParam >= 0) && (wParam <= 255))
+        {
+            zero_mem(e, sizeof(wog_Event));
+            e->type = WOG_EKEYUP;
+            e->key = wParam;
+
+            return ;
+        }
+        break;
+
+    case WM_MOUSEMOVE:
+    {
+        zero_mem(e, sizeof(wog_Event));
+        e->type = WOG_EMOUSEMOTION;
+        wog_getMouse(window, &e->pos.x, &e->pos.y);
+
+        return ;
+    }
+
+    case WM_MOUSEWHEEL: // mousewheel scroll 
+    {
+        int zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
+        zero_mem(e, sizeof(wog_Event));
+        e->type = WOG_EMOUSEWHEEL;
+        e->wheel = zDelta > 0 ? 1 : -1;
+        return ;
+    }
+
+    case WM_LBUTTONDOWN:
+    {
+        zero_mem(e, sizeof(wog_Event));
+        e->type = WOG_EMOUSEBUTTONDOWN;
+        e->button = WOG_MOUSE_LBUTTON;
+        return ;
+    }
+
+    case WM_RBUTTONDOWN:
+    {
+        zero_mem(e, sizeof(wog_Event));
+        e->type = WOG_EMOUSEBUTTONDOWN;
+        e->button = WOG_MOUSE_RBUTTON;
+        return ;
+    }
+
+    case WM_MBUTTONDOWN:
+    {
+        zero_mem(e, sizeof(wog_Event));
+        e->type = WOG_EMOUSEBUTTONDOWN;
+        e->button = WOG_MOUSE_MIDDLE;
+        return ;
+    }
+
+    case WM_LBUTTONUP:
+    {
+        zero_mem(e, sizeof(wog_Event));
+        e->type = WOG_EMOUSEBUTTONUP;
+        e->button = WOG_MOUSE_LBUTTON;
+        return ;
+    }
+
+    case WM_RBUTTONUP:
+    {
+        zero_mem(e, sizeof(wog_Event));
+        e->type = WOG_EMOUSEBUTTONUP;
+        e->button = WOG_MOUSE_RBUTTON;
+        return ;
+    }
+
+    case WM_MBUTTONUP:
+    {
+        zero_mem(e, sizeof(wog_Event));
+        e->type = WOG_EMOUSEBUTTONUP;
+        e->button = WOG_MOUSE_MIDDLE;
+        return ;
+    }
+
+    break;
+
+    default:
+        e->type = WOG_EUNKNOWN;
+        break;
+    }
+    DefWindowProc(hWnd, uMsg, wParam, lParam);
+    return ;
+}
+
+
+int wog_pollEvent(wog_Window* wnd, wog_Event* e)
+{
+    MSG msg;
+    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+    {
+        if (msg.message == WM_QUIT) return 0;
+        TranslateMessage(&msg);
+        wog_handleEvent(wnd, &msg, e);
+        return 1;
+    }
+    return 0;
+}
+
+
+// on size changed callback;
+static wog_Callback onSizeChanged = 0;
+static wog_Callback onQuit = 0;
+
+
+static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    // Get The Window Context
+    wog_Window* window = (wog_Window*)(GetWindowLong(hWnd, GWL_USERDATA));
+
+    // call callback functions 
+#define call(callback)\
+    if (callback) \
+        callback(window) 
+
+    switch (uMsg)
+    {
+    case WM_CREATE:
+    {
+        CREATESTRUCT* creation = (CREATESTRUCT*)(lParam);  // Store Window Structure Pointer
+        window = (wog_Window*)(creation->lpCreateParams);  // Get wog_Window
+        SetWindowLong(hWnd, GWL_USERDATA, (LONG)(window)); // Save it 
+    }
+    return 0;
+
+    case WM_CLOSE:                                         // Post WM_CLOSE to message queue. 
+        PostMessage(hWnd, WM_CLOSE, wParam, lParam);
+        return 0;
+
+    case WM_SIZE:
+        call(onSizeChanged);
+        return 0;
+
+    case WM_QUIT:
+        call(onQuit);
+        return 0;
+
+    }
+
+    return DefWindowProc(hWnd, uMsg, wParam, lParam);
+#undef call
+}
+
+
+void wog_registerResizeCallback(wog_Callback cal)
+{
+    onSizeChanged = cal;
+}
+
+
+void wog_registerQuitCallback(wog_Callback cal)
+{
+    onQuit = cal; 
+}
+
+wog_Surface* wog_getsurface(wog_Window* wnd) {
+	return wnd->surface;
+}
+
+static int registerWindowClass()
+{
+    // Register A Window Class
+    WNDCLASSEX windowClass;                                         // Window Class
+    zero_mem(&windowClass, sizeof(WNDCLASSEX));                     // Make Sure Memory Is Cleared
+
+    windowClass.cbSize        = sizeof(WNDCLASSEX);                 // Size Of The windowClass Structure
+    windowClass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraws The Window For Any Movement / Resizing
+    windowClass.lpfnWndProc   = (WNDPROC)(WindowProc);              // WindowProc Handles Messages
+    windowClass.hInstance     = GetModuleHandle(0);                 // Set The Instance
+    windowClass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE);       // Class Background Brush Color
+    windowClass.hCursor       = LoadCursor(NULL, IDC_ARROW);        // Load The Arrow Pointer
+    windowClass.lpszClassName = WINDOW_CLASS;                       // Sets The Applications Classname
+
+    if (RegisterClassEx(&windowClass) == 0)                         // Did Registering The Class Fail?
+    {
+        // NOTE: Failure, Should Never Happen
+        MessageBox(HWND_DESKTOP, "RegisterClassEx Failed!", "Error", MB_OK | MB_ICONEXCLAMATION);
+        return FALSE;                                               // Return False (Failure)
+    }
+    return TRUE;
+}
+
+static void create_surface(HWND handle, int width, int height, wog_Surface **out_surface, HDC *out_memory_dc) {
+	BITMAPINFOHEADER bi_header;
+	HDC window_dc;
+	HDC memory_dc;
+	HBITMAP dib_bitmap;
+	HBITMAP old_bitmap;
+	unsigned char *buffer; // color buffer
+	wog_Surface *surface;
+
+	window_dc = GetDC(handle);
+	memory_dc = CreateCompatibleDC(window_dc);
+	ReleaseDC(handle, window_dc);
+
+	memset(&bi_header, 0, sizeof(BITMAPINFOHEADER));
+	bi_header.biSize = sizeof(BITMAPINFOHEADER);
+	bi_header.biWidth = width;
+	bi_header.biHeight = -height;  /* top-down */
+	bi_header.biPlanes = 1;
+	bi_header.biBitCount = 32;
+	bi_header.biCompression = BI_RGB;
+	dib_bitmap = CreateDIBSection(memory_dc, (BITMAPINFO*)&bi_header,
+		DIB_RGB_COLORS, (void**)&buffer, NULL, 0);
+	assert(dib_bitmap != NULL);
+	old_bitmap = (HBITMAP)SelectObject(memory_dc, dib_bitmap);
+	DeleteObject(old_bitmap);
+
+	surface = (wog_Surface*)malloc(sizeof(wog_Surface));
+	surface->width = width;
+	surface->height = height;
+	surface->channels = 4;
+	surface->buffer = buffer;
+
+	*out_surface = surface;
+	*out_memory_dc = memory_dc;
+}
+
+
+wog_Window* wog_createWindow(const char* title, int width, int height, int x, int y, uint32 flags)
+{
+		int client_w = width, client_h = height;
+
+    if (! registerWindowClass())
+    {
+        printf("Register window class failed.\n");
+        return 0;
+    }
+
+    wog_Window* wnd = heap_alloc(wog_Window, 1);
+    zero_mem(wnd, sizeof(wog_Window));
+
+    DWORD windowStyle = 0;     // Define Our Window Style
+    windowStyle |= WS_POPUP;
+    windowStyle |= WS_OVERLAPPED;
+    windowStyle |= WS_CAPTION; 
+    windowStyle |= WS_SYSMENU; 
+    windowStyle |= WS_MINIMIZEBOX;
+    windowStyle |= WS_VISIBLE;
+#define hasbit(fs, f) ((fs & f) == f)
+    if (hasbit(flags, WOG_RESIZABLE)) windowStyle |= WS_SIZEBOX; 
+    if (hasbit(flags, WOG_DISABLE)) windowStyle |= WS_DISABLED;
+
+    DWORD windowExtendedStyle = WS_EX_APPWINDOW; // Define The Window's Extended Style
+
+    PIXELFORMATDESCRIPTOR pfd =           // pfd Tells Windows How We Want Things To Be
+    {
+        sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
+        1,                             // Version Number
+        PFD_DRAW_TO_WINDOW |           // Format Must Support Window
+#if WOG_API == WOG_GL
+        PFD_SUPPORT_OPENGL |           // Format Must Support OpenGL
+#endif
+        PFD_DOUBLEBUFFER,              // Must Support Double Buffering
+        PFD_TYPE_RGBA,                 // Request An RGBA Format
+        32,                            // Select Our Color Depth
+        0, 0, 0, 0, 0, 0,              // Color Bits Ignored
+        0,                             // No Alpha Buffer
+        0,                             // Shift Bit Ignored
+        0,                             // No Accumulation Buffer
+        0, 0, 0, 0,                    // Accumulation Bits Ignored
+        16,                            // 16Bit Z-Buffer (Depth Buffer)  
+        0,                             // No Stencil Buffer
+        0,                             // No Auxiliary Buffer
+        PFD_MAIN_PLANE,                // Main Drawing Layer
+        0,                             // Reserved
+        0, 0, 0                        // Layer Masks Ignored
+    };
+    RECT windowRect = { 0, 0, width, height };
+    AdjustWindowRectEx(&windowRect, windowStyle, 0, windowExtendedStyle);
+    width = windowRect.right - windowRect.left;
+    height = windowRect.bottom - windowRect.top;
+    wnd->hwnd = CreateWindowEx(
+        windowExtendedStyle,
+        WINDOW_CLASS,
+        title, 
+        windowStyle, 
+        x, y, 
+        width, height,
+        HWND_DESKTOP, 
+        0, 
+        GetModuleHandle(0), 
+        wnd
+        );
+
+    if (wnd->hwnd == 0)
+        return 0;
+
+    if (hasbit(flags, WOG_HIDDEN)) wog_hide(wnd);
+
+    // init device context 
+    wnd->hdc = GetDC(wnd->hwnd); 
+    if (wnd->hdc== 0)
+    {
+        DestroyWindow(wnd->hwnd);
+        wnd->hwnd = 0; 
+        return 0;
+    }
+
+#if WOG_API == WOG_GDI 
+		create_surface(wnd->hwnd, client_w, client_h, &wnd->surface, &wnd->hdc);
+#endif
+
+#if WOG_API == WOG_GL 
+    // set pixel format 
+    unsigned int pixelformat; 
+    pixelformat = ChoosePixelFormat(wnd->hdc, &pfd);
+    if (pixelformat == 0)                                    
+    {
+        wog_destroyWindow(wnd);
+        return 0;
+    }
+
+    // set pixel format 
+    if (SetPixelFormat(wnd->hdc, pixelformat, &pfd) == 0 )
+    {
+        wog_destroyWindow(wnd); 
+        return 0; 
+    }
+#endif
+
+    return wnd;
+}
+
+#if WOG_API == WOG_GL 
+wog_GLContext* wog_createGLContext(wog_Window* wnd)
+{
+    wog_GLContext* cxt = heap_alloc(wog_GLContext, 1);
+    zero_mem(cxt, sizeof(wog_GLContext));
+    cxt->hrc = wglCreateContext(wnd->hdc); // create opengl context base on device context 
+    if (cxt->hrc == 0)
+    {
+        free(cxt);
+        return 0;
+    }
+    return cxt; 
+}
+#endif
+
+#if WOG_API == WOG_GL 
+int wog_makeCurrent(wog_Window* wnd, wog_GLContext* cxt)
+{
+    if (wnd && cxt)
+    {
+        if (wglMakeCurrent(wnd->hdc, cxt->hrc) == 0)
+        {
+            return 0; 
+        }    
+        return 1; 
+    }
+
+    return 0; 
+}
+#endif
+
+#if WOG_API == WOG_GL 
+void wog_destroyGLContext(wog_GLContext* cxt)
+{
+    if (cxt && cxt->hrc)
+    {
+        wglDeleteContext(cxt->hrc);
+        free(cxt);
+    }
+}
+#endif
+
+void wog_updateSurface(wog_Window* wnd) {
+	HDC window_dc = GetDC(wnd->hwnd);
+	HDC memory_dc = wnd->hdc;
+	wog_Surface *surface = wnd->surface;
+	int width = surface->width;
+	int height = surface->height;
+	BitBlt(window_dc, 0, 0, width, height, memory_dc, 0, 0, SRCCOPY);
+	ReleaseDC(wnd->hwnd, window_dc);
+}
+
+void wog_destroyWindow(wog_Window* wnd)
+{
+    if (wnd)
+    {
+        ReleaseDC(wnd->hwnd, wnd->hdc);
+        DestroyWindow(wnd->hwnd);
+        free(wnd);
+    }
+}
+
+
+static void UnEscapeQuotes(char *arg)
+{
+    char *last = NULL;
+
+    while (*arg) {
+        if (*arg == '"' && *last == '\\') {
+            char *c_curr = arg;
+            char *c_last = last;
+
+            while (*c_curr) {
+                *c_last = *c_curr;
+                c_last = c_curr;
+                c_curr++;
+            }
+            *c_last = '\0';
+        }
+        last = arg;
+        arg++;
+    }
+}
+
+
+/* Parse a command line buffer into arguments */
+static int ParseCommandLine(char *cmdline, char **argv)
+{
+    char *bufp;
+    char *lastp = NULL;
+    int argc, last_argc;
+
+    argc = last_argc = 0;
+    for (bufp = cmdline; *bufp; ) {
+        /* Skip leading whitespace */
+        while (isspace(*bufp)) {
+            ++bufp;
+        }
+        /* Skip over argument */
+        if (*bufp == '"') {
+            ++bufp;
+            if (*bufp) {
+                if (argv) {
+                    argv[argc] = bufp;
+                }
+                ++argc;
+            }
+            /* Skip over word */
+            while (*bufp && (*bufp != '"' || (lastp && *lastp == '\\'))) {
+                lastp = bufp;
+                ++bufp;
+            }
+        }
+        else {
+            if (*bufp) {
+                if (argv) {
+                    argv[argc] = bufp;
+                }
+                ++argc;
+            }
+            /* Skip over word */
+            while (*bufp && !isspace(*bufp)) {
+                ++bufp;
+            }
+        }
+        if (*bufp) {
+            if (argv) {
+                *bufp = '\0';
+            }
+            ++bufp;
+        }
+
+        /* Strip out \ from \" sequences */
+        if (argv && last_argc != argc) {
+            UnEscapeQuotes(argv[last_argc]);
+        }
+        last_argc = argc;
+    }
+    if (argv) {
+        argv[argc] = NULL;
+    }
+    return(argc);
+} 
+
+
+#ifdef main 
+#undef main 
+#endif
+
+
+#if defined(_MSC_VER) && !defined(_WIN32_WCE)
+/* The VC++ compiler needs main defined */
+#define console_main main
+#endif
+
+extern int wog_main(int argc, char* argv[]); 
+
+/**
+* Entry of console application.
+*/
+int console_main(int argc, char* argv[])
+{
+    int status = wog_main(argc, argv); 
+    return status;
+}
+
+
+/**
+* Entry of windows application. 
+*/
+int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
+{
+    char* temp = GetCommandLine();
+    int len = strlen(temp) + 1; 
+    char* cmd = stack_alloc(char, len); 
+    strcpy(cmd, temp);
+    cmd[len - 1] = '\0';
+
+    int argc = 0; 
+    char** argv = 0;
+    argc = ParseCommandLine(cmd, 0);
+    ParseCommandLine(cmd, 0);
+    argv = stack_alloc(char*, argc + 1); 
+    ParseCommandLine(cmd, argv);
+
+    int status = console_main(argc, argv); 
+
+    return 0;
+}
+
+
+void wog_swapBuffers(wog_Window* wnd)
+{
+    if (wnd)
+    {
+        SwapBuffers(wnd->hdc);
+    }
+}
+
+
+void wog_getMouse(wog_Window* wnd, int *x, int *y)
+{
+    POINT p;
+    GetCursorPos(&p); 
+    ScreenToClient(wnd->hwnd, &p);
+    int w, h; 
+    wog_getwindowsize(wnd, &w, &h); 
+    *x = clamp(p.x, 0, w); 
+    *y = clamp(p.y, 0, h);
+}
+
+
+void wog_getwindowsize(wog_Window* wnd, int* width, int* height)
+{
+    RECT r; 
+    GetClientRect(wnd->hwnd, &r);
+    *width = r.right;
+    *height = r.bottom;
+}
+
+
+void wog_show(wog_Window* wnd)
+{
+    ShowWindow(wnd->hwnd, SW_SHOW);
+}
+
+
+void wog_hide(wog_Window* wnd)
+{
+    ShowWindow(wnd->hwnd, SW_HIDE);
+}
+
+
+void wog_sleep(int ms)
+{
+    Sleep(ms);
+}
+
+int wog_tick()
+{
+    return GetTickCount();
+}
\ No newline at end of file
diff --git a/src/extern/wog.h b/src/extern/wog.h
new file mode 100644
index 0000000..f616d82
--- /dev/null
+++ b/src/extern/wog.h
@@ -0,0 +1,140 @@
+/**
+* Copyright (c) 2015~2017 chai(neonum)
+*
+* This library is free software; you can redistribute it and/or modify it
+* under the terms of the MIT license. See LICENSE for details.
+*/
+
+#ifndef _WOG_H
+#define _WOG_H
+#include <Windows.h> // for virtual key value
+
+#define WOG_GL   1
+#define WOG_GDI  2
+
+#define WOG_API  WOG_GDI
+
+typedef unsigned int uint32; 
+typedef unsigned short uint16; 
+
+enum // event type 
+{
+    WOG_EUNKNOWN = 0,     // unknown event  
+
+    WOG_EKEYDOWN,         // key pressed 
+    WOG_EKEYUP,           // key released 
+
+    WOG_EMOUSEMOTION,     // mouse motion 
+    WOG_EMOUSEWHEEL,      // mouse wheel scrolling
+    WOG_EMOUSEBUTTONDOWN, // mosue button down 
+    WOG_EMOUSEBUTTONUP,   // mosue button down 
+
+    WOG_ECLOSE,           // close window
+};
+
+enum // mouse button event, e.button value
+{
+    WOG_MOUSE_LBUTTON, // left mouse button 
+    WOG_MOUSE_RBUTTON, // right mouse button 
+    WOG_MOUSE_MIDDLE,  // middle button 
+};
+
+typedef struct wog_Event
+{
+    int type; 
+    union             // event value 
+    {
+        int key;      // for key, simply use windows virtual key value 
+                      // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
+        struct        // for mouse motion
+        {
+            int x, y; // mouse position 
+        }pos;
+        int wheel;    // 1 indicate scroll up and -1 indicate scrool down
+        int button;   // mouse button 
+    };
+}wog_Event;
+
+typedef struct {
+	int width, height, channels;
+	unsigned char* buffer;
+} wog_Surface;
+
+/**
+* Entry of user program which defined in user project. You need provide 
+* this function's defination. 
+*/
+#define main wog_main
+extern int wog_main(int argc, char* argv[]);
+
+typedef struct wog_Window wog_Window;
+
+#if WOG_API == WOG_GL
+/**
+* Struct that hold opengl context generated by wglCreateContext() which 
+* defined in opengl32.lib 
+*/
+typedef struct wog_GLContext wog_GLContext;
+#endif
+
+enum // window style flag
+{
+    WOG_HIDDEN     = 4, 
+    WOG_RESIZABLE  = 8,
+    WOG_DISABLE    = 16, 
+};
+
+/**
+* Create window with given configures. 
+* flag would be:
+*     WOG_HIDDEN
+*     WOG_RESIZABLE
+*     WOG_DISABLE
+* or just 0;  
+*/
+wog_Window* wog_createWindow(const char* title, int width, int height, int x, int y, uint32 flags); 
+
+#if WOG_API == WOG_GL
+wog_GLContext* wog_createGLContext(wog_Window* wnd);
+
+int wog_makeCurrent(wog_Window* wnd, wog_GLContext* cxt);
+
+void wog_destroyGLContext(wog_GLContext* cxt);
+#endif
+
+void wog_destroyWindow(wog_Window* wnd);
+
+#if WOG_API == WOG_GL
+void wog_swapBuffers(wog_Window* wnd); 
+#endif
+
+#if WOG_API == WOG_GDI 
+void wog_updateSurface(wog_Window* wnd);
+#endif
+
+int wog_pollEvent(wog_Window* wnd, wog_Event* e);
+
+void wog_getMouse(wog_Window* wnd, int *x, int *y);
+
+// get current ticks
+int wog_tick(); 
+
+void wog_sleep(int ms);
+
+void wog_getwindowsize(wog_Window* wnd, int* width, int* height); 
+
+void wog_show(wog_Window* wnd);
+
+void wog_hide(wog_Window* wnd);
+
+typedef void(*wog_Callback)(wog_Window* wnd) ;
+
+/**
+* Register callback functions. 
+*/
+void wog_registerResizeCallback(wog_Callback cal);
+void wog_registerQuitCallback(wog_Callback cal);
+
+wog_Surface* wog_getsurface(wog_Window* wnd);
+
+#endif
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 4cf83e5..58615d1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,12 +1,10 @@
-#include <SDL2/SDL.h>
 #include <stdio.h>
 #include <windows.h>
 #include "math/math.h"
 #include "util/assert.h"
 #include "ssr.h"
 #include "example/example.h"
-
-SDL_Surface* suf;
+#include "extern/wog.h"
 
 #define SCREEN_WIDTH 600
 #define SCREEN_HEIGHT 480
@@ -20,7 +18,7 @@ F ondraw;
 /*macro������Ҫ��һ����*/
 /*https://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg*/
 #define SETEXAMPLEF(f, e) \
-f = f##e;
+f = f##_##e;
 
 #define SETEXAMPLE(i) \
 SETEXAMPLEF(onload, i)\
@@ -28,46 +26,35 @@ SETEXAMPLEF(ondraw, i)\
 SETEXAMPLEF(onevent, i)\
 SETEXAMPLEF(onupdate, i)
 
-int main(int argc, char* argv[])
-{
-	if (SDL_Init(SDL_INIT_EVENTS | SDL_INIT_TIMER | SDL_INIT_VIDEO) < 0)
-		return 1;
-	SDL_Window* wnd = SDL_CreateWindow("Soft Shade Room", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
-	SDL_Event e;
-	suf = SDL_GetWindowSurface(wnd);
-	/* ARGB format */
-	ssr_assert(suf->format->BitsPerPixel == 32);
-	ssr_assert(suf->format->Rshift == 16);
-	ssr_assert(suf->format->Gshift == 8);
-	ssr_assert(suf->format->Bshift == 0);
-
+int main(int argc, char* argv[]) {
+	wog_Window* wnd = wog_createWindow("test", SCREEN_WIDTH, SCREEN_HEIGHT, 500, 500, 0);
+	wog_show(wnd);
+	wog_Surface* surface = wog_getsurface(wnd); // ARGB format
 	/* init ssr */
 	ssr_Config config = {
 		SCREEN_WIDTH, SCREEN_HEIGHT,
 		0,
-		suf->pixels
+		surface->buffer
 	};
 	ssr_init(&config);
-
 	SETEXAMPLE(EXAMPLECUR);
-
 	onload(0);
-
 	/* main loop */
-	uint prev = SDL_GetTicks();
+	uint prev = wog_tick();
 	uint dt = 0;
 	uint frame_count = 0;
 	uint time_stamp = 0;
+	wog_Event e;
 	while (1) {
-		while (SDL_PollEvent(&e)) {
-			if (e.type == SDL_QUIT) {
+		while (wog_pollEvent(wnd, &e)) {
+			if (e.type == WOG_ECLOSE) {
 				goto quit;
 			} else {
 				onevent(&e);
 			}
 		}
-
-		dt = SDL_GetTicks() - prev;
+	
+		dt = wog_tick() - prev;
 		prev += dt;
 		time_stamp += dt;
 		++frame_count;
@@ -76,17 +63,16 @@ int main(int argc, char* argv[])
 			time_stamp -= 1000;
 			frame_count = 0;
 		}
-
+	
 		onupdate(&dt);
 		ondraw(0);
 		ssr_present();
-		SDL_UpdateWindowSurface(wnd);
-		
-		/*Sleep(1);*/ /*reduce cpu using*/
+		wog_updateSurface(wnd);
+		Sleep(1); /*reduce cpu using*/
 	}
+	
+	quit:
+	wog_destroyWindow(wnd);
 
-quit:
-	SDL_Quit();
-
-	return 0;
+	return 1;
 }
diff --git a/src/math/mat.c b/src/math/mat.c
index 8b32ba2..592dd5e 100644
--- a/src/math/mat.c
+++ b/src/math/mat.c
@@ -706,7 +706,7 @@ bool mat4_toeuler(Mat4* in, Euler* out) {
 	}
 }
 
-/*from unity src*/
+/*from unity source*/
 /*https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/*/
 void mat4_toquat(Mat4* in, Quat* out) {
 	// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
diff --git a/src/math/math.h b/src/math/math.h
index 1c2a9c0..1c65c01 100644
--- a/src/math/math.h
+++ b/src/math/math.h
@@ -179,6 +179,7 @@ void vec3_lerp(Vec3* v1, Vec3* v2, float t, Vec3* out);
 void vec3_slerp(Vec3* v1, Vec3* v2, float t, Vec3* out);
 
 void vec4_dividew(Vec4* v, Vec3* out);
+void vec4_dividewnoz(Vec4* v, Vec4* out);
 
 void vec4_tostring(Vec4* v, char buf[]);
 void vec4_print(Vec4* v);
diff --git a/src/math/vec4.c b/src/math/vec4.c
index 71ec6b6..3d6df46 100644
--- a/src/math/vec4.c
+++ b/src/math/vec4.c
@@ -16,6 +16,15 @@ void vec4_dividew(Vec4* v, Vec3* out) {
 	out->z = v->z * w;
 }
 
+void vec4_dividewnoz(Vec4* v, Vec4* out) {
+	ssr_assert(out && v);
+	float w = 1.f / v->w;
+	out->x = v->x * w;
+	out->y = v->y * w;
+	out->z = v->z;
+	out->w = v->w;
+}
+
 void vec4_tostring(Vec4* v, char buf[]) {
 	sprintf(buf, "%8.3f %8.3f %8.3f %8.3f", v->x, v->y, v->z, v->w);
 }
diff --git a/src/shaders/common.h b/src/shaders/common.h
index cae9309..7e0ca5f 100644
--- a/src/shaders/common.h
+++ b/src/shaders/common.h
@@ -1,12 +1,33 @@
 #ifndef _SOFTSHADEROOM_COMMON_HEADER_H_
 #define _SOFTSHADEROOM_COMMON_HEADER_H_
-
-/*
-** Common shader header
-*/
 #include "../core/shader.h"
 
-extern void ssrR_putline(int x0, int y0, int x1, int y1, Color color);
+/************************************************************************/
+/* constants                                                            */
+/************************************************************************/
+
+#define SSR_PI            3.14159265359f
+#define SSR_TWO_PI        6.28318530718f
+#define SSR_FOUR_PI       12.56637061436f
+#define SSR_INV_PI        0.31830988618f
+#define SSR_INV_TWO_PI    0.15915494309f
+#define SSR_INV_FOUR_PI   0.07957747155f
+#define SSR_HALF_PI       1.57079632679f
+#define SSR_INV_HALF_PI   0.636619772367f
+
+/************************************************************************/
+/* variables                                                            */
+/************************************************************************/
+
+#define _model_matrix (uniforms->model)
+#define _view_matrix (uniforms->view)
+#define _proj_matrix (uniforms->projection)
+#define _mvp_matrix (uniforms->mvp)
+#define _it_model_matrix /*inverse-transpose model matrix if needed*/
+
+/************************************************************************/
+/* functions                                                            */
+/************************************************************************/
 
 /*shader built in functions*/
 Vec3 normal_from_color(Color32 c32);
@@ -20,6 +41,8 @@ Vec2 texsize(Texture* texture);
 do{ \
 if(cond) return 0; \
 }while(0)
+#define discard()  return 0
+#define keep()     return 1
 
 #define MVP_PROCESS \
 do{																										 \
@@ -27,18 +50,16 @@ static Vec4 p; p.xyz = in->vertex->position; p.w = 1;	 \
 mat4_mulvec4(uniforms->mvp, &p, clipcoord);						 \
 }while(0)																							 
 
-#define _model_matrix (uniforms->model)
-#define _view_matrix (uniforms->view)
-#define _proj_matrix (uniforms->projection)
-#define _mvp_matrix (uniforms->mvp)
-#define _inverse_model_matrix   (uniforms->inverse_model)
-
 #define object2clip(pos, out)    mat4_mulvec4(_mvp_matrix, pos, out);
 
 /*need defined _it_model_matrix of model matrix, i-nverse, t-ranspose*/
 #define object2world_normal(normal, out)    \
 mat4_mulvec4(_it_model_matrix, normal, out)
 
-
+/*take sample from normal map and translate to normal*/
+#define unpack_normal(color, out_v3) \
+out_v3->x = color.x * 2 - 1; \
+out_v3->y = color.y * 2 - 1; \
+out_v3->z = color.z * 2 - 1; 
 
 #endif
\ No newline at end of file
diff --git a/src/window.h b/src/window.h
new file mode 100644
index 0000000..8983a89
--- /dev/null
+++ b/src/window.h
@@ -0,0 +1,8 @@
+#ifndef _SOFTSHADEROOM_WINDOW_H_
+#define _SOFTSHADEROOM_WINDOW_H_
+
+typedef struct {
+	const char* code;
+} Event;
+
+#endif
\ No newline at end of file
-- 
cgit v1.1-26-g67d0