Skip to content

Instantly share code, notes, and snippets.

@cadaver
Last active December 20, 2016 17:46
Show Gist options
  • Save cadaver/eaf784926ea394351731e319e8c6cef9 to your computer and use it in GitHub Desktop.
Save cadaver/eaf784926ea394351731e319e8c6cef9 to your computer and use it in GitHub Desktop.
Urho3D NuklearUI work in progress
/*
* Nuklear - v1.17 - public domain
* no warrenty implied; use at your own risk.
* authored from 2015-2016 by Micha Mettke
*/
/*
* ==============================================================
*
* API
*
* ===============================================================
*/
#ifndef NK_SDL_GL3_H_
#define NK_SDL_GL3_H_
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
#include "../Graphics/Graphics.h"
#include "../Graphics/Texture2D.h"
#include "../Graphics/IndexBuffer.h"
#include "../Graphics/VertexBuffer.h"
#include "../Graphics/ShaderVariation.h"
NK_API struct nk_context* nk_sdl_init(SDL_Window *win);
NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);
NK_API void nk_sdl_font_stash_end(void);
NK_API int nk_sdl_handle_event(SDL_Event *evt);
NK_API void nk_sdl_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
NK_API void nk_sdl_shutdown(void);
NK_API void nk_sdl_device_destroy(void);
NK_API void nk_sdl_device_create(void);
#endif
/*
* ==============================================================
*
* IMPLEMENTATION
*
* ===============================================================
*/
#ifdef NK_SDL_GL3_IMPLEMENTATION
#include <string.h>
struct nk_sdl_device {
struct nk_buffer cmds;
struct nk_draw_null_texture null;
Urho3D::VertexBuffer* vbuf;
Urho3D::IndexBuffer* ebuf;
//Urho3D::Vector<Urho3D::SharedPtr<Urho3D::Texture2D> > font_texs;
};
struct nk_sdl_vertex {
float position[2];
float uv[2];
nk_byte col[4];
};
static struct nk_sdl {
SDL_Window *win;
Urho3D::Graphics* graphics;
struct nk_sdl_device ogl;
struct nk_context ctx;
struct nk_font_atlas atlas;
} sdl;
NK_API void
nk_sdl_device_create(void)
{
struct nk_sdl_device *dev = &sdl.ogl;
nk_buffer_init_default(&dev->cmds);
sdl.ogl.ebuf = new Urho3D::IndexBuffer(sdl.graphics->GetContext());
sdl.ogl.vbuf = new Urho3D::VertexBuffer(sdl.graphics->GetContext());
Urho3D::Texture2D* nullTex = new Urho3D::Texture2D(sdl.graphics->GetContext());
nullTex->SetNumLevels(1);
unsigned whiteOpaque = 0xffffffff;
nullTex->SetSize(1, 1, Urho3D::Graphics::GetRGBAFormat());
nullTex->SetData(0, 0, 0, 1, 1, &whiteOpaque);
sdl.ogl.null.texture.ptr = nullTex;
}
NK_API void
nk_sdl_device_destroy(void)
{
struct nk_sdl_device *dev = &sdl.ogl;
delete dev->vbuf;
dev->vbuf = 0;
delete dev->ebuf;
dev->ebuf = 0;
delete (Urho3D::Texture2D*)(dev->null.texture.ptr);
dev->null.texture.ptr = 0;
//dev->font_texs.Clear();
nk_buffer_free(&dev->cmds);
}
NK_API void
nk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
{
struct nk_sdl_device *dev = &sdl.ogl;
sdl.graphics->SetViewport(Urho3D::IntRect(0, 0, sdl.graphics->GetWidth(), sdl.graphics->GetHeight()));
sdl.graphics->SetBlendMode(Urho3D::BLEND_ALPHA);
sdl.graphics->SetCullMode(Urho3D::CULL_NONE);
sdl.graphics->SetDepthTest(Urho3D::CMP_ALWAYS);
sdl.graphics->SetFillMode(Urho3D::FILL_SOLID);
sdl.graphics->SetColorWrite(true);
sdl.graphics->SetDepthWrite(false);
// Max. vertex / index count is not assumed to change later
if (dev->vbuf->GetVertexCount() == 0)
{
Urho3D::PODVector<Urho3D::VertexElement> elems;
elems.Push(Urho3D::VertexElement(Urho3D::TYPE_VECTOR2, Urho3D::SEM_POSITION));
elems.Push(Urho3D::VertexElement(Urho3D::TYPE_VECTOR2, Urho3D::SEM_TEXCOORD));
elems.Push(Urho3D::VertexElement(Urho3D::TYPE_UBYTE4_NORM, Urho3D::SEM_COLOR));
dev->vbuf->SetSize(max_vertex_buffer / sizeof(nk_sdl_vertex), elems, true);
}
if (dev->ebuf->GetIndexCount() == 0)
dev->ebuf->SetSize(max_element_buffer / sizeof(unsigned short), false, true);
void* vertexData = dev->vbuf->Lock(0, dev->vbuf->GetVertexCount(), true);
void* indexData = dev->ebuf->Lock(0, dev->ebuf->GetIndexCount(), true);
if (vertexData && indexData)
{
struct nk_convert_config config;
static const struct nk_draw_vertex_layout_element vertex_layout[] = {
{ NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position) },
{ NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv) },
{ NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col) },
{ NK_VERTEX_LAYOUT_END }
};
NK_MEMSET(&config, 0, sizeof(config));
config.vertex_layout = vertex_layout;
config.vertex_size = sizeof(struct nk_sdl_vertex);
config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);
config.null = dev->null;
config.circle_segment_count = 22;
config.curve_segment_count = 22;
config.arc_segment_count = 22;
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
{
struct nk_buffer vbuf, ebuf;
nk_buffer_init_fixed(&vbuf, vertexData, (nk_size)max_vertex_buffer);
nk_buffer_init_fixed(&ebuf, indexData, (nk_size)max_element_buffer);
nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);
}
Urho3D::IntVector2 viewSize = sdl.graphics->GetViewport().Size();
Urho3D::Vector2 invScreenSize(1.0f / (float)viewSize.x_, 1.0f / (float)viewSize.y_);
Urho3D::Vector2 scale(2.0f * invScreenSize.x_, -2.0f * invScreenSize.y_);
Urho3D::Matrix4 projection(Urho3D::Matrix4::IDENTITY);
projection.m00_ = scale.x_;
projection.m03_ = -1.0f;
projection.m11_ = scale.y_;
projection.m13_ = 1.0f;
projection.m22_ = 1.0f;
projection.m23_ = 0.0f;
projection.m33_ = 1.0f;
Urho3D::ShaderVariation* diffTextureVS = sdl.graphics->GetShader(Urho3D::VS, "NuklearUI", "");
Urho3D::ShaderVariation* diffTexturePS = sdl.graphics->GetShader(Urho3D::PS, "NuklearUI", "");
sdl.graphics->SetShaders(diffTextureVS, diffTexturePS);
sdl.graphics->SetVertexBuffer(dev->vbuf);
sdl.graphics->SetIndexBuffer(dev->ebuf);
sdl.graphics->SetShaderParameter(Urho3D::VSP_VIEWPROJ, projection);
unsigned offset = 0;
const struct nk_draw_command *cmd;
nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {
if (!cmd->elem_count) continue;
sdl.graphics->SetTexture(0, (Urho3D::Texture2D*)cmd->texture.ptr);
sdl.graphics->SetScissorTest(true, Urho3D::IntRect(cmd->clip_rect.x, cmd->clip_rect.y,
(cmd->clip_rect.x + cmd->clip_rect.w), (cmd->clip_rect.y + cmd->clip_rect.h)));
sdl.graphics->Draw(Urho3D::TRIANGLE_LIST, offset, cmd->elem_count, 0, 0, dev->vbuf->GetVertexCount());
offset += cmd->elem_count;
}
nk_clear(&sdl.ctx);
}
dev->vbuf->Unlock();
dev->ebuf->Unlock();
sdl.graphics->SetScissorTest(false);
}
static void
nk_sdl_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
{
const char *text = SDL_GetClipboardText();
if (text) nk_textedit_paste(edit, text, nk_strlen(text));
(void)usr;
}
static void
nk_sdl_clipbard_copy(nk_handle usr, const char *text, int len)
{
char *str = 0;
(void)usr;
if (!len) return;
str = (char*)malloc((size_t)len + 1);
if (!str) return;
memcpy(str, text, (size_t)len);
str[len] = '\0';
SDL_SetClipboardText(str);
free(str);
}
NK_API struct nk_context*
nk_sdl_init(Urho3D::Graphics* graphics)
{
sdl.graphics = graphics;
sdl.win = graphics->GetWindow();
nk_init_default(&sdl.ctx, 0);
sdl.ctx.clip.copy = nk_sdl_clipbard_copy;
sdl.ctx.clip.paste = nk_sdl_clipbard_paste;
sdl.ctx.clip.userdata = nk_handle_ptr(0);
nk_sdl_device_create();
return &sdl.ctx;
}
NK_API void
nk_sdl_font_stash_begin(struct nk_font_atlas **atlas)
{
nk_font_atlas_init_default(&sdl.atlas);
nk_font_atlas_begin(&sdl.atlas);
*atlas = &sdl.atlas;
}
NK_API void
nk_sdl_font_stash_end(void)
{
const void *image; int w, h;
image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
struct nk_sdl_device *dev = &sdl.ogl;
Urho3D::Texture2D* fontTex(new Urho3D::Texture2D(sdl.graphics->GetContext()));
fontTex->SetNumLevels(1);
fontTex->SetSize(w, h, Urho3D::Graphics::GetRGBAFormat());
fontTex->SetData(0, 0, 0, w, h, image);
// Remember the created texture for cleanup
//dev->font_texs.Push(fontTex);
nk_font_atlas_end(&sdl.atlas, nk_handle_ptr(fontTex), &sdl.ogl.null);
if (sdl.atlas.default_font)
nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
}
NK_API int
nk_sdl_handle_event(SDL_Event *evt)
{
struct nk_context *ctx = &sdl.ctx;
if (evt->type == SDL_KEYUP || evt->type == SDL_KEYDOWN) {
/* key events */
int down = evt->type == SDL_KEYDOWN;
const Uint8* state = SDL_GetKeyboardState(0);
SDL_Keycode sym = evt->key.keysym.sym;
if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT)
nk_input_key(ctx, NK_KEY_SHIFT, down);
else if (sym == SDLK_DELETE)
nk_input_key(ctx, NK_KEY_DEL, down);
else if (sym == SDLK_RETURN)
nk_input_key(ctx, NK_KEY_ENTER, down);
else if (sym == SDLK_TAB)
nk_input_key(ctx, NK_KEY_TAB, down);
else if (sym == SDLK_BACKSPACE)
nk_input_key(ctx, NK_KEY_BACKSPACE, down);
else if (sym == SDLK_HOME) {
nk_input_key(ctx, NK_KEY_TEXT_START, down);
nk_input_key(ctx, NK_KEY_SCROLL_START, down);
}
else if (sym == SDLK_END) {
nk_input_key(ctx, NK_KEY_TEXT_END, down);
nk_input_key(ctx, NK_KEY_SCROLL_END, down);
}
else if (sym == SDLK_PAGEDOWN) {
nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
}
else if (sym == SDLK_PAGEUP) {
nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
}
else if (sym == SDLK_z)
nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && state[SDL_SCANCODE_LCTRL]);
else if (sym == SDLK_r)
nk_input_key(ctx, NK_KEY_TEXT_REDO, down && state[SDL_SCANCODE_LCTRL]);
else if (sym == SDLK_c)
nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]);
else if (sym == SDLK_v)
nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]);
else if (sym == SDLK_x)
nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]);
else if (sym == SDLK_b)
nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && state[SDL_SCANCODE_LCTRL]);
else if (sym == SDLK_e)
nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && state[SDL_SCANCODE_LCTRL]);
else if (sym == SDLK_UP)
nk_input_key(ctx, NK_KEY_UP, down);
else if (sym == SDLK_DOWN)
nk_input_key(ctx, NK_KEY_DOWN, down);
else if (sym == SDLK_LEFT) {
if (state[SDL_SCANCODE_LCTRL])
nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
else nk_input_key(ctx, NK_KEY_LEFT, down);
}
else if (sym == SDLK_RIGHT) {
if (state[SDL_SCANCODE_LCTRL])
nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
else nk_input_key(ctx, NK_KEY_RIGHT, down);
}
else return 0;
return 1;
}
else if (evt->type == SDL_MOUSEBUTTONDOWN || evt->type == SDL_MOUSEBUTTONUP) {
/* mouse button */
int down = evt->type == SDL_MOUSEBUTTONDOWN;
const int x = evt->button.x, y = evt->button.y;
if (evt->button.button == SDL_BUTTON_LEFT)
nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
if (evt->button.button == SDL_BUTTON_MIDDLE)
nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
if (evt->button.button == SDL_BUTTON_RIGHT)
nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
return 1;
}
else if (evt->type == SDL_MOUSEMOTION) {
if (ctx->input.mouse.grabbed) {
int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
}
else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
return 1;
}
else if (evt->type == SDL_TEXTINPUT) {
nk_glyph glyph;
memcpy(glyph, evt->text.text, NK_UTF_SIZE);
nk_input_glyph(ctx, glyph);
return 1;
}
else if (evt->type == SDL_MOUSEWHEEL) {
nk_input_scroll(ctx, (float)evt->wheel.y);
return 1;
}
return 0;
}
NK_API
void nk_sdl_shutdown(void)
{
nk_font_atlas_clear(&sdl.atlas);
nk_free(&sdl.ctx);
nk_sdl_device_destroy();
memset(&sdl, 0, sizeof(sdl));
}
#endif
#include "Uniforms.glsl"
#include "Samplers.glsl"
#ifdef COMPILEVS
// Silence GLSL 150 deprecation warnings
#ifdef GL3
#define attribute in
#define varying out
#endif
attribute vec2 iPos;
attribute vec2 iTexCoord;
attribute vec4 iColor;
#else
// Silence GLSL 150 deprecation warnings
#ifdef GL3
#define varying in
// \todo: should not hardcode the number of MRT outputs according to defines
#if defined(DEFERRED)
out vec4 fragData[4];
#elif defined(PREPASS)
out vec4 fragData[2];
#else
out vec4 fragData[1];
#endif
#define gl_FragColor fragData[0]
#define gl_FragData fragData
#endif
#endif
varying vec2 vTexCoord;
varying vec4 vColor;
void VS()
{
gl_Position = vec4(iPos, 0.0, 1.0) * cViewProj;
vTexCoord = iTexCoord;
vColor = iColor;
}
void PS()
{
gl_FragColor = vColor * texture2D(sDiffMap, vTexCoord);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment