Release Version 1.0

This is the first release version of nuklear (previously: zahnrad).
As for those who no the old version will notice: a lot has changed.

Most obvious should be the two biggest changes. First the name change
because I got critique that the name is hard to comprehend and
remember (understandable for non-germans) and the second is the
transistion from four files (zahnrad.h, zahnrad.c, stb_truetype
and stb_rect_pack) to one single header library file nuklear.h.
I am not 100% convinced that using a single header library is the
right choice here but so far I haven't encountered any problems.

Noticable should be as well that nuklear now directly embeds three
stb libraries: stb_truetype, stb_rect_pack and stb_textedit. Like
in previous versions the first two are optional and the library
can be compiled without. stb_textedit on the other hand powers
the text edit implementation for single as well as multiline
text manipulation. The text edit implementation is still relative
new and untested so you can expect some bugs I have not found yet.

In the demo department a lot changed as well. All platform demos
now don't compile one big demo but instead contain a simple
demo and small abstraction layer over the platform. Main benefit is
better understandablity improved ease of use. The old demo
is now split up and transfered into the example folder while each part
is self contained and compileable. (All examples use glfw I don't now
if this is the best platform but it is at least the simplest.
I also removed the apple demo because I don't have an apple system
and cannot make sure the new version runs with the old version.

Finally a lot of small bugs have been fixed as well as bugs found by
clang analyzer and coverity.
pull/61/head
vurtun 2016-04-11 01:34:59 +02:00
parent f1e81a59ea
commit b2c87ed7c0
110 changed files with 26011 additions and 29917 deletions

View File

@ -1,43 +0,0 @@
CONTRIBUTING
============
## Submitting changes
Please send a GitHub Pull Request with a clear list of what you've done (read more about [pull requests](http://help.github.com/pull-requests/)).
## Features
If you have an idea for new features just [open an issue](https://github.com/vurtun/zahnrad/issues) with your suggestion.
* Find and correct spelling mistakes
* Add (insert your favorite platform or render backend here) demo implementation (some possibilities: DirectX 9/DirectX 10/DirectX 11 and win32 with OpenGL)
* Add clipboard user callbacks back into all demos
* Add additional widgets
* Find a better way to change the style or group style options
* Add support for multiple pointers for touch input devices (probably requires to rewrite mouse handling in `struct zr_input`)
* Extend xlib demo to support image drawing with arbitrary image width and height
* Change cursor in `zr_widget_edit_box` and `zr_widget_edit_field` to thin standard cursor version used in editors
* Extend piemenu to support submenus (another ring around the first ring or something like [this:](http://gdj.gdj.netdna-cdn.com/wp-content/uploads/2013/02/ui+concepts+13.gif)) and turn it into a default library widget.
* Add label describing the currently active piemenu entry
* Add tables with scaleable column width
* Rewrite the chart API to support a better range of charts (maybe take notes from Javascript chart frameworks)
* Create an API to allow scaling between groups (maybe extend and convert the demo example)
* Come up with a better way to provide and create widget and window styles
* Add multiple Tab support (maybe use `zr_group` and add a header)
* Extend context to not only support overlapping windows but tiled windows as well
## Bugs
* Seperator widget is currently bugged and does not work as intended
* Text handling is still a little bit janky and probably needs to be further tested and polished
* `zr_edit_buffer` with multiline flag is bugged for '\n', need to differentiate between visible and non-visible characters
## Coding conventions
* Only use C89 (ANSI C)
* Do not use any compiler specific extensions
* For indent use four spaces
* Do not typedef structs, unions and enums
* Variable, object and function names should always be lowercase and use underscores instead of camel case
* Whitespace after for, while, if, do and switch
* Always use parentheses if you use the sizeof operator (e.g: sizeof(struct zr_context) and not sizeof struct zr_context)
* Beginning braces on the new line for functions and on the same line otherwise.
* If function becomes to big either a.) create a subblock inside the function and comment or b.) write a functional function
* Only use fixed size types (zr_uint, zr_size, ...) if you really need to and use basic types otherwise
* Do not include any header files in either zahnrad.h or zahnrad.c
* Do not add dependencies rather write your own version if possible
* Write correct commit messages: (http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)

17
LICENSE
View File

@ -1,17 +0,0 @@
Copyright (c) 2016 Micha Mettke
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

140
Readme.md
View File

@ -1,9 +1,7 @@
# Zahnrad
[![Coverity Status](https://scan.coverity.com/projects/5863/badge.svg)](https://scan.coverity.com/projects/5863)
# Nuklear
This is a minimal state immediate mode graphical user interface toolkit
written in ANSI C and licensed under zlib. It was designed as a simple embeddable user interface for
application and does not have any direct dependencies,
written in ANSI C and licensed under public domain. It was designed as a simple
embeddable user interface for application and does not have any dependencies,
a default renderbackend or OS window and input handling but instead provides a very modular
library approach by using simple input state for input and draw
commands describing primitive shapes as output. So instead of providing a
@ -12,34 +10,30 @@ render backends it only focuses on the actual UI.
## Features
- Immediate mode graphical user interface toolkit
- Single header library
- Written in C89 (ANSI C)
- Small codebase (~12kLOC)
- Small codebase (~15kLOC)
- Focus on portability, efficiency and simplicity
- No dependencies (not even the standard library)
- No global or hidden state
- No dependencies (not even the standard library if not wanted)
- Fully skinnable and customizable
- Low memory footprint with total memory control if needed or wanted
- UTF-8 support
## Optional
- Vertex buffer output
- Font handling
- No global or hidden state
- Customizeable library modules (you can compile and use only what you need)
- Optional font baker and vertex buffer output
## Building
The library is self-contained within four different files that only have to be
copied and compiled into your application. Files zahnrad.c and zahnrad.h make up
the core of the library, while stb_rect_pack.h and stb_truetype.h are
for a optional font handling implementation and can be removed if not needed.
- zahnrad.c
- zahnrad.h
- stb_rect_pack.h (optional)
- stb_truetype.h (optional)
This library is self contained in one single header file and can be used either
in header only mode or in implementation mode. The header only mode is used
by default when included and allows including this header in other headers
and does not contain the actual implementation.
There are no dependencies or a particular building process required. You just have
to compile the .c file and #include zahnrad.h into your project. To actually
run you have to provide the input state, configuration style and memory
for draw commands to the library. After the GUI was executed all draw commands
have to be either executed or optionally converted into a vertex buffer to
draw the GUI.
The implementation mode requires to define the preprocessor macro
`NK_IMPLEMENTATION` in *one* .c/.cpp file before #includeing this file, e.g.:
```c
#define NK_IMPLEMENTATION
#include "nuklear.h"
```
## Gallery
![screenshot](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
@ -51,40 +45,100 @@ draw the GUI.
## Example
```c
/* init gui state */
struct zr_context ctx;
zr_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
struct nk_context ctx;
nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
enum {EASY, HARD};
int op = EASY;
float value = 0.6f;
int i = 20;
struct zr_panel layout;
zr_begin(&ctx, &layout, "Show", zr_rect(50, 50, 220, 220),
ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_CLOSEABLE);
struct nk_panel layout;
nk_begin(&ctx, &layout, "Show", nk_rect(50, 50, 220, 220),
NK_WINDOW_BORDER|NK_WINDOW_MOVEABLE|NK_WINDOW_CLOSEABLE);
{
/* fixed widget pixel width */
zr_layout_row_static(&ctx, 30, 80, 1);
if (zr_button_text(&ctx, "button", ZR_BUTTON_DEFAULT)) {
nk_layout_row_static(&ctx, 30, 80, 1);
if (nk_button_text(&ctx, "button", NK_BUTTON_DEFAULT)) {
/* event handling */
}
/* fixed widget window ratio width */
zr_layout_row_dynamic(&ctx, 30, 2);
if (zr_option(&ctx, "easy", op == EASY)) op = EASY;
if (zr_option(&ctx, "hard", op == HARD)) op = HARD;
nk_layout_row_dynamic(&ctx, 30, 2);
if (nk_option(&ctx, "easy", op == EASY)) op = EASY;
if (nk_option(&ctx, "hard", op == HARD)) op = HARD;
/* custom widget pixel width */
zr_layout_row_begin(&ctx, ZR_STATIC, 30, 2);
nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);
{
zr_layout_row_push(&ctx, 50);
zr_label(&ctx, "Volume:", ZR_TEXT_LEFT);
zr_layout_row_push(&ctx, 110);
zr_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
nk_layout_row_push(&ctx, 50);
nk_label(&ctx, "Volume:", NK_TEXT_LEFT);
nk_layout_row_push(&ctx, 110);
nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);
}
zr_layout_row_end(&ctx);
nk_layout_row_end(&ctx);
}
zr_end(ctx);
nk_end(ctx);
```
![example](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)
##FAQ
---
#### Why single-file headers?
Windows doesn't have standard directories where libraries
live. That makes deploying libraries in Windows a lot more
painful than open source developers on Unix-derivates generally
realize. (It also makes library dependencies a lot worse in Windows.)
There's also a common problem in Windows where a library was built
against a different version of the runtime library, which causes
link conflicts and confusion. Shipping the libs as headers means
you normally just compile them straight into your project without
making libraries, thus sidestepping that problem.
Making them a single file makes it very easy to just
drop them into a project that needs them. (Of course you can
still put them in a proper shared library tree if you want.)
Why not two files, one a header and one an implementation?
The difference between 10 files and 9 files is not a big deal,
but the difference between 2 files and 1 file is a big deal.
You don't need to zip or tar the files up, you don't have to
remember to attach *two* files, etc.
#### Where is the documentation?
Each file has documentation, basic ussage description and
examples at the top of the file. In addition each API function,
struct and member variables are documented as well.
Finally each library has a corresponding test file inside the
test directory for additional working examples.
#### Why C?
Personally I primarily use C instead of C++ and since I want to
support both C and C++ and C++ is not useable from C I therefore focus
on C.
#### Why C89?
I use C89 instead of C99/C11 for its portability between different compilers
and accessiblity for other languages.
##CREDITS:
Developed by Micha Mettke and every direct or indirect contributor to the GitHub.
Embeds stb_texedit, stb_truetype and stb_rectpack by Sean Barret (public domain)
Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license).
Big thank you to Omar Cornut (ocornut@github) for his imgui library and
giving me the inspiration for this library, Casey Muratori for handmade hero
and his original immediate mode graphical user interface idea and Sean
Barret for his amazing single header libraries which restored by faith
in libraries and brought me to create some of my own.
##LICENSE:
This software is dual-licensed to the public domain and under the following
license: you are granted a perpetual, irrevocable license to copy, modify,
publish and distribute this file as you see fit.

View File

@ -1 +0,0 @@
# Demo

View File

@ -8,7 +8,7 @@ DCC = gcc
# Flags
CFLAGS = -std=c89 -pedantic
SRC = ../../zahnrad.c allegro.c
SRC = main.c
OBJ = $(SRC:.c=.o)
ifeq ($(OS),Windows_NT)

View File

@ -1,337 +0,0 @@
/*
Copyright (c) 2016 Micha Mettke
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <math.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
/* macros */
#define MAX_VERTEX_MEMORY 512 * 1024
#define MAX_ELEMENT_MEMORY 128 * 1024
#define DEMO_DO_NOT_DRAW_IMAGES
#include "../../zahnrad.h"
#include "../demo.c"
struct device {
ALLEGRO_DISPLAY *display;
ALLEGRO_EVENT_QUEUE *queue;
ALLEGRO_BITMAP *texture;
ALLEGRO_VERTEX_DECL *vertex_decl;
struct zr_draw_null_texture null;
struct zr_buffer cmds;
void *vertex_buffer;
void *element_buffer;
};
struct allegro_vertex {
struct zr_vec2 pos;
struct zr_vec2 uv;
ALLEGRO_COLOR col;
};
static void
die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputs("\n", stderr);
exit(EXIT_FAILURE);
}
static char*
file_load(const char* path, size_t* siz)
{
char *buf;
FILE *fd = fopen(path, "rb");
if (!fd) die("Failed to open file: %s\n", path);
fseek(fd, 0, SEEK_END);
*siz = (size_t)ftell(fd);
fseek(fd, 0, SEEK_SET);
buf = (char*)calloc(*siz, 1);
fread(buf, *siz, 1, fd);
fclose(fd);
return buf;
}
static void
device_init(struct device *dev)
{
ALLEGRO_VERTEX_ELEMENT elems[] = {
{ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, offsetof(struct allegro_vertex, pos)},
{ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, offsetof(struct allegro_vertex, uv)},
{ALLEGRO_PRIM_COLOR_ATTR, 0, offsetof(struct allegro_vertex, col)},
{0,0,0}
};
dev->vertex_decl = al_create_vertex_decl(elems, sizeof(struct allegro_vertex));
/* allocate memory for drawing process */
dev->vertex_buffer = calloc(MAX_VERTEX_MEMORY, 1);
dev->element_buffer = calloc(MAX_ELEMENT_MEMORY, 1);
}
static void
device_shutdown(struct device *dev)
{
free(dev->vertex_buffer);
free(dev->element_buffer);
zr_buffer_free(&dev->cmds);
}
static void
device_upload_atlas(struct device *dev, const void *image, int width, int height)
{
/* create allegro font bitmap */
ALLEGRO_BITMAP *bitmap = 0;
int flags = al_get_new_bitmap_flags();
int fmt = al_get_new_bitmap_format();
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP|ALLEGRO_MIN_LINEAR|ALLEGRO_MAG_LINEAR);
al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE);
bitmap = al_create_bitmap(width, height);
al_set_new_bitmap_flags(flags);
al_set_new_bitmap_format(fmt);
assert(bitmap);
{
/* copy font texture into bitmap */
ALLEGRO_LOCKED_REGION * locked_img;
locked_img = al_lock_bitmap(bitmap, al_get_bitmap_format(bitmap), ALLEGRO_LOCK_WRITEONLY);
assert(locked_img);
memcpy(locked_img->data, image, sizeof(uint32_t)*(size_t)(width*height));
al_unlock_bitmap(bitmap);
}
/* convert software texture into hardware texture */
dev->texture = al_clone_bitmap(bitmap);
al_destroy_bitmap(bitmap);
assert(dev->texture);
}
static void
device_draw(struct device *dev, struct zr_context *ctx, enum zr_anti_aliasing AA)
{
int op, src, dst;
al_get_blender(&op, &src, &dst);
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
{
const struct zr_draw_command *cmd;
struct zr_buffer vbuf, ebuf;
int offset = 0;
struct allegro_vertex *vertices = 0;
int *indicies = 0;
/* fill converting configuration */
struct zr_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.arc_segment_count = 22;
config.curve_segment_count = 22;
config.null = dev->null;
/* convert from command into hardware format */
zr_buffer_init_fixed(&vbuf, dev->vertex_buffer, MAX_VERTEX_MEMORY);
zr_buffer_init_fixed(&ebuf, dev->element_buffer, MAX_ELEMENT_MEMORY);
zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);
{
/* <sign> allegro does not support 32-bit packed color */
unsigned int i = 0;
struct zr_draw_vertex *verts = (struct zr_draw_vertex*)dev->vertex_buffer;
vertices = calloc(sizeof(struct allegro_vertex), ctx->canvas.vertex_count);
for (i = 0; i < ctx->canvas.vertex_count; ++i) {
zr_byte *c;
vertices[i].pos = verts[i].position;
vertices[i].uv = verts[i].uv;
c = (zr_byte*)&verts[i].col;
vertices[i].col = al_map_rgba(c[0], c[1], c[2], c[3]);
}
}
{
/* <massive sign> allegro does not support 16-bit indicies:
* @OPT: define zr_draw_index as int to fix this issue. */
unsigned int i = 0;
zr_draw_index *elements = (zr_draw_index*)dev->element_buffer;
indicies = calloc(sizeof(int), ctx->canvas.element_count);
for (i = 0; i < ctx->canvas.element_count; ++i)
indicies[i] = elements[i];
}
/* iterate over and execute each draw command */
zr_draw_foreach(cmd, ctx, &dev->cmds)
{
ALLEGRO_BITMAP *texture = cmd->texture.ptr;
if (!cmd->elem_count) continue;
al_set_clipping_rectangle((int)cmd->clip_rect.x, (int)cmd->clip_rect.y,
(int)cmd->clip_rect.w, (int)cmd->clip_rect.h);
al_draw_indexed_prim(vertices, dev->vertex_decl, texture, &indicies[offset],
(int)cmd->elem_count, ALLEGRO_PRIM_TRIANGLE_LIST);
offset += cmd->elem_count;
}
free(vertices);
free(indicies);
zr_clear(ctx);
}
al_set_blender(op, src, dst);
al_set_clipping_rectangle(0,0,al_get_display_width(dev->display),
al_get_display_height(dev->display));
}
static void
input_key(struct zr_context *ctx, ALLEGRO_EVENT *evt, int down)
{
int sym = evt->keyboard.keycode;
if (sym == ALLEGRO_KEY_RSHIFT || sym == ALLEGRO_KEY_LSHIFT)
zr_input_key(ctx, ZR_KEY_SHIFT, down);
else if (sym == ALLEGRO_KEY_DELETE)
zr_input_key(ctx, ZR_KEY_DEL, down);
else if (sym == ALLEGRO_KEY_ENTER)
zr_input_key(ctx, ZR_KEY_ENTER, down);
else if (sym == ALLEGRO_KEY_TAB)
zr_input_key(ctx, ZR_KEY_TAB, down);
else if (sym == ALLEGRO_KEY_BACKSPACE)
zr_input_key(ctx, ZR_KEY_BACKSPACE, down);
else if (sym == ALLEGRO_KEY_LEFT)
zr_input_key(ctx, ZR_KEY_LEFT, down);
else if (sym == ALLEGRO_KEY_RIGHT)
zr_input_key(ctx, ZR_KEY_RIGHT, down);
else if (sym == ALLEGRO_KEY_C)
zr_input_key(ctx, ZR_KEY_COPY, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
else if (sym == ALLEGRO_KEY_V)
zr_input_key(ctx, ZR_KEY_PASTE, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
else if (sym == ALLEGRO_KEY_X)
zr_input_key(ctx, ZR_KEY_CUT, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
}
static void
input_button(struct zr_context *ctx, ALLEGRO_EVENT *evt, int down)
{
const int x = evt->mouse.x;
const int y = evt->mouse.y;
if (evt->mouse.button == 1)
zr_input_button(ctx, ZR_BUTTON_LEFT, x, y, down);
if (evt->mouse.button == 2)
zr_input_button(ctx, ZR_BUTTON_RIGHT, x, y, down);
}
int
main(int argc, char *argv[])
{
struct device dev;
int running = 1;
struct demo gui;
struct zr_font *font;
struct zr_font_atlas atlas;
const char *font_path = (argc > 1) ? argv[1]: 0;
/* Allegro */
al_init();
al_install_keyboard();
al_install_mouse();
al_init_primitives_addon();
dev.display = al_create_display(WINDOW_WIDTH, WINDOW_HEIGHT);
al_set_window_title(dev.display, "Zahnrad");
dev.queue = al_create_event_queue();
al_register_event_source(dev.queue, al_get_display_event_source(dev.display));
al_register_event_source(dev.queue, al_get_keyboard_event_source());
al_register_event_source(dev.queue, al_get_mouse_event_source());
device_init(&dev);
{
/* Font */
const void *image;
int width, height;
zr_font_atlas_init_default(&atlas);
zr_font_atlas_begin(&atlas);
if (font_path) font = zr_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
else font = zr_font_atlas_add_default(&atlas, 14.0f, NULL);
image = zr_font_atlas_bake(&atlas, &width, &height, ZR_FONT_ATLAS_RGBA32);
device_upload_atlas(&dev, image, width, height);
zr_font_atlas_end(&atlas, zr_handle_ptr(dev.texture), &dev.null);
/* GUI */
memset(&gui, 0, sizeof(gui));
zr_buffer_init_default(&dev.cmds);
zr_init_default(&gui.ctx, &font->handle);
}
while (running) {
/* Input */
ALLEGRO_EVENT evt;
zr_input_begin(&gui.ctx);
while (al_get_next_event(dev.queue, &evt)) {
if (evt.type == ALLEGRO_EVENT_DISPLAY_CLOSE) goto cleanup;
else if (evt.type == ALLEGRO_EVENT_KEY_UP && evt.keyboard.display == dev.display)
input_key(&gui.ctx, &evt, zr_false);
else if (evt.type == ALLEGRO_EVENT_KEY_DOWN && evt.keyboard.display == dev.display)
input_key(&gui.ctx, &evt, zr_true);
else if (evt.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)
input_button(&gui.ctx, &evt, zr_true);
else if (evt.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)
input_button(&gui.ctx, &evt, zr_false);
else if (evt.type == ALLEGRO_EVENT_MOUSE_AXES) {
zr_input_motion(&gui.ctx, evt.mouse.x, evt.mouse.y);
} else if (evt.type == ALLEGRO_EVENT_KEY_CHAR) {
if (evt.keyboard.display == dev.display)
if (evt.keyboard.unichar > 0 && evt.keyboard.unichar < 0x10000)
zr_input_unicode(&gui.ctx, (zr_rune)evt.keyboard.unichar);
}
}
zr_input_end(&gui.ctx);
/* GUI */
running = run_demo(&gui);
/* Draw */
al_clear_to_color(al_map_rgba_f(0.2f, 0.2f, 0.2f, 1.0f));
device_draw(&dev, &gui.ctx, ZR_ANTI_ALIASING_ON);
al_flip_display();
}
cleanup:
/* Cleanup */
if (dev.texture)
al_destroy_bitmap(dev.texture);
if (dev.queue)
al_destroy_event_queue(dev.queue);
if (dev.display)
al_destroy_display(dev.display);
zr_font_atlas_clear(&atlas);
device_shutdown(&dev);
zr_free(&gui.ctx);
return 0;
}

131
demo/allegro5/main.c Normal file
View File

@ -0,0 +1,131 @@
/* nuklear - v1.00 - public domain */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <math.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
/* macros */
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define MAX_VERTEX_MEMORY 512 * 1024
#define MAX_ELEMENT_MEMORY 128 * 1024
/* these defines are both needed for the header
* and source file. So if you split them remember
* to copy them as well. */
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#include "nuklear_allegro.h"
#include "nuklear_allegro.c"
int
main(void)
{
int running = 1;
struct nk_context *ctx;
struct nk_color background;
ALLEGRO_DISPLAY *display;
ALLEGRO_EVENT_QUEUE *queue;
/* Allegro */
al_init();
al_install_keyboard();
al_install_mouse();
al_init_primitives_addon();
display = al_create_display(WINDOW_WIDTH, WINDOW_HEIGHT);
al_set_window_title(display, "nuklear");
queue = al_create_event_queue();
al_register_event_source(queue, al_get_display_event_source(display));
al_register_event_source(queue, al_get_keyboard_event_source());
al_register_event_source(queue, al_get_mouse_event_source());
ctx = nk_allegro_init(display, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY);
/* Load Fonts: if none of these are loaded a default font will be used */
{struct nk_font_atlas *atlas;
nk_allegro_font_stash_begin(&atlas);
/*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
/*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Robot-Regular.ttf", 14, 0);*/
/*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
/*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
/*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
/*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
nk_allegro_font_stash_end();
/*nk_style_set_font(ctx, &droid->handle);*/}
background = nk_rgb(28,48,62);
while (running)
{
/* Input */
ALLEGRO_EVENT evt;
nk_input_begin(ctx);
while (al_get_next_event(queue, &evt)) {
if (evt.type == ALLEGRO_EVENT_DISPLAY_CLOSE) goto cleanup;
nk_allegro_handle_event(&evt);
}
nk_input_end(ctx);
/* GUI */
{struct nk_panel layout;
if (nk_begin(ctx, &layout, "Demo", nk_rect(50, 50, 200, 200),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
enum {EASY, HARD};
static int op = EASY;
static int property = 20;
nk_layout_row_static(ctx, 30, 80, 1);
if (nk_button_label(ctx, "button", NK_BUTTON_DEFAULT))
fprintf(stdout, "button pressed\n");
nk_layout_row_dynamic(ctx, 30, 2);
if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
nk_layout_row_dynamic(ctx, 22, 1);
nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
{struct nk_panel combo;
nk_layout_row_dynamic(ctx, 20, 1);
nk_label(ctx, "background:", NK_TEXT_LEFT);
nk_layout_row_dynamic(ctx, 25, 1);
if (nk_combo_begin_color(ctx, &combo, background, 400)) {
nk_layout_row_dynamic(ctx, 120, 1);
background = nk_color_picker(ctx, background, NK_RGBA);
nk_layout_row_dynamic(ctx, 25, 1);
background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
nk_combo_end(ctx);
}}
}
nk_end(ctx);}
/* Draw */
{float bg[4];
nk_color_fv(bg, background);
al_clear_to_color(al_map_rgba_f(bg[0], bg[1], bg[2], bg[3]));
nk_allegro_render(NK_ANTI_ALIASING_ON);
al_flip_display();}
}
cleanup:
/* Cleanup */
if (queue) al_destroy_event_queue(queue);
if (display) al_destroy_display(display);
nk_allegro_shutdown();
return 0;
}

View File

@ -0,0 +1,271 @@
#define NK_IMPLEMENTATION
#include "../../nuklear.h"
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
struct nk_allegro_device {
ALLEGRO_BITMAP *texture;
ALLEGRO_VERTEX_DECL *vertex_decl;
struct nk_draw_null_texture null;
struct nk_buffer cmds;
void *vertex_buffer;
void *element_buffer;
int max_vertex_memory;
int max_element_memory;
};
struct nk_allegro_vertex {
struct nk_vec2 pos;
struct nk_vec2 uv;
ALLEGRO_COLOR col;
};
static struct {
ALLEGRO_DISPLAY *win;
struct nk_allegro_device dev;
struct nk_context ctx;
struct nk_font_atlas atlas;
} allegro;
NK_API void
nk_allegro_device_create(int max_vertex_memory, int max_element_memory)
{
struct nk_allegro_device *dev = &allegro.dev;
ALLEGRO_VERTEX_ELEMENT elems[] = {
{ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, offsetof(struct nk_allegro_vertex, pos)},
{ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, offsetof(struct nk_allegro_vertex, uv)},
{ALLEGRO_PRIM_COLOR_ATTR, 0, offsetof(struct nk_allegro_vertex, col)},
{0,0,0}
};
dev->vertex_decl = al_create_vertex_decl(elems, sizeof(struct nk_allegro_vertex));
dev->vertex_buffer = calloc((size_t)max_vertex_memory, 1);
dev->element_buffer = calloc((size_t)max_element_memory, 1);
dev->max_vertex_memory = max_vertex_memory;
dev->max_element_memory = max_element_memory;
nk_buffer_init_default(&dev->cmds);
}
static void
nk_allegro_device_upload_atlas(const void *image, int width, int height)
{
/* create allegro font bitmap */
ALLEGRO_BITMAP *bitmap = 0;
struct nk_allegro_device *dev = &allegro.dev;
int flags = al_get_new_bitmap_flags();
int fmt = al_get_new_bitmap_format();
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP|ALLEGRO_MIN_LINEAR|ALLEGRO_MAG_LINEAR);
al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE);
bitmap = al_create_bitmap(width, height);
al_set_new_bitmap_flags(flags);
al_set_new_bitmap_format(fmt);
assert(bitmap);
{/* copy font texture into bitmap */
ALLEGRO_LOCKED_REGION * locked_img;
locked_img = al_lock_bitmap(bitmap, al_get_bitmap_format(bitmap), ALLEGRO_LOCK_WRITEONLY);
assert(locked_img);
memcpy(locked_img->data, image, sizeof(uint32_t)*(size_t)(width*height));
al_unlock_bitmap(bitmap);}
/* convert software texture into hardware texture */
dev->texture = al_clone_bitmap(bitmap);
al_destroy_bitmap(bitmap);
assert(dev->texture);
}
NK_API void
nk_allegro_render(enum nk_anti_aliasing AA)
{
int op, src, dst;
struct nk_allegro_device *dev = &allegro.dev;
struct nk_context *ctx = &allegro.ctx;
al_get_blender(&op, &src, &dst);
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
{
const struct nk_draw_command *cmd;
struct nk_buffer vbuf, ebuf;
int offset = 0;
struct nk_allegro_vertex *vertices = 0;
int *indicies = 0;
/* fill converting configuration */
struct nk_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.arc_segment_count = 22;
config.curve_segment_count = 22;
config.null = dev->null;
/* convert from command into hardware format */
nk_buffer_init_fixed(&vbuf, dev->vertex_buffer, (nk_size)dev->max_vertex_memory);
nk_buffer_init_fixed(&ebuf, dev->element_buffer, (nk_size)dev->max_element_memory);
nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);
{
/* <sign> allegro does not support 32-bit packed color */
unsigned int i = 0;
struct nk_draw_vertex *verts = (struct nk_draw_vertex*)dev->vertex_buffer;
vertices = calloc(sizeof(struct nk_allegro_vertex), ctx->draw_list.vertex_count);
for (i = 0; i < ctx->draw_list.vertex_count; ++i) {
nk_byte *c;
vertices[i].pos = verts[i].position;
vertices[i].uv = verts[i].uv;
c = (nk_byte*)&verts[i].col;
vertices[i].col = al_map_rgba(c[0], c[1], c[2], c[3]);
}
}
{
/* <massive sign> allegro does not support 16-bit indicies:
* @OPT: define nk_draw_index as int to fix this issue. */
unsigned int i = 0;
nk_draw_index *elements = (nk_draw_index*)dev->element_buffer;
indicies = calloc(sizeof(int), ctx->draw_list.element_count);
for (i = 0; i < ctx->draw_list.element_count; ++i)
indicies[i] = elements[i];
}
/* iterate over and execute each draw command */
nk_draw_foreach(cmd, ctx, &dev->cmds)
{
ALLEGRO_BITMAP *texture = cmd->texture.ptr;
if (!cmd->elem_count) continue;
al_set_clipping_rectangle((int)cmd->clip_rect.x, (int)cmd->clip_rect.y,
(int)cmd->clip_rect.w, (int)cmd->clip_rect.h);
al_draw_indexed_prim(vertices, dev->vertex_decl, texture, &indicies[offset],
(int)cmd->elem_count, ALLEGRO_PRIM_TRIANGLE_LIST);
offset += cmd->elem_count;
}
free(vertices);
free(indicies);
nk_clear(ctx);
}
al_set_blender(op, src, dst);
al_set_clipping_rectangle(0,0, al_get_display_width(allegro.win),
al_get_display_height(allegro.win));
}
NK_API void
nk_allegro_device_destroy(void)
{
struct nk_allegro_device *dev = &allegro.dev;
free(dev->vertex_buffer);
free(dev->element_buffer);
nk_buffer_free(&dev->cmds);
}
NK_API struct nk_context*
nk_allegro_init(ALLEGRO_DISPLAY *win, int max_vertex_memory, int max_element_memory)
{
allegro.win = win;
nk_init_default(&allegro.ctx, 0);
nk_allegro_device_create(max_vertex_memory, max_element_memory);
return &allegro.ctx;
}
NK_API void
nk_allegro_font_stash_begin(struct nk_font_atlas **atlas)
{
nk_font_atlas_init_default(&allegro.atlas);
nk_font_atlas_begin(&allegro.atlas);
*atlas = &allegro.atlas;
}
NK_API void
nk_allegro_font_stash_end(void)
{
const void *image; int w, h;
image = nk_font_atlas_bake(&allegro.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
nk_allegro_device_upload_atlas(image, w, h);
nk_font_atlas_end(&allegro.atlas, nk_handle_ptr(allegro.dev.texture), &allegro.dev.null);
if (allegro.atlas.default_font)
nk_style_set_font(&allegro.ctx, &allegro.atlas.default_font->handle);
}
NK_API void
nk_allegro_handle_event(ALLEGRO_EVENT *evt)
{
struct nk_context *ctx = &allegro.ctx;
if ((evt->type == ALLEGRO_EVENT_KEY_UP ||
evt->type == ALLEGRO_EVENT_KEY_DOWN) &&
evt->keyboard.display == allegro.win)
{
/* key handler */
int down = (evt->type == ALLEGRO_EVENT_KEY_UP);
int sym = evt->keyboard.keycode;
if (sym == ALLEGRO_KEY_RSHIFT || sym == ALLEGRO_KEY_LSHIFT)
nk_input_key(ctx, NK_KEY_SHIFT, down);
else if (sym == ALLEGRO_KEY_DELETE)
nk_input_key(ctx, NK_KEY_DEL, down);
else if (sym == ALLEGRO_KEY_ENTER)
nk_input_key(ctx, NK_KEY_ENTER, down);
else if (sym == ALLEGRO_KEY_TAB)
nk_input_key(ctx, NK_KEY_TAB, down);
else if (sym == ALLEGRO_KEY_BACKSPACE)
nk_input_key(ctx, NK_KEY_BACKSPACE, down);
else if (sym == ALLEGRO_KEY_LEFT) {
if (evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL)
nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
else nk_input_key(ctx, NK_KEY_LEFT, down);
} else if (sym == ALLEGRO_KEY_RIGHT) {
if (evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL)
nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
else nk_input_key(ctx, NK_KEY_RIGHT, down);
} else if (sym == ALLEGRO_KEY_HOME)
nk_input_key(ctx, NK_KEY_TEXT_START, down);
else if (sym == ALLEGRO_KEY_END)
nk_input_key(ctx, NK_KEY_TEXT_END, down);
else if (sym == ALLEGRO_KEY_C)
nk_input_key(ctx, NK_KEY_COPY, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
else if (sym == ALLEGRO_KEY_V)
nk_input_key(ctx, NK_KEY_PASTE, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
else if (sym == ALLEGRO_KEY_X)
nk_input_key(ctx, NK_KEY_CUT, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
else if (sym == ALLEGRO_KEY_Z)
nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
else if (sym == ALLEGRO_KEY_R)
nk_input_key(ctx, NK_KEY_TEXT_REDO, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
else if (sym == ALLEGRO_KEY_X)
nk_input_key(ctx, NK_KEY_CUT, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
else if (sym == ALLEGRO_KEY_B)
nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
else if (sym == ALLEGRO_KEY_E)
nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL);
} else if (evt->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN ||
evt->type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
/* button handler */
int down = evt->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN;
const int x = evt->mouse.x, y = evt->mouse.y;
if (evt->mouse.button == 1)
nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
if (evt->mouse.button == 2)
nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
} else if (evt->type == ALLEGRO_EVENT_MOUSE_AXES) {
/* mouse motion */
nk_input_motion(ctx, evt->mouse.x, evt->mouse.y);
} else if (evt->type == ALLEGRO_EVENT_KEY_CHAR) {
/* text input */
if (evt->keyboard.display == allegro.win)
if (evt->keyboard.unichar > 0 && evt->keyboard.unichar < 0x10000)
nk_input_unicode(ctx, (nk_rune)evt->keyboard.unichar);
}
}
NK_API void
nk_allegro_shutdown(void)
{
if (allegro.dev.texture)
al_destroy_bitmap(allegro.dev.texture);
free(allegro.dev.vertex_buffer);
free(allegro.dev.element_buffer);
}

View File

@ -0,0 +1,17 @@
#ifndef NK_ALLEGRO_H_
#define NK_ALLEGRO_H_
#include "../../nuklear.h"
NK_API struct nk_context* nk_allegro_init(ALLEGRO_DISPLAY *win, int max_vertex_memory, int max_element_memory);
NK_API void nk_allegro_font_stash_begin(struct nk_font_atlas **atlas);
NK_API void nk_allegro_font_stash_end(void);
NK_API void nk_allegro_handle_event(ALLEGRO_EVENT *evt);
NK_API void nk_allegro_render(enum nk_anti_aliasing);
NK_API void nk_allegro_shutdown(void);
NK_API void nk_allegro_device_destroy(void);
NK_API void nk_allegro_device_create(int max_vertex_memory, int max_elemnt_memory);
#endif

53
demo/apple/.gitignore vendored
View File

@ -1,53 +0,0 @@
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
## Other
*.xccheckout
*.moved-aside
*.xcuserstate
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
fastlane/report.xml
fastlane/screenshots

View File

@ -1,293 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
500B20241C4B41870002B53F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B20231C4B41870002B53F /* main.m */; };
500B20401C4B43930002B53F /* ZahnradBackend.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B203F1C4B43930002B53F /* ZahnradBackend.m */; };
500B20421C4B43A30002B53F /* zahnrad.c in Sources */ = {isa = PBXBuildFile; fileRef = 500B20411C4B43A30002B53F /* zahnrad.c */; };
500B20481C4B43BC0002B53F /* DroidSans.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20441C4B43BC0002B53F /* DroidSans.ttf */; };
500B20491C4B43BC0002B53F /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20451C4B43BC0002B53F /* Roboto-Bold.ttf */; };
500B204A1C4B43BC0002B53F /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20461C4B43BC0002B53F /* Roboto-Light.ttf */; };
500B204B1C4B43BC0002B53F /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20471C4B43BC0002B53F /* Roboto-Regular.ttf */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
500B201C1C4B41870002B53F /* Mac_GL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mac_GL.app; sourceTree = BUILT_PRODUCTS_DIR; };
500B20231C4B41870002B53F /* main.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; tabWidth = 4; };
500B202A1C4B41880002B53F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
500B203E1C4B43930002B53F /* ZahnradBackend.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = ZahnradBackend.h; sourceTree = SOURCE_ROOT; tabWidth = 4; };
500B203F1C4B43930002B53F /* ZahnradBackend.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = ZahnradBackend.m; sourceTree = SOURCE_ROOT; tabWidth = 4; };
500B20411C4B43A30002B53F /* zahnrad.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = zahnrad.c; path = ../../../zahnrad.c; sourceTree = "<group>"; tabWidth = 5; };
500B20441C4B43BC0002B53F /* DroidSans.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = DroidSans.ttf; sourceTree = "<group>"; };
500B20451C4B43BC0002B53F /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
500B20461C4B43BC0002B53F /* Roboto-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Light.ttf"; sourceTree = "<group>"; };
500B20471C4B43BC0002B53F /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
504DFDEA1C4EA2CD00D3714A /* zahnrad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zahnrad.h; path = ../../../zahnrad.h; sourceTree = "<group>"; };
504DFDED1C4EA34800D3714A /* demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = demo.c; path = ../../demo.c; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
500B20191C4B41870002B53F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
500B20131C4B41870002B53F = {
isa = PBXGroup;
children = (
500B201E1C4B41870002B53F /* Mac_GL */,
500B20431C4B43BC0002B53F /* font */,
500B201D1C4B41870002B53F /* Products */,
);
sourceTree = "<group>";
};
500B201D1C4B41870002B53F /* Products */ = {
isa = PBXGroup;
children = (
500B201C1C4B41870002B53F /* Mac_GL.app */,
);
name = Products;
sourceTree = "<group>";
};
500B201E1C4B41870002B53F /* Mac_GL */ = {
isa = PBXGroup;
children = (
504DFDED1C4EA34800D3714A /* demo.c */,
500B203E1C4B43930002B53F /* ZahnradBackend.h */,
500B203F1C4B43930002B53F /* ZahnradBackend.m */,
500B20231C4B41870002B53F /* main.m */,
504DFDEA1C4EA2CD00D3714A /* zahnrad.h */,
500B20411C4B43A30002B53F /* zahnrad.c */,
500B202A1C4B41880002B53F /* Info.plist */,
);
path = Mac_GL;
sourceTree = "<group>";
};
500B20431C4B43BC0002B53F /* font */ = {
isa = PBXGroup;
children = (
500B20441C4B43BC0002B53F /* DroidSans.ttf */,
500B20451C4B43BC0002B53F /* Roboto-Bold.ttf */,
500B20461C4B43BC0002B53F /* Roboto-Light.ttf */,
500B20471C4B43BC0002B53F /* Roboto-Regular.ttf */,
);
name = font;
path = ../../font;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
500B201B1C4B41870002B53F /* Mac_GL */ = {
isa = PBXNativeTarget;
buildConfigurationList = 500B202D1C4B41880002B53F /* Build configuration list for PBXNativeTarget "Mac_GL" */;
buildPhases = (
500B20181C4B41870002B53F /* Sources */,
500B20191C4B41870002B53F /* Frameworks */,
500B201A1C4B41870002B53F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = Mac_GL;
productName = Mac_GL;
productReference = 500B201C1C4B41870002B53F /* Mac_GL.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
500B20141C4B41870002B53F /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0720;
ORGANIZATIONNAME = richi;
TargetAttributes = {
500B201B1C4B41870002B53F = {
CreatedOnToolsVersion = 7.2;
};
};
};
buildConfigurationList = 500B20171C4B41870002B53F /* Build configuration list for PBXProject "Mac_GL" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 500B20131C4B41870002B53F;
productRefGroup = 500B201D1C4B41870002B53F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
500B201B1C4B41870002B53F /* Mac_GL */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
500B201A1C4B41870002B53F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
500B20491C4B43BC0002B53F /* Roboto-Bold.ttf in Resources */,
500B20481C4B43BC0002B53F /* DroidSans.ttf in Resources */,
500B204B1C4B43BC0002B53F /* Roboto-Regular.ttf in Resources */,
500B204A1C4B43BC0002B53F /* Roboto-Light.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
500B20181C4B41870002B53F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
500B20241C4B41870002B53F /* main.m in Sources */,
500B20421C4B43A30002B53F /* zahnrad.c in Sources */,
500B20401C4B43930002B53F /* ZahnradBackend.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
500B202B1C4B41880002B53F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
500B202C1C4B41880002B53F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
};
name = Release;
};
500B202E1C4B41880002B53F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Mac_GL/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.richi.Mac-GL";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
500B202F1C4B41880002B53F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Mac_GL/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.richi.Mac-GL";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
500B20171C4B41870002B53F /* Build configuration list for PBXProject "Mac_GL" */ = {
isa = XCConfigurationList;
buildConfigurations = (
500B202B1C4B41880002B53F /* Debug */,
500B202C1C4B41880002B53F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
500B202D1C4B41880002B53F /* Build configuration list for PBXNativeTarget "Mac_GL" */ = {
isa = XCConfigurationList;
buildConfigurations = (
500B202E1C4B41880002B53F /* Debug */,
500B202F1C4B41880002B53F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 500B20141C4B41870002B53F /* Project object */;
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:Mac_GL.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 richi. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@ -1,400 +0,0 @@
/*
Copyright (c) 2016 richi
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#import "ZahnradBackend.h"
@interface ZahnradView : NSOpenGLView
@end
@implementation ZahnradView
{
ZahnradBackend* zr;
NSTrackingArea* currentTrackingArea;
CVDisplayLinkRef displayLink;
}
#pragma mark - Setup -
- (instancetype) initWithFrame: (NSRect) frameRect
{
NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = {
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFAColorSize, 24,
NSOpenGLPFAAlphaSize, 8,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAAccelerated,
NSOpenGLPFANoRecovery,
0
};
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: pixelFormatAttributes];
assert(self = [super initWithFrame: frameRect pixelFormat: pixelFormat]);
[self updateTrackingArea];
[[self openGLContext] makeCurrentContext];
zr = [[ZahnradBackend alloc] initWithView: self];
return self;
}
#if !SIMULATE_TOUCH
static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{
return [(__bridge ZahnradView*) displayLinkContext drawFrameForTime: outputTime];
}
- (void) prepareOpenGL
{
// Synchronize buffer swaps with vertical refresh rate
GLint swapInt = 1;
[[self openGLContext] setValues: &swapInt forParameter: NSOpenGLCPSwapInterval];
// Create a display link capable of being used with all active displays
CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
// Set the renderer output callback function
CVDisplayLinkSetOutputCallback(displayLink, &displayLinkCallback, (__bridge void* _Nullable)(self));
// Set the display link for the current renderer
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
// Activate the display link
CVDisplayLinkStart(displayLink);
}
#endif
- (void) glLocked: (dispatch_block_t) block
{
CGLLockContext(self.openGLContext.CGLContextObj);
@try
{
block();
}
@catch (NSException *exception)
{
NSLog(@"%@", exception);
}
@finally
{
CGLUnlockContext(self.openGLContext.CGLContextObj);
}
}
#pragma mark - Drawing -
- (void) drawFrame
{
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
[zr updateFrame];
[zr drawFrameWithScale: 1.0 width: self.bounds.size.width height: self.bounds.size.height];
[[self openGLContext] flushBuffer];
}
- (CVReturn) drawFrameForTime: (const CVTimeStamp*) outputTime
{
@autoreleasepool
{
[self glLocked: ^{
[[self openGLContext] makeCurrentContext];
[self drawFrame];
}];
}
return kCVReturnSuccess;
}
- (void) drawRect: (NSRect) dirtyRect
{
[self glLocked: ^{
[[self openGLContext] makeCurrentContext];
[super drawRect: dirtyRect];
[self drawFrame];
}];
}
#pragma mark - User Input -
- (void) addEvent: (NSDictionary*) event
{
[self glLocked: ^{
[zr addEvent: event];
}];
#if SIMULATE_TOUCH
[self setNeedsDisplay: YES];
#endif
}
- (void) mouseMoved: (NSEvent*) theEvent
{
#if !SIMULATE_TOUCH
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
[self addEvent: @{@"type" : @1, @"pos" : NSStringFromPoint(location)}];
#endif
}
- (void) mouseDragged: (NSEvent*) theEvent
{
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
[self addEvent: @{@"type" : @2, @"pos" : NSStringFromPoint(location)}];
}
- (void) rightMouseDragged: (NSEvent*) theEvent
{
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
[self addEvent: @{@"type" : @3, @"pos" : NSStringFromPoint(location)}];
}
- (void) otherMouseDragged: (NSEvent*) theEvent
{
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
[self addEvent: @{@"type" : @4, @"pos" : NSStringFromPoint(location)}];
}
- (void) mouseDown: (NSEvent*) theEvent
{
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
[self addEvent: @{@"type" : @5, @"pos" : NSStringFromPoint(location)}];
}
- (void) mouseUp: (NSEvent*) theEvent
{
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
[self addEvent: @{@"type" : @6, @"pos" : NSStringFromPoint(location)}];
}
- (void) rightMouseDown: (NSEvent*) theEvent
{
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
[self addEvent: @{@"type" : @7, @"pos" : NSStringFromPoint(location)}];
}
- (void) rightMouseUp: (NSEvent*) theEvent
{
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
[self addEvent: @{@"type" : @8, @"pos" : NSStringFromPoint(location)}];
}
- (void) otherMouseDown: (NSEvent*) theEvent
{
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
[self addEvent: @{@"type" : @9, @"pos" : NSStringFromPoint(location)}];
}
- (void) otherMouseUp: (NSEvent*) theEvent
{
NSPoint location = [self convertPoint: [theEvent locationInWindow] fromView: nil];
[self addEvent: @{@"type" : @10, @"pos" : NSStringFromPoint(location)}];
}
- (void) scrollWheel: (NSEvent*) theEvent
{
[self addEvent: @{@"type" : @11, @"deltaX" : @(theEvent.deltaX), @"deltaY" : @(theEvent.deltaY)}];
}
- (void) keyDown: (NSEvent*) theEvent
{
NSString* str = theEvent.characters;
if (str.length)
[self addEvent: @{@"type" : @12, @"txt" : str, @"mod" : @(theEvent.modifierFlags)}];
}
- (void) keyUp: (NSEvent*) theEvent
{
NSString* str = theEvent.characters;
if (str.length)
[self addEvent: @{@"type" : @13, @"txt" : str, @"mod" : @(theEvent.modifierFlags)}];
}
- (BOOL) acceptsFirstResponder
{
return YES;
}
- (void) removeCurrentTrackingArea
{
if (currentTrackingArea)
{
[self removeTrackingArea: currentTrackingArea];
currentTrackingArea = nil;
}
}
- (void) updateTrackingArea
{
[self removeCurrentTrackingArea];
#if !SIMULATE_TOUCH
currentTrackingArea = [[NSTrackingArea alloc]
initWithRect: self.bounds
options: NSTrackingMouseMoved | NSTrackingActiveInActiveApp
owner: self
userInfo: nil];
[self addTrackingArea: currentTrackingArea];
#endif
}
- (void) reshape
{
[self updateTrackingArea];
NSRect bounds = [self bounds];
[self glLocked: ^{
[[self openGLContext] makeCurrentContext];
glViewport((GLint)NSMinX(bounds), (GLint)NSMinY(bounds), (GLint)NSWidth(bounds), (GLint)NSHeight(bounds));
}];
}
- (void) update
{
[self glLocked: ^{
[super update];
}];
}
@end
#pragma mark - App Delegate -
@interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate>
@property (strong) IBOutlet NSWindow* window;
@end
@implementation AppDelegate
- (void) applicationDidFinishLaunching: (NSNotification*) aNotification
{
NSString* appName = [[NSProcessInfo processInfo] processName];
NSLog(@"Starting %@", appName);
NSMenu* appMenu = [NSMenu new];
[appMenu addItem: [[NSMenuItem alloc] initWithTitle: [@"Quit " stringByAppendingString: appName]
action: @selector(terminate:)
keyEquivalent: @"q"]];
NSMenuItem* appMenuItem = [NSMenuItem new];
[appMenuItem setSubmenu: appMenu];
NSMenu* menubar = [NSMenu new];
[menubar addItem: appMenuItem];
[NSApp setMainMenu: menubar];
NSRect frame = NSMakeRect(0, 0, 800, 600);
_window = [[NSWindow alloc] initWithContentRect: frame
styleMask: NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask
backing: NSBackingStoreBuffered
defer: NO];
[_window setContentView: [[ZahnradView alloc] initWithFrame: frame]];
[_window setDelegate: self];
[_window setTitle: appName];
[_window cascadeTopLeftFromPoint: NSMakePoint(20, 20)];
[_window makeKeyAndOrderFront: nil];
}
- (void) windowWillClose: (NSNotification*) notification
{
[NSApp terminate: self];
}
@end
int main()
{
@autoreleasepool
{
[NSApplication sharedApplication];
[NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
AppDelegate* appDelegate = [AppDelegate new];
[NSApp setDelegate: appDelegate];
[NSApp run];
}
return EXIT_SUCCESS;
}

View File

@ -1,19 +0,0 @@
Zahnrad for Mac OS X, iOS and tvOS
==================================
This is a bunch of experimental render backends for [Zahnrad](https://github.com/vurtun/zahnrad) a gorgeous immediate mode GUI toolkit.
Included are native versions for Mac OS X, iOS and tvOS. The Mac version is using OpenGL 3.2. iOS and tvOS are running on OpenGL ES 3.2.
Versions utilising Metal are in the making.
How to use?
-----------
Open `ZahnradBackend.xcworkspace` with XCode and start your engines.
License
-------
[WTFPL](http://www.wtfpl.net)

View File

@ -1,81 +0,0 @@
/*
Copyright (c) 2016 Micha Mettke
Macintosh / Objective-C adaptation (c) 2016 richi
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#import <Foundation/Foundation.h>
#import "zahnrad.h"
#define SIMULATE_TOUCH 0
#if (TARGET_OS_IPHONE && (!TARGET_OS_TV)) || SIMULATE_TOUCH
#define ZR_REFRESH_ON_EVENT_ONLY 0
#define ZR_TOUCH_SCREEN 1
#endif
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import <OpenGLES/ES3/gl.h>
#import <OpenGLES/ES3/glext.h>
#define GLVIEW GLKView
#else
#import <Cocoa/Cocoa.h>
#import <OpenGL/OpenGL.h>
#import <OpenGL/gl.h>
#import <OpenGL/gl3.h>
#define GLVIEW NSOpenGLView
#endif
@interface ZahnradBackend : NSObject
@property (readonly) GLVIEW* view;
- (instancetype) initWithView: (GLVIEW*) view;
- (void) addEvent: (NSDictionary*) event;
- (void) updateFrame;
- (void) drawFrameWithScale: (CGFloat) scale width: (CGFloat) width height: (CGFloat) height;
@end
@interface ZahnradBackend (Adapter)
- (struct zr_context*) createContextWithBuffer: (struct zr_buffer*) cmds
allocator: (struct zr_allocator*) alloc
defaultFont: (struct zr_user_font*) defFont;
- (int) fillFrame;
@end
void zr_backend_show_keyboard(zr_hash hash, struct zr_rect bounds, struct zr_buffer* text);
void zr_backend_hide_keyboard(void);
int zr_touch_edit_string(struct zr_context *ctx, zr_flags flags, char *text, zr_size *len, zr_size max, zr_filter filter, zr_hash unique_id);

View File

@ -1,767 +0,0 @@
/*
Copyright (c) 2016 Micha Mettke
Macintosh / Objective-C adaptation (c) 2016 richi
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#import "ZahnradBackend.h"
#define MAX_VERTEX_MEMORY (512 * 1024)
#define MAX_ELEMENT_MEMORY (128 * 1024)
// This is the adapter for demo.c.
// #else does provide a generic version to start
// your own project.
#if 1
#if TARGET_OS_IPHONE
#define zr_edit_string(_ct, _fl, _bu, _le, _ma, _fi) zr_touch_edit_string(_ct, _fl, _bu, _le, _ma, _fi, (zr_hash)__COUNTER__)
#endif
#define DEMO_DO_NOT_DRAW_IMAGES
#include "../demo.c"
@implementation ZahnradBackend (Adapter)
static struct demo gui;
- (struct zr_context*) createContextWithBuffer: (struct zr_buffer*) cmds
allocator: (struct zr_allocator*) alloc
defaultFont: (struct zr_user_font*) defFont
{
memset(&gui, 0, sizeof(gui));
zr_buffer_init(cmds, alloc, 4096);
zr_init(&gui.ctx, alloc, defFont);
return &gui.ctx;
}
- (int) fillFrame;
{
return run_demo(&gui);
}
@end
#else
#import "ZahnradBackend.h"
@implementation ZahnradBackend (Adapter)
static struct zr_context context;
- (struct zr_context*) createContextWithBuffer: (struct zr_buffer*) cmds
allocator: (struct zr_allocator*) alloc
defaultFont: (struct zr_user_font*) defFont
{
memset(&context, 0, sizeof(context));
zr_buffer_init(cmds, alloc, 4096);
zr_init(&context, alloc, defFont);
return &context;
}
- (int) fillFrame;
{
return 1;
}
@end
#endif
@implementation ZahnradBackend
{
struct zr_context* context;
struct zr_allocator alloc;
struct zr_user_font sysFnt;
struct zr_font font;
struct zr_draw_null_texture nullTexture;
struct zr_buffer cmds;
NSMutableArray* bufferedCommands;
NSMutableArray* events;
struct
{
GLuint vbo, vao, ebo;
GLuint program;
GLuint vertexShader;
GLuint fragmentShader;
GLint attributePosition;
GLint attributeUV;
GLint attributeColor;
GLint uniformTexture;
GLint uniformProjection;
GLuint fontTexture;
} device;
}
static void* mem_alloc(zr_handle unused, size_t size)
{
return calloc(1, size);
}
static void mem_free(zr_handle unused, void* ptr)
{
free(ptr);
}
#pragma mark - Setup -
- (instancetype) initWithView: (GLVIEW*) view;
{
if (!(self = [super init])) return self;
_view = view;
events = [NSMutableArray new];
bufferedCommands = [NSMutableArray new];
[self setupGL];
NSURL* fontURL = [[NSBundle mainBundle] URLForResource: @"DroidSans" withExtension: @"ttf"];
assert(fontURL != nil);
alloc.userdata.ptr = NULL;
alloc.alloc = mem_alloc;
alloc.free = mem_free;
sysFnt = [self fontFromUrl: fontURL height: 14 range: zr_font_default_glyph_ranges()];
context = [self createContextWithBuffer: &cmds allocator: &alloc defaultFont: &sysFnt];
[self fillFrame];
return self;
}
- (void) setupGL
{
GLint status;
static const GLchar* vss =
#if TARGET_OS_IPHONE
"#version 300 es\n"
#else
"#version 150\n"
#endif
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main() {\n"
" Frag_UV = TexCoord;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
static const GLchar* fss =
#if TARGET_OS_IPHONE
"#version 300 es\n"
#else
"#version 150\n"
#endif
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
device.program = glCreateProgram();
device.vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(device.vertexShader, 1, &vss, 0);
glCompileShader(device.vertexShader);
#if defined(DEBUG)
GLint logLength;
glGetShaderiv(device.vertexShader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar* log = (GLchar*)malloc(logLength);
glGetShaderInfoLog(device.vertexShader, logLength, &logLength, log);
NSLog(@"Shader compile log:\n%s", log);
free(log);
}
#endif
glGetShaderiv(device.vertexShader, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
device.fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(device.fragmentShader, 1, &fss, 0);
glCompileShader(device.fragmentShader);
#if defined(DEBUG)
glGetShaderiv(device.fragmentShader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar* log = (GLchar*)malloc(logLength);
glGetShaderInfoLog(device.fragmentShader, logLength, &logLength, log);
NSLog(@"Shader compile log:\n%s", log);
free(log);
}
#endif
glGetShaderiv(device.fragmentShader, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glAttachShader(device.program, device.vertexShader);
glAttachShader(device.program, device.fragmentShader);
glLinkProgram(device.program);
#if defined(DEBUG)
glGetProgramiv(device.program, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar* log = (GLchar*)malloc(logLength);
glGetProgramInfoLog(device.program, logLength, &logLength, log);
NSLog(@"Program link log:\n%s", log);
free(log);
}
#endif
glGetProgramiv(device.program, GL_LINK_STATUS, &status);
assert(status == GL_TRUE);
device.uniformTexture = glGetUniformLocation(device.program, "Texture");
device.uniformProjection = glGetUniformLocation(device.program, "ProjMtx");
device.attributePosition = glGetAttribLocation(device.program, "Position");
device.attributeUV = glGetAttribLocation(device.program, "TexCoord");
device.attributeColor = glGetAttribLocation(device.program, "Color");
// buffer setup
GLsizei vs = sizeof(struct zr_draw_vertex);
size_t vp = offsetof(struct zr_draw_vertex, position);
size_t vt = offsetof(struct zr_draw_vertex, uv);
size_t vc = offsetof(struct zr_draw_vertex, col);
// allocate vertex and element buffer
glGenBuffers(1, &device.vbo);
glGenBuffers(1, &device.ebo);
glGenVertexArrays(1, &device.vao);
glBindVertexArray(device.vao);
glBindBuffer(GL_ARRAY_BUFFER, device.vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, device.ebo);
glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
glEnableVertexAttribArray((GLuint)device.attributePosition);
glEnableVertexAttribArray((GLuint)device.attributeUV);
glEnableVertexAttribArray((GLuint)device.attributeColor);
glVertexAttribPointer((GLuint)device.attributePosition, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)device.attributeUV, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)device.attributeColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
- (struct zr_user_font) fontFromUrl: (NSURL*) url height: (unsigned) fontHeight range: (const zr_rune*) range
{
struct zr_baked_font baked_font;
struct zr_recti custom;
memset(&baked_font, 0, sizeof(baked_font));
memset(&custom, 0, sizeof(custom));
// bake and upload font texture
NSData* ttfData = [NSData dataWithContentsOfURL: url];
assert(ttfData != nil);
// setup font configuration
struct zr_font_config config;
memset(&config, 0, sizeof(config));
config.ttf_blob = (void*)ttfData.bytes;
config.font = &baked_font;
config.coord_type = ZR_COORD_UV;
config.range = range;
config.pixel_snap = zr_false;
config.size = (float)fontHeight;
config.spacing = zr_vec2(0, 0);
config.oversample_h = 1;
config.oversample_v = 1;
config.merge_mode = 0;
// query needed amount of memory for the font baking process
int glyph_count;
size_t tmp_size;
zr_font_bake_memory(&tmp_size, &glyph_count, &config, 1);
struct zr_font_glyph* glyphes = (struct zr_font_glyph*)calloc(sizeof(struct zr_font_glyph), (size_t)glyph_count);
void* tmp = calloc(1, tmp_size);
// pack all glyphes and return needed image width, height and memory size
int img_width, img_height;
size_t img_size;
custom.w = 2; custom.h = 2;
assert(zr_font_bake_pack(&img_size, &img_width, &img_height, &custom, tmp, tmp_size, &config, 1));
// bake all glyphes and custom white pixel into image
const char* custom_data = "....";
void* img = calloc(1, img_size);
zr_font_bake(img, img_width, img_height, tmp, tmp_size, glyphes, glyph_count, &config, 1);
zr_font_bake_custom_data(img, img_width, img_height, custom, custom_data, 2, 2, '.', 'X');
// convert alpha8 image into rgba8 image
void* img_rgba = calloc(4, (size_t)(img_height * img_width));
zr_font_bake_convert(img_rgba, img_width, img_height, img);
free(img);
img = img_rgba;
// upload baked font image
glGenTextures(1, &device.fontTexture);
glBindTexture(GL_TEXTURE_2D, device.fontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)img_width, (GLsizei)img_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
free(tmp);
free(img);
// default white pixel in a texture which is needed to draw primitives
nullTexture.texture.id = (int)device.fontTexture;
nullTexture.uv = zr_vec2((custom.x + 0.5f) / (float)img_width, (custom.y + 0.5f) / (float)img_height);
/* setup font with glyphes. IMPORTANT: the font only references the glyphes
this was done to have the possibility to have multible fonts with one
total glyph array. Not quite sure if it is a good thing since the
glyphes have to be freed as well.
*/
zr_font_init(&font, (float)fontHeight, '?', glyphes, &baked_font, nullTexture.texture);
return &font.handle;
}
#pragma mark - Drawing -
- (void) drawFrameWithScale: (CGFloat) scale width: (CGFloat) width height: (CGFloat) height
{
// save opengl state
GLint last_prog, last_tex;
GLint last_ebo, last_vbo, last_vao;
glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
// setup global state
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
// setup program
GLfloat ortho[4][4] = {
{2.0f, 0.0f, 0.0f, 0.0f},
{0.0f, -2.0f, 0.0f, 0.0f},
{0.0f, 0.0f, -1.0f, 0.0f},
{-1.0f, 1.0f, 0.0f, 1.0f},
};
ortho[0][0] /= width;
ortho[1][1] /= height;
glUseProgram(device.program);
glUniform1i(device.uniformTexture, 0);
glUniformMatrix4fv(device.uniformProjection, 1, GL_FALSE, &ortho[0][0]);
// activate vertex and element buffer
glBindVertexArray(device.vao);
glBindBuffer(GL_ARRAY_BUFFER, device.vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, device.ebo);
// if draw commands have been buffered we will draw only those
if (bufferedCommands.count)
{
const struct zr_draw_command* cmd;
const zr_draw_index* offset = NULL;
// iterate over and execute each draw command
for (NSData* data in bufferedCommands)
{
cmd = data.bytes;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)(cmd->clip_rect.x * scale),
(GLint)((height - (cmd->clip_rect.y + cmd->clip_rect.h)) * scale),
(GLint)(cmd->clip_rect.w * scale),
(GLint)(cmd->clip_rect.h * scale));
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
}
else
{
// load draw vertices & elements into vertex + element buffer
void* vertices = glMapBufferRange(GL_ARRAY_BUFFER, 0, MAX_VERTEX_MEMORY, GL_MAP_WRITE_BIT);
void* elements = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, MAX_ELEMENT_MEMORY, GL_MAP_WRITE_BIT);
//
// fill converting configuration
struct zr_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = ZR_ANTI_ALIASING_ON;
config.line_AA = ZR_ANTI_ALIASING_ON;
config.circle_segment_count = 22;
config.curve_segment_count = 22;
config.arc_segment_count = 22;
config.null = nullTexture;
//
// setup buffers to load vertices and elements
struct zr_buffer vbuf, ebuf;
zr_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
zr_convert(context, &cmds, &vbuf, &ebuf, &config);
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
//
// convert from command queue into draw list and draw to screen
const struct zr_draw_command* cmd;
const zr_draw_index* offset = NULL;
[bufferedCommands removeAllObjects];
// iterate over and execute each draw command
zr_draw_foreach(cmd, context, &cmds)
{
if (cmd->elem_count > 0)
{
#if ZR_REFRESH_ON_EVENT_ONLY
[bufferedCommands addObject: [NSData dataWithBytes: cmd length: sizeof(struct zr_draw_command)]];
#endif
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)(cmd->clip_rect.x * scale),
(GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale),
(GLint)(cmd->clip_rect.w * scale),
(GLint)(cmd->clip_rect.h * scale));
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
}
zr_clear(context);
}
// restore old state
glUseProgram((GLuint)last_prog);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
glBindVertexArray((GLuint)last_vao);
glDisable(GL_SCISSOR_TEST);
}
#pragma mark - Events -
- (void) updateFrame
{
#if ZR_REFRESH_ON_EVENT_ONLY
if (events.count)
#endif
{
[self handleEvents];
[self fillFrame];
}
}
- (void) handleEvents
{
NSArray* currentEvents = events.copy;
[events removeAllObjects];
zr_input_begin(context);
for (NSDictionary* event in currentEvents)
{
#if TARGET_OS_IPHONE
CGPoint location = CGPointFromString(event[@"pos"]);
#else
NSPoint location = NSPointFromString(event[@"pos"]);
location.y = (int)(self.view.bounds.size.height - location.y);
#endif
int x = (int)location.x;
int y = (int)location.y;
int type = [event[@"type"] intValue];
switch (type)
{
#if ZR_REFRESH_ON_EVENT_ONLY || ZR_TOUCH_SCREEN
case 2: case 3: case 4:
zr_input_motion(context, x, y);
break;
case 5:
zr_input_motion(context, x, y);
zr_input_end(context);
zr_input_begin(context);
zr_input_button(context, ZR_BUTTON_LEFT, x, y, zr_true);
break;
case 6:
zr_input_button(context, ZR_BUTTON_LEFT, x, y, zr_false);
zr_input_end(context);
[self fillFrame];
zr_clear(context);
zr_input_begin(context);
zr_input_motion(context, INT_MAX, INT_MAX);
break;
#else
case 1: case 2: case 3: case 4:
zr_input_motion(context, x, y);
break;
case 5:
zr_input_button(context, ZR_BUTTON_LEFT, x, y, zr_true);
break;
case 6:
zr_input_button(context, ZR_BUTTON_LEFT, x, y, zr_false);
break;
case 7:
zr_input_button(context, ZR_BUTTON_RIGHT, x, y, zr_true);
break;
case 8:
zr_input_button(context, ZR_BUTTON_RIGHT, x, y, zr_false);
break;
case 9:
zr_input_button(context, ZR_BUTTON_MIDDLE, x, y, zr_true);
break;
case 10:
zr_input_button(context, ZR_BUTTON_MIDDLE, x, y, zr_false);
break;
case 11:
zr_input_scroll(context, -[event[@"deltaY"] floatValue]);
break;
#endif
case 12:
case 13:
{
int down = type == 12 ? zr_true : zr_false;
NSString* str = event[@"txt"];
NSData* data = [str dataUsingEncoding: NSUTF32LittleEndianStringEncoding];
const uint32_t* c = data.bytes;
NSInteger n = data.length / sizeof(uint32_t);
#if TARGET_OS_IPHONE
if (down)
{
if (n && *c == '\b')
{
zr_input_key(context, ZR_KEY_BACKSPACE, zr_true);
zr_input_end(context);
[self fillFrame];
zr_clear(context);
zr_input_begin(context);
zr_input_key(context, ZR_KEY_BACKSPACE, zr_false);
}
else
{
for (NSInteger i = 0; i < n; i += 1, c += 1)
zr_input_unicode(context, *c);
}
}
#else
for (NSInteger i = 0; i < n; i += 1, c += 1)
{
if (*c == 127 || *c < ' ' || *c >= NSUpArrowFunctionKey)
{
switch (*c)
{
case NSLeftArrowFunctionKey:
zr_input_key(context, ZR_KEY_LEFT, down);
break;
case NSRightArrowFunctionKey:
zr_input_key(context, ZR_KEY_RIGHT, down);
break;
case 3:
zr_input_key(context, ZR_KEY_COPY, down);
break;
case 22:
zr_input_key(context, ZR_KEY_PASTE, down);
break;
case 24:
zr_input_key(context, ZR_KEY_CUT, down);
break;
case 9:
zr_input_key(context, ZR_KEY_TAB, down);
break;
case 13:
zr_input_key(context, ZR_KEY_ENTER, down);
break;
case 127:
zr_input_key(context, ZR_KEY_BACKSPACE, down);
break;
default:
break;
}
}
else if (down)
{
zr_input_unicode(context, *c);
}
}
#endif
}
break;
default:
break;
}
}
zr_input_end(context);
}
- (void) addEvent: (NSDictionary*) event
{
[bufferedCommands removeAllObjects];
[events addObject: event];
}
@end
@protocol ZahnradKeyboardDelegate <NSObject>
- (void) showKeyboard: (NSDictionary*) info;
- (void) hideKeyboard;
@end
#undef zr_edit_string
#if TARGET_OS_IPHONE
void zr_backend_show_keyboard(zr_hash zrHash, struct zr_rect zrBounds, struct zr_buffer* zrText)
{
CGRect frame = CGRectMake(zrBounds.x, zrBounds.y, zrBounds.w, zrBounds.h);
id ad = [[UIApplication sharedApplication] delegate];
if ([ad respondsToSelector: @selector(showKeyboard:)])
{
char str[zrText->allocated + 1];
strncpy(str, zrText->memory.ptr, zrText->allocated);
str[zrText->allocated] = 0;
NSString* text = [NSString stringWithCString: str encoding: NSUTF8StringEncoding];
[ad performSelector: @selector(showKeyboard:) withObject: @{@"hash" : @(zrHash), @"text" : text, @"frame" : NSStringFromCGRect(frame)}];
}
}
void zr_backend_hide_keyboard(void)
{
id ad = [[UIApplication sharedApplication] delegate];
if ([ad respondsToSelector: @selector(hideKeyboard)])
[ad performSelector: @selector(hideKeyboard)];
}
int zr_touch_edit_string(struct zr_context *ctx, zr_flags flags, char *text, zr_size *len, zr_size max, zr_filter filter, zr_hash unique_id)
{
zr_flags state;
struct zr_rect bounds;
zr_layout_peek(&bounds, ctx);
state = zr_edit_string(ctx, flags, text, len, max, filter);
if (state & ZR_EDIT_ACTIVATED)
{
struct zr_buffer buffer;
zr_buffer_init_fixed(&buffer, text, max);
buffer.allocated = *len;
zr_backend_show_keyboard((zr_hash)unique_id, bounds, &buffer);
}
else if (state & ZR_EDIT_DEACTIVATED)
{
zr_backend_hide_keyboard();
}
return state;
}
#else
void zr_backend_show_keyboard(zr_hash zrHash, struct zr_rect zrBounds, struct zr_buffer* zrText)
{
}
void zr_backend_hide_keyboard(void)
{
}
int zr_touch_edit_string(struct zr_context *ctx, zr_flags flags, char *text, zr_size *len, zr_size max, zr_filter filter, zr_hash unique_id)
{
return zr_edit_string(ctx, flags, text, len, max, filter);
}
#endif

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Mac_GL.xcodeproj">
</FileRef>
<FileRef
location = "group:iOS_GL_ES.xcodeproj">
</FileRef>
<FileRef
location = "group:iOS_CoreGraphics.xcodeproj">
</FileRef>
<FileRef
location = "group:tvOS_GL_ES.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,275 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
50F9C54A1C5FE56C009533F4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F9C5491C5FE56C009533F4 /* main.m */; };
50F9C5611C5FE7BD009533F4 /* zahnrad.c in Sources */ = {isa = PBXBuildFile; fileRef = 50F9C55F1C5FE7BD009533F4 /* zahnrad.c */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
50F9C5451C5FE56C009533F4 /* iOS_CoreGraphics.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOS_CoreGraphics.app; sourceTree = BUILT_PRODUCTS_DIR; };
50F9C5491C5FE56C009533F4 /* main.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; tabWidth = 4; };
50F9C5591C5FE56C009533F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
50F9C55F1C5FE7BD009533F4 /* zahnrad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zahnrad.c; path = ../../../zahnrad.c; sourceTree = "<group>"; };
50F9C5601C5FE7BD009533F4 /* zahnrad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zahnrad.h; path = ../../../zahnrad.h; sourceTree = "<group>"; };
50F9C5621C5FE7D9009533F4 /* demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = demo.c; path = ../../demo.c; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
50F9C5421C5FE56C009533F4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
50F9C53C1C5FE56C009533F4 = {
isa = PBXGroup;
children = (
50F9C5471C5FE56C009533F4 /* iOS_CoreGraphics */,
50F9C5461C5FE56C009533F4 /* Products */,
);
sourceTree = "<group>";
};
50F9C5461C5FE56C009533F4 /* Products */ = {
isa = PBXGroup;
children = (
50F9C5451C5FE56C009533F4 /* iOS_CoreGraphics.app */,
);
name = Products;
sourceTree = "<group>";
};
50F9C5471C5FE56C009533F4 /* iOS_CoreGraphics */ = {
isa = PBXGroup;
children = (
50F9C5621C5FE7D9009533F4 /* demo.c */,
50F9C55F1C5FE7BD009533F4 /* zahnrad.c */,
50F9C5601C5FE7BD009533F4 /* zahnrad.h */,
50F9C5491C5FE56C009533F4 /* main.m */,
50F9C5591C5FE56C009533F4 /* Info.plist */,
50F9C5481C5FE56C009533F4 /* Supporting Files */,
);
path = iOS_CoreGraphics;
sourceTree = "<group>";
};
50F9C5481C5FE56C009533F4 /* Supporting Files */ = {
isa = PBXGroup;
children = (
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
50F9C5441C5FE56C009533F4 /* iOS_CoreGraphics */ = {
isa = PBXNativeTarget;
buildConfigurationList = 50F9C55C1C5FE56C009533F4 /* Build configuration list for PBXNativeTarget "iOS_CoreGraphics" */;
buildPhases = (
50F9C5411C5FE56C009533F4 /* Sources */,
50F9C5421C5FE56C009533F4 /* Frameworks */,
50F9C5431C5FE56C009533F4 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = iOS_CoreGraphics;
productName = iOS_CoreGraphics;
productReference = 50F9C5451C5FE56C009533F4 /* iOS_CoreGraphics.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
50F9C53D1C5FE56C009533F4 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0720;
ORGANIZATIONNAME = richi;
TargetAttributes = {
50F9C5441C5FE56C009533F4 = {
CreatedOnToolsVersion = 7.2;
};
};
};
buildConfigurationList = 50F9C5401C5FE56C009533F4 /* Build configuration list for PBXProject "iOS_CoreGraphics" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 50F9C53C1C5FE56C009533F4;
productRefGroup = 50F9C5461C5FE56C009533F4 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
50F9C5441C5FE56C009533F4 /* iOS_CoreGraphics */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
50F9C5431C5FE56C009533F4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
50F9C5411C5FE56C009533F4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
50F9C5611C5FE7BD009533F4 /* zahnrad.c in Sources */,
50F9C54A1C5FE56C009533F4 /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
50F9C55A1C5FE56C009533F4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
50F9C55B1C5FE56C009533F4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
50F9C55D1C5FE56C009533F4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "Brand Assets";
INFOPLIST_FILE = iOS_CoreGraphics/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.richi.iOS-CoreGraphics";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
50F9C55E1C5FE56C009533F4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "Brand Assets";
INFOPLIST_FILE = iOS_CoreGraphics/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.richi.iOS-CoreGraphics";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
50F9C5401C5FE56C009533F4 /* Build configuration list for PBXProject "iOS_CoreGraphics" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50F9C55A1C5FE56C009533F4 /* Debug */,
50F9C55B1C5FE56C009533F4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
50F9C55C1C5FE56C009533F4 /* Build configuration list for PBXNativeTarget "iOS_CoreGraphics" */ = {
isa = XCConfigurationList;
buildConfigurations = (
50F9C55D1C5FE56C009533F4 /* Debug */,
50F9C55E1C5FE56C009533F4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 50F9C53D1C5FE56C009533F4 /* Project object */;
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:iOS_CoreGraphics.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIcons</key>
<dict/>
<key>CFBundleIcons~ipad</key>
<dict/>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -1,341 +0,0 @@
/*
Copyright (c) 2016 richi
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#import <UIKit/UIKit.h>
#define DEMO_DO_NOT_DRAW_IMAGES
#include "zahnrad.h"
#include "../../demo.c"
static void* mem_alloc(zr_handle unused, size_t size)
{
return calloc(1, size);
}
static void mem_free(zr_handle unused, void* ptr)
{
free(ptr);
}
NSString* stringFromZR(const char* text, zr_size len)
{
char cstr[len + 1];
strncpy(cstr, text, len);
cstr[len] = 0;
return [NSString stringWithUTF8String: cstr];
}
static zr_size fontTextWidth(zr_handle handle, float height, const char* text, zr_size len)
{
UIFont* font = (__bridge UIFont*) handle.ptr;
NSString* aString = stringFromZR(text, len);
NSDictionary* attributes = @{ NSFontAttributeName: font};
CGSize stringSize = [aString sizeWithAttributes: attributes];
return ceil(stringSize.width);
}
#pragma mark - ZRView -
@interface ZRView : UIView
{
UIFont* font;
struct zr_user_font usrfnt;
struct zr_allocator alloc;
struct demo gui;
}
@end
@implementation ZRView
- (instancetype) initWithFrame: (CGRect) frame
{
if (!(self = [super initWithFrame: frame]))
return self;
alloc.userdata.ptr = NULL;
alloc.alloc = mem_alloc;
alloc.free = mem_free;
font = [UIFont systemFontOfSize: 11];
font = [UIFont fontWithName: @"Menlo-Regular" size: 11];
NSDictionary* attributes = @{NSFontAttributeName: font};
CGSize stringSize = [@"W" sizeWithAttributes: attributes];
memset(&usrfnt, 0, sizeof(usrfnt));
usrfnt.height = round(stringSize.height);
usrfnt.width = fontTextWidth;
usrfnt.userdata.ptr = (__bridge void*)(font);
zr_init(&gui.ctx, &alloc, &usrfnt);
zr_clear(&gui.ctx);
run_demo(&gui);
return self;
}
#define setColor(_c) \
CGContextSetRGBStrokeColor(context, _c->color.r / 255.0, _c->color.g / 255.0, _c->color.b / 255.0, _c->color.a / 255.0); \
CGContextSetRGBFillColor(context, _c->color.r / 255.0, _c->color.g / 255.0, _c->color.b / 255.0, _c->color.a / 255.0);
- (void) drawRect: (CGRect) rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
UIGraphicsPushContext(context);
UIColor* color = [UIColor blackColor];
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, rect);
const struct zr_command* cmd;
CGContextSaveGState(context);
zr_foreach(cmd, &gui.ctx)
{
switch (cmd->type)
{
case ZR_COMMAND_SCISSOR:
{
const struct zr_command_scissor* s = zr_command(scissor, cmd);
CGRect cr = CGRectMake(s->x, s->y, s->w, s->h);
CGContextRestoreGState(context);
CGContextSaveGState(context);
CGContextClipToRect(context, cr);
} break;
case ZR_COMMAND_LINE:
{
const struct zr_command_line* l = zr_command(line, cmd);
setColor(l);
CGContextBeginPath(context);
CGContextMoveToPoint(context, l->begin.x + .5, l->begin.y + .5);
CGContextAddLineToPoint(context, l->end.x + .5, l->end.y + .5);
CGContextStrokePath(context);
} break;
case ZR_COMMAND_RECT:
{
const struct zr_command_rect* r = zr_command(rect, cmd);
CGRect cr = CGRectMake(r->x, r->y, r->w, r->h);
setColor(r);
if (!r->rounding) CGContextFillRect(context, cr);
else
{
CGMutablePathRef p = CGPathCreateMutable();
CGPathAddRoundedRect(p, nil, cr, r->rounding, r->rounding);
CGPathCloseSubpath(p);
CGContextBeginPath(context);
CGContextAddPath(context, p);
CGContextDrawPath(context, kCGPathFill);
CGPathRelease(p);
}
} break;
case ZR_COMMAND_CIRCLE:
{
const struct zr_command_circle* c = zr_command(circle, cmd);
CGRect cr = CGRectMake(c->x, c->y, c->w, c->h);
setColor(c);
CGContextFillEllipseInRect(context, cr);
} break;
case ZR_COMMAND_TRIANGLE:
{
const struct zr_command_triangle* t = zr_command(triangle, cmd);
setColor(t);
CGContextBeginPath(context);
CGContextMoveToPoint (context, t->a.x, t->a.y);
CGContextAddLineToPoint(context, t->b.x, t->b.y);
CGContextAddLineToPoint(context, t->c.x, t->c.y);
CGContextClosePath(context);
CGContextFillPath(context);
} break;
case ZR_COMMAND_TEXT:
{
const struct zr_command_text* t = zr_command(text, cmd);
CGRect cr = CGRectMake(t->x, t->y, t->w, t->h);
CGContextSetRGBFillColor(context, t->background.r / 255.0, t->background.g / 255.0, t->background.b / 255.0, t->background.a / 255.0);
CGContextFillRect(context, cr);
NSString* aString = stringFromZR(t->string, t->length);
UIColor* fg = [UIColor colorWithRed: t->foreground.r / 255.0 green: t->foreground.g / 255.0 blue: t->foreground.b / 255.0 alpha: t->foreground.a / 255.0];
UIColor* bg = [UIColor colorWithRed: t->background.r / 255.0 green: t->background.g / 255.0 blue: t->background.b / 255.0 alpha: t->background.a / 255.0];
NSDictionary* attributes = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: fg, NSBackgroundColorAttributeName: bg };
CGSize size = [aString sizeWithAttributes: attributes];
CGRect xr = CGRectMake(cr.origin.x, cr.origin.y + (cr.size.height - size.height) / 2.0, cr.size.width, size.height);
[aString drawInRect: xr withAttributes: attributes];
} break;
case ZR_COMMAND_CURVE:
case ZR_COMMAND_IMAGE:
case ZR_COMMAND_ARC:
case ZR_COMMAND_NOP:
default:
break;
}
}
UIGraphicsPopContext();
}
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView: self];
zr_input_begin(&gui.ctx);
zr_input_motion(&gui.ctx, location.x, location.y);
zr_input_end(&gui.ctx);
zr_clear(&gui.ctx);
zr_input_begin(&gui.ctx);
zr_input_button(&gui.ctx, ZR_BUTTON_LEFT, location.x, location.y, zr_true);
zr_input_end(&gui.ctx);
run_demo(&gui);
[self setNeedsDisplay];
}
- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView: self];
zr_clear(&gui.ctx);
zr_input_begin(&gui.ctx);
zr_input_motion(&gui.ctx, location.x, location.y);
zr_input_end(&gui.ctx);
run_demo(&gui);
[self setNeedsDisplay];
}
- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView: self];
zr_clear(&gui.ctx);
zr_input_begin(&gui.ctx);
zr_input_motion(&gui.ctx, location.x, location.y);
zr_input_button(&gui.ctx, ZR_BUTTON_LEFT, location.x, location.y, zr_false);
zr_input_end(&gui.ctx);
run_demo(&gui);
zr_clear(&gui.ctx);
zr_input_begin(&gui.ctx);
zr_input_motion(&gui.ctx, 0, 0);
zr_input_end(&gui.ctx);
run_demo(&gui);
[self setNeedsDisplay];
}
- (void) touchesCancelled: (NSSet*) touches withEvent: (UIEvent*) event
{
[self touchesEnded: touches withEvent: event];
}
@end
#pragma mark - ViewController -
@interface ViewController : UIViewController
@property (strong, nonatomic) ZRView* zrView;
@end
@implementation ViewController
- (void) viewDidLoad
{
[super viewDidLoad];
_zrView = [[ZRView alloc] initWithFrame: self.view.bounds];
[self.view addSubview: _zrView];
}
@end
#pragma mark - App Delegate -
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow* window;
@property (strong, nonatomic) ViewController* viewController;
@end
@implementation AppDelegate
- (BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
{
_window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
_viewController = [ViewController new];
_window.rootViewController = _viewController;
[_window makeKeyAndVisible];
return YES;
}
@end
int main(int argc, char* argv[])
{
@autoreleasepool
{
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View File

@ -1,296 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
500B20321C4B42B60002B53F /* ZahnradBackend.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B20311C4B42B60002B53F /* ZahnradBackend.m */; };
500B20341C4B43010002B53F /* zahnrad.c in Sources */ = {isa = PBXBuildFile; fileRef = 500B20331C4B43010002B53F /* zahnrad.c */; };
500B203A1C4B43380002B53F /* DroidSans.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20361C4B43380002B53F /* DroidSans.ttf */; };
500B203B1C4B43380002B53F /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20371C4B43380002B53F /* Roboto-Bold.ttf */; };
500B203C1C4B43380002B53F /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20381C4B43380002B53F /* Roboto-Light.ttf */; };
500B203D1C4B43380002B53F /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20391C4B43380002B53F /* Roboto-Regular.ttf */; };
504DFDF11C4EA36500D3714A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B1FF91C4B410F0002B53F /* main.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
500B1FF51C4B410F0002B53F /* iOS_GL_ES.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOS_GL_ES.app; sourceTree = BUILT_PRODUCTS_DIR; };
500B1FF91C4B410F0002B53F /* main.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; tabWidth = 4; };
500B200D1C4B410F0002B53F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
500B20301C4B42B60002B53F /* ZahnradBackend.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = ZahnradBackend.h; sourceTree = SOURCE_ROOT; tabWidth = 4; };
500B20311C4B42B60002B53F /* ZahnradBackend.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = ZahnradBackend.m; sourceTree = SOURCE_ROOT; tabWidth = 4; };
500B20331C4B43010002B53F /* zahnrad.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = zahnrad.c; path = ../../../zahnrad.c; sourceTree = "<group>"; tabWidth = 4; };
500B20361C4B43380002B53F /* DroidSans.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = DroidSans.ttf; sourceTree = "<group>"; };
500B20371C4B43380002B53F /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
500B20381C4B43380002B53F /* Roboto-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Light.ttf"; sourceTree = "<group>"; };
500B20391C4B43380002B53F /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
504DFDEB1C4EA2EE00D3714A /* zahnrad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zahnrad.h; path = ../../../zahnrad.h; sourceTree = "<group>"; };
504DFDEF1C4EA36200D3714A /* demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = demo.c; path = ../../demo.c; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
500B1FF21C4B410F0002B53F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
500B1FEC1C4B410F0002B53F = {
isa = PBXGroup;
children = (
500B1FF71C4B410F0002B53F /* iOS_GL_ES */,
500B20351C4B43380002B53F /* font */,
500B1FF61C4B410F0002B53F /* Products */,
);
sourceTree = "<group>";
};
500B1FF61C4B410F0002B53F /* Products */ = {
isa = PBXGroup;
children = (
500B1FF51C4B410F0002B53F /* iOS_GL_ES.app */,
);
name = Products;
sourceTree = "<group>";
};
500B1FF71C4B410F0002B53F /* iOS_GL_ES */ = {
isa = PBXGroup;
children = (
504DFDEF1C4EA36200D3714A /* demo.c */,
500B20301C4B42B60002B53F /* ZahnradBackend.h */,
500B20311C4B42B60002B53F /* ZahnradBackend.m */,
500B1FF91C4B410F0002B53F /* main.m */,
504DFDEB1C4EA2EE00D3714A /* zahnrad.h */,
500B20331C4B43010002B53F /* zahnrad.c */,
500B200D1C4B410F0002B53F /* Info.plist */,
);
path = iOS_GL_ES;
sourceTree = "<group>";
};
500B20351C4B43380002B53F /* font */ = {
isa = PBXGroup;
children = (
500B20361C4B43380002B53F /* DroidSans.ttf */,
500B20371C4B43380002B53F /* Roboto-Bold.ttf */,
500B20381C4B43380002B53F /* Roboto-Light.ttf */,
500B20391C4B43380002B53F /* Roboto-Regular.ttf */,
);
name = font;
path = ../../font;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
500B1FF41C4B410F0002B53F /* iOS_GL_ES */ = {
isa = PBXNativeTarget;
buildConfigurationList = 500B20101C4B410F0002B53F /* Build configuration list for PBXNativeTarget "iOS_GL_ES" */;
buildPhases = (
500B1FF11C4B410F0002B53F /* Sources */,
500B1FF21C4B410F0002B53F /* Frameworks */,
500B1FF31C4B410F0002B53F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = iOS_GL_ES;
productName = iOS_GL_ES;
productReference = 500B1FF51C4B410F0002B53F /* iOS_GL_ES.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
500B1FED1C4B410F0002B53F /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0720;
ORGANIZATIONNAME = richi;
TargetAttributes = {
500B1FF41C4B410F0002B53F = {
CreatedOnToolsVersion = 7.2;
};
};
};
buildConfigurationList = 500B1FF01C4B410F0002B53F /* Build configuration list for PBXProject "iOS_GL_ES" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 500B1FEC1C4B410F0002B53F;
productRefGroup = 500B1FF61C4B410F0002B53F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
500B1FF41C4B410F0002B53F /* iOS_GL_ES */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
500B1FF31C4B410F0002B53F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
500B203B1C4B43380002B53F /* Roboto-Bold.ttf in Resources */,
500B203A1C4B43380002B53F /* DroidSans.ttf in Resources */,
500B203D1C4B43380002B53F /* Roboto-Regular.ttf in Resources */,
500B203C1C4B43380002B53F /* Roboto-Light.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
500B1FF11C4B410F0002B53F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
500B20341C4B43010002B53F /* zahnrad.c in Sources */,
504DFDF11C4EA36500D3714A /* main.m in Sources */,
500B20321C4B42B60002B53F /* ZahnradBackend.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
500B200E1C4B410F0002B53F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
500B200F1C4B410F0002B53F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
500B20111C4B410F0002B53F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = iOS_GL_ES/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.richi.iOS-GL-ES";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
500B20121C4B410F0002B53F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = iOS_GL_ES/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.richi.iOS-GL-ES";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
500B1FF01C4B410F0002B53F /* Build configuration list for PBXProject "iOS_GL_ES" */ = {
isa = XCConfigurationList;
buildConfigurations = (
500B200E1C4B410F0002B53F /* Debug */,
500B200F1C4B410F0002B53F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
500B20101C4B410F0002B53F /* Build configuration list for PBXNativeTarget "iOS_GL_ES" */ = {
isa = XCConfigurationList;
buildConfigurations = (
500B20111C4B410F0002B53F /* Debug */,
500B20121C4B410F0002B53F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 500B1FED1C4B410F0002B53F /* Project object */;
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:iOS_GL_ES.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@ -1,225 +0,0 @@
/*
Copyright (c) 2016 richi
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import "ZahnradBackend.h"
@interface GameViewController : GLKViewController <UIKeyInput>
@end
@implementation GameViewController
{
BOOL keyboardAllowed;
NSUInteger keyboardHash;
EAGLContext* context;
ZahnradBackend* zr;
}
- (void) viewDidLoad
{
[super viewDidLoad];
keyboardHash = -1;
context = [[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES3];
assert(context != nil);
((GLKView*)self.view).context = context;
((GLKView*)self.view).drawableDepthFormat = GLKViewDrawableDepthFormatNone;
[EAGLContext setCurrentContext: context];
zr = [[ZahnradBackend alloc] initWithView: ((GLKView*)self.view)];
}
- (BOOL) prefersStatusBarHidden
{
return YES;
}
- (void) update
{
[zr updateFrame];
}
- (void) glkView: (GLKView*) view drawInRect: (CGRect) rect
{
CGRect bounds = view.bounds;
CGFloat scale = view.window.screen.scale;
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
[zr drawFrameWithScale: scale width: bounds.size.width height: bounds.size.height];
}
#pragma mark - User Input -
- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView: self.view];
[zr addEvent: @{@"type" : @2, @"pos" : NSStringFromCGPoint(location)}];
}
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView: self.view];
[zr addEvent: @{@"type" : @5, @"pos" : NSStringFromCGPoint(location)}];
}
- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event
{
UITouch* touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView: self.view];
[zr addEvent: @{@"type" : @6, @"pos" : NSStringFromCGPoint(location)}];
}
- (void) touchesCancelled: (NSSet*) touches withEvent: (UIEvent*) event
{
[self touchesEnded: touches withEvent: event];
}
- (void) insertText: (NSString*) text
{
[zr addEvent: @{@"type" : @12, @"txt" : text, @"mod" : @0}];
}
- (void) deleteBackward
{
[zr addEvent: @{@"type" : @12, @"txt" : @"\b", @"mod" : @0}];
}
- (BOOL) hasText
{
return NO;
}
- (BOOL) canBecomeFirstResponder
{
return keyboardAllowed;
}
- (BOOL) canResignFirstResponder
{
return YES;
}
- (void) showKeyboard: (NSDictionary*) info
{
NSUInteger hash = [info[@"hash"] unsignedIntegerValue];
if (hash != keyboardHash)
{
keyboardHash = hash;
keyboardAllowed = YES;
if (!self.isFirstResponder)
[self becomeFirstResponder];
}
}
- (void) hideKeyboard
{
keyboardHash = -1;
keyboardAllowed = NO;
[self resignFirstResponder];
}
@end
#pragma mark - App Delegate -
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow* window;
@property (strong, nonatomic) GameViewController* gameViewController;
@end
@implementation AppDelegate
- (void) showKeyboard: (NSDictionary*) info
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.gameViewController showKeyboard: info];
});
}
- (void) hideKeyboard
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.gameViewController hideKeyboard];
});
}
- (BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
{
_window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
_gameViewController = [GameViewController new];
_window.rootViewController = _gameViewController;
[_window makeKeyAndVisible];
return YES;
}
@end
int main(int argc, char* argv[])
{
@autoreleasepool
{
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View File

@ -1,292 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
500B20661C4B4AB00002B53F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B20651C4B4AB00002B53F /* main.m */; };
500B208A1C4B4D460002B53F /* ZahnradBackend.m in Sources */ = {isa = PBXBuildFile; fileRef = 500B20891C4B4D460002B53F /* ZahnradBackend.m */; };
500B208C1C4B4D580002B53F /* zahnrad.c in Sources */ = {isa = PBXBuildFile; fileRef = 500B208B1C4B4D580002B53F /* zahnrad.c */; };
500B20921C4B4D700002B53F /* DroidSans.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B208E1C4B4D700002B53F /* DroidSans.ttf */; };
500B20931C4B4D700002B53F /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B208F1C4B4D700002B53F /* Roboto-Bold.ttf */; };
500B20941C4B4D700002B53F /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20901C4B4D700002B53F /* Roboto-Light.ttf */; };
500B20951C4B4D700002B53F /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 500B20911C4B4D700002B53F /* Roboto-Regular.ttf */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
500B20611C4B4AB00002B53F /* tvOS_GL_ES.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tvOS_GL_ES.app; sourceTree = BUILT_PRODUCTS_DIR; };
500B20651C4B4AB00002B53F /* main.m */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; tabWidth = 4; };
500B20741C4B4AB00002B53F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
500B20881C4B4D460002B53F /* ZahnradBackend.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = ZahnradBackend.h; sourceTree = SOURCE_ROOT; tabWidth = 4; };
500B20891C4B4D460002B53F /* ZahnradBackend.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = ZahnradBackend.m; sourceTree = SOURCE_ROOT; tabWidth = 4; };
500B208B1C4B4D580002B53F /* zahnrad.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = zahnrad.c; path = ../../../zahnrad.c; sourceTree = "<group>"; tabWidth = 5; };
500B208E1C4B4D700002B53F /* DroidSans.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = DroidSans.ttf; sourceTree = "<group>"; };
500B208F1C4B4D700002B53F /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
500B20901C4B4D700002B53F /* Roboto-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Light.ttf"; sourceTree = "<group>"; };
500B20911C4B4D700002B53F /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
504DFDEC1C4EA2FF00D3714A /* zahnrad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zahnrad.h; path = ../../../zahnrad.h; sourceTree = "<group>"; };
504DFDF21C4EA37700D3714A /* demo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = demo.c; path = ../../demo.c; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
500B205E1C4B4AB00002B53F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
500B20581C4B4AB00002B53F = {
isa = PBXGroup;
children = (
500B20631C4B4AB00002B53F /* tvOS_GL_ES */,
500B208D1C4B4D700002B53F /* font */,
500B20621C4B4AB00002B53F /* Products */,
);
sourceTree = "<group>";
};
500B20621C4B4AB00002B53F /* Products */ = {
isa = PBXGroup;
children = (
500B20611C4B4AB00002B53F /* tvOS_GL_ES.app */,
);
name = Products;
sourceTree = "<group>";
};
500B20631C4B4AB00002B53F /* tvOS_GL_ES */ = {
isa = PBXGroup;
children = (
504DFDF21C4EA37700D3714A /* demo.c */,
500B20881C4B4D460002B53F /* ZahnradBackend.h */,
500B20891C4B4D460002B53F /* ZahnradBackend.m */,
500B20651C4B4AB00002B53F /* main.m */,
504DFDEC1C4EA2FF00D3714A /* zahnrad.h */,
500B208B1C4B4D580002B53F /* zahnrad.c */,
500B20741C4B4AB00002B53F /* Info.plist */,
);
path = tvOS_GL_ES;
sourceTree = "<group>";
};
500B208D1C4B4D700002B53F /* font */ = {
isa = PBXGroup;
children = (
500B208E1C4B4D700002B53F /* DroidSans.ttf */,
500B208F1C4B4D700002B53F /* Roboto-Bold.ttf */,
500B20901C4B4D700002B53F /* Roboto-Light.ttf */,
500B20911C4B4D700002B53F /* Roboto-Regular.ttf */,
);
name = font;
path = ../../font;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
500B20601C4B4AB00002B53F /* tvOS_GL_ES */ = {
isa = PBXNativeTarget;
buildConfigurationList = 500B20771C4B4AB00002B53F /* Build configuration list for PBXNativeTarget "tvOS_GL_ES" */;
buildPhases = (
500B205D1C4B4AB00002B53F /* Sources */,
500B205E1C4B4AB00002B53F /* Frameworks */,
500B205F1C4B4AB00002B53F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = tvOS_GL_ES;
productName = tvOS_GL_ES;
productReference = 500B20611C4B4AB00002B53F /* tvOS_GL_ES.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
500B20591C4B4AB00002B53F /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0720;
ORGANIZATIONNAME = richi;
TargetAttributes = {
500B20601C4B4AB00002B53F = {
CreatedOnToolsVersion = 7.2;
};
};
};
buildConfigurationList = 500B205C1C4B4AB00002B53F /* Build configuration list for PBXProject "tvOS_GL_ES" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 500B20581C4B4AB00002B53F;
productRefGroup = 500B20621C4B4AB00002B53F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
500B20601C4B4AB00002B53F /* tvOS_GL_ES */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
500B205F1C4B4AB00002B53F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
500B20931C4B4D700002B53F /* Roboto-Bold.ttf in Resources */,
500B20921C4B4D700002B53F /* DroidSans.ttf in Resources */,
500B20951C4B4D700002B53F /* Roboto-Regular.ttf in Resources */,
500B20941C4B4D700002B53F /* Roboto-Light.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
500B205D1C4B4AB00002B53F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
500B20661C4B4AB00002B53F /* main.m in Sources */,
500B208C1C4B4D580002B53F /* zahnrad.c in Sources */,
500B208A1C4B4D460002B53F /* ZahnradBackend.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
500B20751C4B4AB00002B53F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = appletvos;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.1;
};
name = Debug;
};
500B20761C4B4AB00002B53F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = appletvos;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.1;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
500B20781C4B4AB00002B53F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = tvOS_GL_ES/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.richi.tvOS-GL-ES";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
500B20791C4B4AB00002B53F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = tvOS_GL_ES/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.richi.tvOS-GL-ES";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
500B205C1C4B4AB00002B53F /* Build configuration list for PBXProject "tvOS_GL_ES" */ = {
isa = XCConfigurationList;
buildConfigurations = (
500B20751C4B4AB00002B53F /* Debug */,
500B20761C4B4AB00002B53F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
500B20771C4B4AB00002B53F /* Build configuration list for PBXNativeTarget "tvOS_GL_ES" */ = {
isa = XCConfigurationList;
buildConfigurations = (
500B20781C4B4AB00002B53F /* Debug */,
500B20791C4B4AB00002B53F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 500B20591C4B4AB00002B53F /* Project object */;
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:tvOS_GL_ES.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
</dict>
</plist>

View File

@ -1,254 +0,0 @@
/*
Copyright (c) 2016 richi
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import "ZahnradBackend.h"
@interface GameViewController : GLKViewController <UITextFieldDelegate>
@end
@implementation GameViewController
{
NSUInteger keyboardHash;
UITextField* textInputField;
CGPoint cursor;
UIView* cursorView;
EAGLContext* context;
ZahnradBackend* zr;
}
- (void) viewDidLoad
{
[super viewDidLoad];
keyboardHash = -1;
context = [[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES3];
assert(context != nil);
((GLKView*)self.view).context = context;
((GLKView*)self.view).drawableDepthFormat = GLKViewDrawableDepthFormatNone;
[EAGLContext setCurrentContext: context];
zr = [[ZahnradBackend alloc] initWithView: ((GLKView*)self.view)];
UIPanGestureRecognizer* panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action: @selector(pan:)];
[self.view addGestureRecognizer:panRecognizer];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
cursor = CGPointMake(95, 70);
cursorView = [[UIView alloc] initWithFrame: CGRectMake(cursor.x, cursor.y, 10, 10)];
cursorView.backgroundColor = UIColor.redColor;
[self.view addSubview: cursorView];
[zr addEvent: @{@"type" : @2, @"pos" : NSStringFromCGPoint(cursor)}];
});
}
- (void) update
{
[zr updateFrame];
}
- (void) glkView: (GLKView*) view drawInRect: (CGRect) rect
{
CGRect bounds = view.bounds;
CGFloat scale = view.window.screen.scale;
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
[zr drawFrameWithScale: scale width: bounds.size.width height: bounds.size.height];
}
#pragma mark - User Input -
- (void) pan: (UIPanGestureRecognizer*) panRecognizer
{
CGPoint delta = [panRecognizer translationInView: self.view];
#if 0
CGFloat s = 33.0;
cursor.x += delta.x / s;
cursor.y += delta.y / s;
#else
CGFloat s = 150.0;
if (delta.x != 0.0)
cursor.x += pow(2.0, fabs(delta.x / s)) * (delta.x > 0.0 ? 1.0 : -1.0);
if (delta.y != 0.0)
cursor.y += pow(2.0, fabs(delta.y / s)) * (delta.y > 0.0 ? 1.0 : -1.0);
#endif
CGRect bounds = self.view.bounds;
if (cursor.x < CGRectGetMinX(bounds)) cursor.x = CGRectGetMinX(bounds);
if (cursor.x > CGRectGetMaxX(bounds)) cursor.x = CGRectGetMaxX(bounds);
if (cursor.y < CGRectGetMinY(bounds)) cursor.y = CGRectGetMinY(bounds);
if (cursor.y > CGRectGetMaxY(bounds)) cursor.y = CGRectGetMaxY(bounds);
cursorView.center = cursor;
[zr addEvent: @{@"type" : @2, @"pos" : NSStringFromCGPoint(cursor)}];
}
- (void) pressesBegan: (NSSet*) presses withEvent: (UIPressesEvent*) event
{
UIPress* press = [[event allPresses] anyObject];
if (press.type != UIPressTypeSelect) return;
[zr addEvent: @{@"type" : @5, @"pos" : NSStringFromCGPoint(cursor)}];
}
- (void) pressesEnded: (NSSet*) presses withEvent: (UIPressesEvent*) event
{
UIPress* press = [[event allPresses] anyObject];
if (press.type != UIPressTypeSelect) return;
[zr addEvent: @{@"type" : @6, @"pos" : NSStringFromCGPoint(cursor)}];
}
- (void) pressesCancelled: (NSSet*) presses withEvent: (UIPressesEvent*) event
{
[self pressesEnded: presses withEvent: event];
}
- (BOOL) textFieldShouldReturn: (UITextField*) textField
{
return YES;
}
- (void) textFieldDidEndEditing: (UITextField*) textField
{
[textInputField resignFirstResponder];
[textInputField removeFromSuperview];
textInputField = nil;
[zr addEvent: @{@"type" : @12, @"txt" : textField.text, @"mod" : @0}];
}
- (void) showKeyboard: (NSDictionary*) info
{
NSUInteger hash = [info[@"hash"] unsignedIntegerValue];
if (hash != keyboardHash)
{
keyboardHash = hash;
if (!textInputField)
{
CGRect frame = CGRectFromString(info[@"frame"]);
textInputField = [[UITextField alloc] initWithFrame: frame];
textInputField.delegate = self;
textInputField.text = info[@"text"];
[self.view addSubview: textInputField];
[textInputField becomeFirstResponder];
}
}
}
- (void) hideKeyboard
{
[textInputField resignFirstResponder];
[textInputField removeFromSuperview];
textInputField = nil;
keyboardHash = -1;
}
@end
#pragma mark - App Delegate -
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow* window;
@property (strong, nonatomic) GameViewController* gameViewController;
@end
@implementation AppDelegate
- (void) showKeyboard: (NSDictionary*) info
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.gameViewController showKeyboard: info];
});
}
- (void) hideKeyboard
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.gameViewController hideKeyboard];
});
}
- (BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
{
_window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
_gameViewController = [GameViewController new];
_window.rootViewController = _gameViewController;
[_window makeKeyAndVisible];
return YES;
}
@end
int main(int argc, char* argv[])
{
@autoreleasepool
{
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ DCC = gcc
# Flags
CFLAGS = -std=c99 -pedantic -O2
SRC = ../../zahnrad.c glfw.c
SRC = main.c
OBJ = $(SRC:.c=.o)
ifeq ($(OS),Windows_NT)

View File

@ -1,591 +0,0 @@
/*
Copyright (c) 2016 Micha Mettke
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GLFW/glfw3.h>
/* macros */
#define MAX_VERTEX_MEMORY 512 * 1024
#define MAX_ELEMENT_MEMORY 128 * 1024
#include "../../zahnrad.h"
#include "../demo.c"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wfloat-equal"
#pragma clang diagnostic ignored "-Wbad-function-cast"
#pragma clang diagnostic ignored "-Wcast-qual"
#pragma clang diagnostic ignored "-Wshadow"
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
#pragma clang diagnostic ignored "-Wdeclaration-after-statement"
#pragma clang diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wbad-function-cast"
#pragma GCC diagnostic ignored "-Wcast-qual"
#pragma GCC diagnostic ignored "-Wshadow"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
#pragma GCC diagnostic ignored "-Wtype-limits"
#pragma GCC diagnostic ignored "-Wswitch-default"
#pragma GCC diagnostic ignored "-Wunused-function"
#elif _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4456)
#endif
#define STB_IMAGE_IMPLEMENTATION
#include "../stb_image.h"
#ifdef __clang__
#pragma clang diagnostic pop
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic pop
#elif _MSC_VER
#pragma warning (pop)
#endif
static int mouse_pos_x = 0;
static int mouse_pos_y = 0;
static struct demo gui;
/* ==============================================================
*
* Utility
*
* ===============================================================*/
static void
die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputs("\n", stderr);
exit(EXIT_FAILURE);
}
static char*
file_load(const char* path, size_t* siz)
{
char *buf;
FILE *fd = fopen(path, "rb");
if (!fd) die("Failed to open file: %s\n", path);
fseek(fd, 0, SEEK_END);
*siz = (size_t)ftell(fd);
fseek(fd, 0, SEEK_SET);
buf = (char*)calloc(*siz, 1);
fread(buf, *siz, 1, fd);
fclose(fd);
return buf;
}
static struct zr_image
icon_load(const char *filename)
{
int x,y,n;
GLuint tex;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
if (!data) die("[SDL]: failed to load image: %s", filename);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
return zr_image_id((int)tex);
}
struct device {
struct zr_buffer cmds;
struct zr_draw_null_texture null;
GLuint vbo, vao, ebo;
GLuint prog;
GLuint vert_shdr;
GLuint frag_shdr;
GLint attrib_pos;
GLint attrib_uv;
GLint attrib_col;
GLint uniform_tex;
GLint uniform_proj;
GLuint font_tex;
};
static void
device_init(struct device *dev)
{
GLint status;
static const GLchar *vertex_shader =
"#version 300 es\n"
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main() {\n"
" Frag_UV = TexCoord;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
static const GLchar *fragment_shader =
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
dev->prog = glCreateProgram();
dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
glCompileShader(dev->vert_shdr);
glCompileShader(dev->frag_shdr);
glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glAttachShader(dev->prog, dev->vert_shdr);
glAttachShader(dev->prog, dev->frag_shdr);
glLinkProgram(dev->prog);
glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
assert(status == GL_TRUE);
dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
{
/* buffer setup */
GLsizei vs = sizeof(struct zr_draw_vertex);
size_t vp = offsetof(struct zr_draw_vertex, position);
size_t vt = offsetof(struct zr_draw_vertex, uv);
size_t vc = offsetof(struct zr_draw_vertex, col);
glGenBuffers(1, &dev->vbo);
glGenBuffers(1, &dev->ebo);
glGenVertexArrays(1, &dev->vao);
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glEnableVertexAttribArray((GLuint)dev->attrib_pos);
glEnableVertexAttribArray((GLuint)dev->attrib_uv);
glEnableVertexAttribArray((GLuint)dev->attrib_col);
glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
static void
device_upload_atlas(struct device *dev, const void *image, int width, int height)
{
glGenTextures(1, &dev->font_tex);
glBindTexture(GL_TEXTURE_2D, dev->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image);
}
static void
device_shutdown(struct device *dev)
{
glDetachShader(dev->prog, dev->vert_shdr);
glDetachShader(dev->prog, dev->frag_shdr);
glDeleteShader(dev->vert_shdr);
glDeleteShader(dev->frag_shdr);
glDeleteProgram(dev->prog);
glDeleteTextures(1, &dev->font_tex);
glDeleteBuffers(1, &dev->vbo);
glDeleteBuffers(1, &dev->ebo);
}
static void
device_draw(struct device *dev, struct zr_context *ctx, int width, int height,
enum zr_anti_aliasing AA)
{
GLint last_prog, last_tex;
GLint last_ebo, last_vbo, last_vao;
GLfloat ortho[4][4] = {
{2.0f, 0.0f, 0.0f, 0.0f},
{0.0f,-2.0f, 0.0f, 0.0f},
{0.0f, 0.0f,-1.0f, 0.0f},
{-1.0f,1.0f, 0.0f, 1.0f},
};
ortho[0][0] /= (GLfloat)width;
ortho[1][1] /= (GLfloat)height;
/* save previous opengl state */
glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
/* setup global state */
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
/* setup program */
glUseProgram(dev->prog);
glUniform1i(dev->uniform_tex, 0);
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
{
/* convert from command queue into draw list and draw to screen */
const struct zr_draw_command *cmd;
void *vertices, *elements;
const zr_draw_index *offset = NULL;
/* allocate vertex and element buffer */
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
/* load draw vertices & elements directly into vertex + element buffer */
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
{
struct zr_buffer vbuf, ebuf;
/* fill converting configuration */
struct zr_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.curve_segment_count = 22;
config.arc_segment_count = 22;
config.null = dev->null;
/* setup buffers to load vertices and elements */
zr_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
/* iterate over and execute each draw command */
zr_draw_foreach(cmd, ctx, &dev->cmds) {
if (!cmd->elem_count) continue;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)cmd->clip_rect.x,
height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
(GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
zr_clear(ctx);
}
/* restore old state */
glUseProgram((GLuint)last_prog);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
glBindVertexArray((GLuint)last_vao);
glDisable(GL_SCISSOR_TEST);
}
static void
error_callback(int error, const char *description)
{
fprintf(stderr, "Error %d: %s\n", error, description);
}
static void
input_key(GLFWwindow *window, int key, int scancode, int action, int mods)
{
int down = action == GLFW_PRESS;
UNUSED(window);
UNUSED(scancode);
if (key == GLFW_KEY_RIGHT_SHIFT || key == GLFW_KEY_LEFT_SHIFT)
zr_input_key(&gui.ctx, ZR_KEY_SHIFT, down);
else if (key == GLFW_KEY_TAB)
zr_input_key(&gui.ctx, ZR_KEY_TAB, down);
else if (key == GLFW_KEY_DELETE)
zr_input_key(&gui.ctx, ZR_KEY_DEL, down);
else if (key == GLFW_KEY_ENTER)
zr_input_key(&gui.ctx, ZR_KEY_ENTER, down);
else if (key == GLFW_KEY_BACKSPACE)
zr_input_key(&gui.ctx, ZR_KEY_BACKSPACE, down);
else if (key == GLFW_KEY_LEFT)
zr_input_key(&gui.ctx, ZR_KEY_LEFT, down);
else if (key == GLFW_KEY_RIGHT)
zr_input_key(&gui.ctx, ZR_KEY_RIGHT, down);
else if (key == GLFW_KEY_C)
zr_input_key(&gui.ctx, ZR_KEY_COPY, down && (mods & GLFW_MOD_CONTROL));
else if (key == GLFW_KEY_V)
zr_input_key(&gui.ctx, ZR_KEY_PASTE, down && (mods & GLFW_MOD_CONTROL));
else if (key == GLFW_KEY_X)
zr_input_key(&gui.ctx, ZR_KEY_CUT, down && (mods & GLFW_MOD_CONTROL));
}
static void
input_motion(GLFWwindow *window, double xpos, double ypos)
{
const int x = (int)xpos;
const int y = (int)ypos;
UNUSED(window);
mouse_pos_x = x;
mouse_pos_y = y;
zr_input_motion(&gui.ctx, x, y);
}
static void
input_button(GLFWwindow *window, int button, int action, int mods)
{
int x = mouse_pos_x;
int y = mouse_pos_y;
UNUSED(window);
UNUSED(mods);
if (button == 0)
zr_input_button(&gui.ctx, ZR_BUTTON_LEFT, x, y, action == GLFW_PRESS);
if (button == 1)
zr_input_button(&gui.ctx, ZR_BUTTON_RIGHT, x, y, action == GLFW_PRESS);
if (button == 2)
zr_input_button(&gui.ctx, ZR_BUTTON_MIDDLE, x, y, action == GLFW_PRESS);
}
static void
input_text(GLFWwindow *window, unsigned int codepoint)
{
UNUSED(window);
zr_input_unicode(&gui.ctx, codepoint);
}
static void
input_scroll(GLFWwindow *window, double xoffset, double yoffset)
{
UNUSED(window);
UNUSED(xoffset);
zr_input_scroll(&gui.ctx, (float)yoffset);
}
int
main(int argc, char *argv[])
{
/* Platform */
int i;
static GLFWwindow *win;
const char *font_path;
int width = 0, height = 0;
int running = 1;
/* GUI */
struct device device;
struct zr_font *font;
struct zr_font_atlas atlas;
font_path = (argc > 1) ? argv[1]: 0;
glfwSetErrorCallback(error_callback);
if (!glfwInit()) {
fprintf(stdout, "[GFLW] failed to init!\n");
return 1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
glfwMakeContextCurrent(win);
glfwSetCursorPosCallback(win, input_motion);
glfwSetMouseButtonCallback(win, input_button);
glfwSetKeyCallback(win, input_key);
glfwSetCharCallback(win, input_text);
glfwSetScrollCallback(win, input_scroll);
/* OpenGL */
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glewExperimental = 1;
if (glewInit() != GLEW_OK)
die("Failed to setup GLEW\n");
device_init(&device);
{
/* Font */
const void *image;
int w, h;
zr_font_atlas_init_default(&atlas);
zr_font_atlas_begin(&atlas);
if (font_path) font = zr_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
else font = zr_font_atlas_add_default(&atlas, 14.0f, NULL);
image = zr_font_atlas_bake(&atlas, &w, &h, ZR_FONT_ATLAS_RGBA32);
device_upload_atlas(&device, image, w, h);
zr_font_atlas_end(&atlas, zr_handle_id((int)device.font_tex), &device.null);
/* GUI */
memset(&gui, 0, sizeof(gui));
zr_buffer_init_default(&device.cmds);
zr_init_default(&gui.ctx, &font->handle);
}
/* icons */
glEnable(GL_TEXTURE_2D);
gui.icons.unchecked = icon_load("../../icon/unchecked.png");
gui.icons.checked = icon_load("../../icon/checked.png");
gui.icons.rocket = icon_load("../../icon/rocket.png");
gui.icons.cloud = icon_load("../../icon/cloud.png");
gui.icons.pen = icon_load("../../icon/pen.png");
gui.icons.play = icon_load("../../icon/play.png");
gui.icons.pause = icon_load("../../icon/pause.png");
gui.icons.stop = icon_load("../../icon/stop.png");
gui.icons.next = icon_load("../../icon/next.png");
gui.icons.prev = icon_load("../../icon/prev.png");
gui.icons.tools = icon_load("../../icon/tools.png");
gui.icons.dir = icon_load("../../icon/directory.png");
gui.icons.copy = icon_load("../../icon/copy.png");
gui.icons.convert = icon_load("../../icon/export.png");
gui.icons.del = icon_load("../../icon/delete.png");
gui.icons.edit = icon_load("../../icon/edit.png");
gui.icons.menu[0] = icon_load("../../icon/home.png");
gui.icons.menu[1] = icon_load("../../icon/phone.png");
gui.icons.menu[2] = icon_load("../../icon/plane.png");
gui.icons.menu[3] = icon_load("../../icon/wifi.png");
gui.icons.menu[4] = icon_load("../../icon/settings.png");
gui.icons.menu[5] = icon_load("../../icon/volume.png");
gui.icons.home = icon_load("../../icon/home.png");
gui.icons.directory = icon_load("../../icon/directory.png");
gui.icons.computer = icon_load("../../icon/computer.png");
gui.icons.desktop = icon_load("../../icon/desktop.png");
gui.icons.default_file = icon_load("../../icon/default.png");
gui.icons.text_file = icon_load("../../icon/text.png");
gui.icons.music_file = icon_load("../../icon/music.png");
gui.icons.font_file = icon_load("../../icon/font.png");
gui.icons.img_file = icon_load("../../icon/img.png");
gui.icons.movie_file = icon_load("../../icon/movie.png");
for (i = 0; i < 9; ++i) {
char buffer[256];
sprintf(buffer, "../../images/image%d.png", (i+1));
gui.icons.images[i] = icon_load(buffer);
}
while (!glfwWindowShouldClose(win) && running) {
/* Input */
zr_input_begin(&gui.ctx);
glfwPollEvents();
zr_input_end(&gui.ctx);
/* GUI */
glfwGetWindowSize(win, &width, &height);
running = run_demo(&gui);
/* Draw */
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
device_draw(&device, &gui.ctx, width, height, ZR_ANTI_ALIASING_ON);
glfwSwapBuffers(win);
}
/* Cleanup */
glDeleteTextures(1,(const GLuint*)&gui.icons.unchecked.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.checked.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.rocket.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.cloud.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.pen.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.play.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.pause.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.stop.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.next.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.prev.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.tools.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.dir.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.del.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.home.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.computer.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.desktop.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.default_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.text_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.music_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.font_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.img_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.movie_file.handle.id);
for (i = 0; i < 9; ++i)
glDeleteTextures(1, (const GLuint*)&gui.icons.images[i].handle.id);
for (i = 0; i < 6; ++i)
glDeleteTextures(1, (const GLuint*)&gui.icons.menu[i].handle.id);
zr_font_atlas_clear(&atlas);
zr_free(&gui.ctx);
zr_buffer_free(&device.cmds);
device_shutdown(&device);
glfwTerminate();
return 0;
}

139
demo/glfw/main.c Normal file
View File

@ -0,0 +1,139 @@
/* nuklear - v1.00 - public domain */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GLFW/glfw3.h>
/* these defines are both needed for the header
* and source file. So if you split them remember
* to copy them as well. */
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#include "nuklear_glfw.h"
#include "nuklear_glfw.c"
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define MAX_VERTEX_BUFFER 512 * 1024
#define MAX_ELEMENT_BUFFER 128 * 1024
static void error_callback(int e, const char *d){
printf("Error %d: %s\n", e, d);
}
int main(void)
{
/* Platform */
static GLFWwindow *win;
int width = 0, height = 0;
struct nk_context *ctx;
struct nk_color background;
/* GLFW */
glfwSetErrorCallback(error_callback);
if (!glfwInit()) {
fprintf(stdout, "[GFLW] failed to init!\n");
exit(1);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
glfwMakeContextCurrent(win);
/* OpenGL */
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glewExperimental = 1;
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to setup GLEW\n");
exit(1);
}
ctx = nk_glfw3_init(win, NK_GLFW3_INSTALL_CALLBACKS);
/* Load Fonts: if none of these are loaded a default font will be used */
{struct nk_font_atlas *atlas;
nk_glfw3_font_stash_begin(&atlas);
/*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
/*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Robot-Regular.ttf", 14, 0);*/
/*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
/*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
/*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
/*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
nk_glfw3_font_stash_end();
/*nk_style_set_font(ctx, &droid->handle)*/;}
background = nk_rgb(28,48,62);
while (!glfwWindowShouldClose(win))
{
/* Input */
glfwPollEvents();
nk_glfw3_new_frame();
/* GUI */
{struct nk_panel layout;
if (nk_begin(ctx, &layout, "Demo", nk_rect(50, 50, 230, 250),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
enum {EASY, HARD};
static int op = EASY;
static int property = 20;
nk_layout_row_static(ctx, 30, 80, 1);
if (nk_button_label(ctx, "button", NK_BUTTON_DEFAULT))
fprintf(stdout, "button pressed\n");
nk_layout_row_dynamic(ctx, 30, 2);
if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
nk_layout_row_dynamic(ctx, 22, 1);
nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
{struct nk_panel combo;
nk_layout_row_dynamic(ctx, 20, 1);
nk_label(ctx, "background:", NK_TEXT_LEFT);
nk_layout_row_dynamic(ctx, 25, 1);
if (nk_combo_begin_color(ctx, &combo, background, 400)) {
nk_layout_row_dynamic(ctx, 120, 1);
background = nk_color_picker(ctx, background, NK_RGBA);
nk_layout_row_dynamic(ctx, 25, 1);
background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
nk_combo_end(ctx);
}}
}
nk_end(ctx);}
/* Draw */
{float bg[4];
nk_color_fv(bg, background);
glfwGetWindowSize(win, &width, &height);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(bg[0], bg[1], bg[2], bg[3]);
nk_glfw3_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
glfwSwapBuffers(win);}
}
nk_glfw3_shutdown();
glfwTerminate();
return 0;
}

374
demo/glfw/nuklear_glfw.c Normal file
View File

@ -0,0 +1,374 @@
#include <string.h>
#define NK_IMPLEMENTATION
#include "nuklear_glfw.h"
#include "../../nuklear.h"
#define NK_GLFW_TEXT_MAX 256
struct nk_glfw_device {
struct nk_buffer cmds;
struct nk_draw_null_texture null;
GLuint vbo, vao, ebo;
GLuint prog;
GLuint vert_shdr;
GLuint frag_shdr;
GLint attrib_pos;
GLint attrib_uv;
GLint attrib_col;
GLint uniform_tex;
GLint uniform_proj;
GLuint font_tex;
};
static struct nk_glfw {
GLFWwindow *win;
struct nk_glfw_device ogl;
struct nk_context ctx;
struct nk_font_atlas atlas;
unsigned int text[NK_GLFW_TEXT_MAX];
int text_len;
float scroll;
} glfw;
NK_API void
nk_glfw3_device_create(void)
{
GLint status;
static const GLchar *vertex_shader =
"#version 300 es\n"
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main() {\n"
" Frag_UV = TexCoord;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
static const GLchar *fragment_shader =
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
struct nk_glfw_device *dev = &glfw.ogl;
nk_buffer_init_default(&dev->cmds);
dev->prog = glCreateProgram();
dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
glCompileShader(dev->vert_shdr);
glCompileShader(dev->frag_shdr);
glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glAttachShader(dev->prog, dev->vert_shdr);
glAttachShader(dev->prog, dev->frag_shdr);
glLinkProgram(dev->prog);
glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
assert(status == GL_TRUE);
dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
{
/* buffer setup */
GLsizei vs = sizeof(struct nk_draw_vertex);
size_t vp = offsetof(struct nk_draw_vertex, position);
size_t vt = offsetof(struct nk_draw_vertex, uv);
size_t vc = offsetof(struct nk_draw_vertex, col);
glGenBuffers(1, &dev->vbo);
glGenBuffers(1, &dev->ebo);
glGenVertexArrays(1, &dev->vao);
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glEnableVertexAttribArray((GLuint)dev->attrib_pos);
glEnableVertexAttribArray((GLuint)dev->attrib_uv);
glEnableVertexAttribArray((GLuint)dev->attrib_col);
glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
NK_INTERN void
nk_glfw3_device_upload_atlas(const void *image, int width, int height)
{
struct nk_glfw_device *dev = &glfw.ogl;
glGenTextures(1, &dev->font_tex);
glBindTexture(GL_TEXTURE_2D, dev->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image);
}
NK_API void
nk_glfw3_device_destroy(void)
{
struct nk_glfw_device *dev = &glfw.ogl;
glDetachShader(dev->prog, dev->vert_shdr);
glDetachShader(dev->prog, dev->frag_shdr);
glDeleteShader(dev->vert_shdr);
glDeleteShader(dev->frag_shdr);
glDeleteProgram(dev->prog);
glDeleteTextures(1, &dev->font_tex);
glDeleteBuffers(1, &dev->vbo);
glDeleteBuffers(1, &dev->ebo);
nk_buffer_free(&dev->cmds);
}
NK_API void
nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
{
struct nk_glfw_device *dev = &glfw.ogl;
int width, height;
GLint last_prog, last_tex;
GLint last_ebo, last_vbo, last_vao;
GLfloat ortho[4][4] = {
{2.0f, 0.0f, 0.0f, 0.0f},
{0.0f,-2.0f, 0.0f, 0.0f},
{0.0f, 0.0f,-1.0f, 0.0f},
{-1.0f,1.0f, 0.0f, 1.0f},
};
glfwGetWindowSize(glfw.win, &width, &height);
ortho[0][0] /= (GLfloat)width;
ortho[1][1] /= (GLfloat)height;
/* save previous opengl state */
glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
/* setup global state */
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
/* setup program */
glUseProgram(dev->prog);
glUniform1i(dev->uniform_tex, 0);
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
{
/* convert from command queue into draw list and draw to screen */
const struct nk_draw_command *cmd;
void *vertices, *elements;
const nk_draw_index *offset = NULL;
/* allocate vertex and element buffer */
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
/* load draw vertices & elements directly into vertex + element buffer */
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
{
/* fill converting configuration */
struct nk_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.curve_segment_count = 22;
config.arc_segment_count = 22;
config.null = dev->null;
/* setup buffers to load vertices and elements */
{struct nk_buffer vbuf, ebuf;
nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);
nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);
nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);}
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
/* iterate over and execute each draw command */
nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) {
if (!cmd->elem_count) continue;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)cmd->clip_rect.x,
height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
(GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
nk_clear(&glfw.ctx);
}
/* restore old state */
glUseProgram((GLuint)last_prog);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
glBindVertexArray((GLuint)last_vao);
glDisable(GL_SCISSOR_TEST);
}
NK_API void
nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint)
{
(void)win;
if (glfw.text_len < NK_GLFW_TEXT_MAX)
glfw.text[glfw.text_len++] = codepoint;
}
NK_API void
nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)
{
(void)win; (void)xoff;
glfw.scroll += (float)yoff;
}
static void
nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
{
const char *text = glfwGetClipboardString(glfw.win);
if (text) nk_textedit_paste(edit, text, nk_strlen(text));
(void)usr;
}
static void
nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len)
{
char *str = 0;
(void)usr;
if (!len) return;
str = malloc((size_t)len+1);
if (!str) return;
memcpy(str, text, (size_t)len);
str[len] = '\0';
glfwSetClipboardString(glfw.win, str);
free(str);
}
NK_API struct nk_context*
nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state)
{
glfw.win = win;
if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {
glfwSetScrollCallback(win, nk_gflw3_scroll_callback);
glfwSetCharCallback(win, nk_glfw3_char_callback);
}
nk_init_default(&glfw.ctx, 0);
glfw.ctx.clip.copy = nk_glfw3_clipbard_copy;
glfw.ctx.clip.paste = nk_glfw3_clipbard_paste;
glfw.ctx.clip.userdata = nk_handle_ptr(0);
nk_glfw3_device_create();
return &glfw.ctx;
}
NK_API void
nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas)
{
nk_font_atlas_init_default(&glfw.atlas);
nk_font_atlas_begin(&glfw.atlas);
*atlas = &glfw.atlas;
}
NK_API void
nk_glfw3_font_stash_end(void)
{
const void *image; int w, h;
image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
nk_glfw3_device_upload_atlas(image, w, h);
nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null);
if (glfw.atlas.default_font)
nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle);
}
NK_API void
nk_glfw3_new_frame(void)
{
int i;
double x, y;
struct nk_context *ctx = &glfw.ctx;
struct GLFWwindow *win = glfw.win;
nk_input_begin(ctx);
for (i = 0; i < glfw.text_len; ++i)
nk_input_unicode(ctx, glfw.text[i]);
nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS||
glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) {
nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
} else {
nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
nk_input_key(ctx, NK_KEY_COPY, 0);
nk_input_key(ctx, NK_KEY_PASTE, 0);
nk_input_key(ctx, NK_KEY_CUT, 0);
nk_input_key(ctx, NK_KEY_SHIFT, 0);
}
glfwGetCursorPos(win, &x, &y);
nk_input_motion(ctx, (int)x, (int)y);
nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
nk_input_scroll(ctx, glfw.scroll);
nk_input_end(&glfw.ctx);
glfw.text_len = 0;
glfw.scroll = 0;
}
NK_API
void nk_glfw3_shutdown(void)
{
nk_font_atlas_clear(&glfw.atlas);
nk_free(&glfw.ctx);
nk_glfw3_device_destroy();
}

23
demo/glfw/nuklear_glfw.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef NK_GLFW_H_
#define NK_GLFW_H_
#include "../../nuklear.h"
#include <GLFW/glfw3.h>
enum nk_glfw_init_state{NK_GLFW3_DEFAULT=0, NK_GLFW3_INSTALL_CALLBACKS};
NK_API struct nk_context *nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state);
NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas);
NK_API void nk_glfw3_font_stash_end(void);
NK_API void nk_glfw3_new_frame(void);
NK_API void nk_glfw3_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);
NK_API void nk_glfw3_shutdown(void);
NK_API void nk_glfw3_device_destroy(void);
NK_API void nk_glfw3_device_create(void);
NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);
NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);
#endif

View File

@ -1,26 +0,0 @@
# Install
BIN = zahnrad
# Compiler
CC = clang
DCC = gcc
# Flags
CFLAGS = -std=c99 -pedantic -O2
SRC = linuxgl.c ../../zahnrad.c
OBJ = $(SRC:.c=.o)
# Modes
.PHONY: gcc
gcc: CC = gcc
gcc: $(BIN)
.PHONY: clang
clang: CC = clang
clang: $(BIN)
$(BIN):
@mkdir -p bin
rm -f bin/$(BIN) $(OBJS)
$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) -lX11 -lm -lGL -lm -lGLU

View File

@ -1,963 +0,0 @@
/*
Copyright (c) 2016 Micha Mettke
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glext.h>
#include <GL/glxext.h>
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#include "../../zahnrad.h"
#include "../demo.c"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wfloat-equal"
#pragma clang diagnostic ignored "-Wbad-function-cast"
#pragma clang diagnostic ignored "-Wcast-qual"
#pragma clang diagnostic ignored "-Wshadow"
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
#pragma clang diagnostic ignored "-Wdeclaration-after-statement"
#pragma clang diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wbad-function-cast"
#pragma GCC diagnostic ignored "-Wcast-qual"
#pragma GCC diagnostic ignored "-Wshadow"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
#pragma GCC diagnostic ignored "-Wtype-limits"
#pragma GCC diagnostic ignored "-Wswitch-default"
#pragma GCC diagnostic ignored "-Wunused-function"
#elif _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4456)
#endif
#define STB_IMAGE_IMPLEMENTATION
#include "../stb_image.h"
#ifdef __clang__
#pragma clang diagnostic pop
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic pop
#elif _MSC_VER
#pragma warning (pop)
#endif
/* prefered OpenGL version */
#define OGL_MAJOR_VERSION 3
#define OGL_MINOR_VERSION 0
#define MAX_VERTEX_MEMORY 512 * 1024
#define MAX_ELEMENT_MEMORY 128 * 1024
#define UNUSED(a) ((void)(a))
typedef GLXContext(*glxCreateContext)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
/* GL_ARB_vertex_buffer_object */
typedef void(*qglGenBuffers)(GLsizei, GLuint*);
typedef void(*qglBindBuffer)(GLenum, GLuint);
typedef void(*qglBufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum);
typedef void(*qglBufferSubData)(GLenum, GLintptr, GLsizeiptr, const GLvoid*);
typedef void*(*qglMapBuffer)(GLenum, GLenum);
typedef GLboolean(*qglUnmapBuffer)(GLenum);
typedef void(*qglDeleteBuffers)(GLsizei, GLuint*);
/* GL_ARB_vertex_array_object */
typedef void (*qglGenVertexArrays)(GLsizei, GLuint*);
typedef void (*qglBindVertexArray)(GLuint);
typedef void (*qglDeleteVertexArrays)(GLsizei, const GLuint*);
/* GL_ARB_vertex_program / GL_ARB_fragment_program */
typedef void(*qglVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*);
typedef void(*qglEnableVertexAttribArray)(GLuint);
typedef void(*qglDisableVertexAttribArray)(GLuint);
/* GL_ARB_framebuffer_object */
typedef void(*qglGenerateMipmap)(GLenum target);
/* GLSL/OpenGL 2.0 core */
typedef GLuint(*qglCreateShader)(GLenum);
typedef void(*qglShaderSource)(GLuint, GLsizei, const GLchar**, const GLint*);
typedef void(*qglCompileShader)(GLuint);
typedef void(*qglGetShaderiv)(GLuint, GLenum, GLint*);
typedef void(*qglGetShaderInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);
typedef void(*qglDeleteShader)(GLuint);
typedef GLuint(*qglCreateProgram)(void);
typedef void(*qglAttachShader)(GLuint, GLuint);
typedef void(*qglDetachShader)(GLuint, GLuint);
typedef void(*qglLinkProgram)(GLuint);
typedef void(*qglUseProgram)(GLuint);
typedef void(*qglGetProgramiv)(GLuint, GLenum, GLint*);
typedef void(*qglGetProgramInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);
typedef void(*qglDeleteProgram)(GLuint);
typedef GLint(*qglGetUniformLocation)(GLuint, const GLchar*);
typedef GLint(*qglGetAttribLocation)(GLuint, const GLchar*);
typedef void(*qglUniform1i)(GLint, GLint);
typedef void(*qglUniform1f)(GLint, GLfloat);
typedef void(*qglUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat*);
typedef void(*qglUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat*);
static qglGenBuffers glGenBuffers;
static qglBindBuffer glBindBuffer;
static qglBufferData glBufferData;
static qglBufferSubData glBufferSubData;
static qglMapBuffer glMapBuffer;
static qglUnmapBuffer glUnmapBuffer;
static qglDeleteBuffers glDeleteBuffers;
static qglGenVertexArrays glGenVertexArrays;
static qglBindVertexArray glBindVertexArray;
static qglDeleteVertexArrays glDeleteVertexArrays;
static qglVertexAttribPointer glVertexAttribPointer;
static qglEnableVertexAttribArray glEnableVertexAttribArray;
static qglDisableVertexAttribArray glDisableVertexAttribArray;
static qglGenerateMipmap glGenerateMipmap;
static qglCreateShader glCreateShader;
static qglShaderSource glShaderSource;
static qglCompileShader glCompileShader;
static qglGetShaderiv glGetShaderiv;
static qglGetShaderInfoLog glGetShaderInfoLog;
static qglDeleteShader glDeleteShader;
static qglCreateProgram glCreateProgram;
static qglAttachShader glAttachShader;
static qglDetachShader glDetachShader;
static qglLinkProgram glLinkProgram;
static qglUseProgram glUseProgram;
static qglGetProgramiv glGetProgramiv;
static qglGetProgramInfoLog glGetProgramInfoLog;
static qglDeleteProgram glDeleteProgram;
static qglGetUniformLocation glGetUniformLocation;
static qglGetAttribLocation glGetAttribLocation;
static qglUniform1i glUniform1i;
static qglUniform1f glUniform1f;
static qglUniformMatrix3fv glUniformMatrix3fv;
static qglUniformMatrix4fv glUniformMatrix4fv;
enum graphics_card_vendors {
VENDOR_UNKNOWN,
VENDOR_NVIDIA,
VENDOR_AMD,
VENDOR_INTEL
};
struct opengl {
/* context */
GLXContext ctx;
glxCreateContext create_context;
/* info */
const char *vendor_str;
const char *version_str;
const char *extensions_str;
const char *renderer_str;
const char *glsl_version_str;
enum graphics_card_vendors vendor;
/* version */
float version;
int major_version;
int minor_version;
/* extensions */
int glsl_available;
int vertex_buffer_obj_available;
int vertex_array_obj_available;
int map_buffer_range_available;
int fragment_program_available;
int frame_buffer_object_available;
};
struct device {
GLuint vbo, vao, ebo;
GLuint prog;
GLuint vert_shdr;
GLuint frag_shdr;
GLint attrib_pos;
GLint attrib_uv;
GLint attrib_col;
GLint uniform_tex;
GLint uniform_proj;
GLuint font_tex;
struct zr_draw_null_texture null;
struct zr_buffer cmds;
};
struct XWindow {
Display *dpy;
Window win;
XVisualInfo *vis;
Colormap cmap;
XSetWindowAttributes swa;
XWindowAttributes attr;
GLXFBConfig fbc;
int width, height;
};
static int gl_err = FALSE;
static void
die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputs("\n", stderr);
exit(EXIT_FAILURE);
}
static struct zr_image
icon_load(const char *filename)
{
int x,y,n;
GLuint tex;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
if (!data) die("[SDL]: failed to load image: %s", filename);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
return zr_image_id((int)tex);
}
static int
gl_check_extension(struct opengl *GL, const char *ext)
{
const char *start, *where, *term;
where = strchr(ext, ' ');
if (where || *ext == '\0')
return FALSE;
for (start = GL->extensions_str;;) {
where = strstr((const char*)start, ext);
if (!where) break;
term = where + strlen(ext);
if (where == start || *(where - 1) == ' ') {
if (*term == ' ' || *term == '\0')
return TRUE;
}
start = term;
}
return FALSE;
}
#define GL_EXT(name) (q##name)gl_ext(#name)
static __GLXextFuncPtr
gl_ext(const char *name)
{
__GLXextFuncPtr func;
func = glXGetProcAddress((const GLubyte*)name);
if (!func) {
fprintf(stdout, "[GL]: failed to load extension: %s", name);
return NULL;
}
return func;
}
static int
gl_error_handler(Display *dpy, XErrorEvent *ev)
{
UNUSED((dpy, ev));
gl_err = TRUE;
return 0;
}
static int
stricmpn(const char *a, const char *b, int len)
{
int i = 0;
for (i = 0; i < len && a[i] && b[i]; ++i)
if (a[i] != b[i]) return 1;
if (i != len) return 1;
return 0;
}
static void
device_init(struct device *dev)
{
GLint status;
static const GLchar *vertex_shader =
"#version 300 es\n"
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main() {\n"
" Frag_UV = TexCoord;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
static const GLchar *fragment_shader =
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
dev->prog = glCreateProgram();
dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
glCompileShader(dev->vert_shdr);
glCompileShader(dev->frag_shdr);
glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glAttachShader(dev->prog, dev->vert_shdr);
glAttachShader(dev->prog, dev->frag_shdr);
glLinkProgram(dev->prog);
glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
assert(status == GL_TRUE);
dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
{
/* buffer setup */
GLsizei vs = sizeof(struct zr_draw_vertex);
size_t vp = offsetof(struct zr_draw_vertex, position);
size_t vt = offsetof(struct zr_draw_vertex, uv);
size_t vc = offsetof(struct zr_draw_vertex, col);
glGenBuffers(1, &dev->vbo);
glGenBuffers(1, &dev->ebo);
glGenVertexArrays(1, &dev->vao);
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glEnableVertexAttribArray((GLuint)dev->attrib_pos);
glEnableVertexAttribArray((GLuint)dev->attrib_uv);
glEnableVertexAttribArray((GLuint)dev->attrib_col);
glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
static void
device_upload_atlas(struct device *dev, const void *image, int width, int height)
{
glGenTextures(1, &dev->font_tex);
glBindTexture(GL_TEXTURE_2D, dev->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image);
}
static void
device_shutdown(struct device *dev)
{
glDetachShader(dev->prog, dev->vert_shdr);
glDetachShader(dev->prog, dev->frag_shdr);
glDeleteShader(dev->vert_shdr);
glDeleteShader(dev->frag_shdr);
glDeleteProgram(dev->prog);
glDeleteTextures(1, &dev->font_tex);
glDeleteBuffers(1, &dev->vbo);
glDeleteBuffers(1, &dev->ebo);
glDeleteVertexArrays(1, &dev->vao);
}
static void
device_draw(struct device *dev, struct zr_context *ctx, int width, int height,
enum zr_anti_aliasing AA)
{
GLint last_prog, last_tex;
GLint last_ebo, last_vbo, last_vao;
GLfloat ortho[4][4] = {
{2.0f, 0.0f, 0.0f, 0.0f},
{0.0f,-2.0f, 0.0f, 0.0f},
{0.0f, 0.0f,-1.0f, 0.0f},
{-1.0f,1.0f, 0.0f, 1.0f},
};
ortho[0][0] /= (GLfloat)width;
ortho[1][1] /= (GLfloat)height;
/* save previous opengl state */
glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
/* setup global state */
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
/* setup program */
glUseProgram(dev->prog);
glUniform1i(dev->uniform_tex, 0);
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
{
/* convert from command queue into draw list and draw to screen */
void *vertices, *elements;
const struct zr_draw_command *cmd;
const zr_draw_index *offset = NULL;
/* allocate vertex and element buffer */
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
/* load draw vertices & elements directly into vertex + element buffer */
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
{
struct zr_buffer vbuf, ebuf;
/* fill converting configuration */
struct zr_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.arc_segment_count = 22;
config.curve_segment_count = 22;
config.null = dev->null;
/* setup buffers to load vertices and elements */
zr_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
/* iterate over and execute each draw command */
zr_draw_foreach(cmd, ctx, &dev->cmds) {
if (!cmd->elem_count) continue;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)cmd->clip_rect.x,
height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
(GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
zr_clear(ctx);
}
/* restore old state */
glUseProgram((GLuint)last_prog);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
glBindVertexArray((GLuint)last_vao);
glDisable(GL_SCISSOR_TEST);
}
static void
input_key(struct XWindow *xw, struct zr_context *ctx, XEvent *evt, int down)
{
int ret;
KeySym *code = XGetKeyboardMapping(xw->dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
if (*code == XK_Shift_L || *code == XK_Shift_R)
zr_input_key(ctx, ZR_KEY_SHIFT, down);
else if (*code == XK_Delete)
zr_input_key(ctx, ZR_KEY_DEL, down);
else if (*code == XK_Return)
zr_input_key(ctx, ZR_KEY_ENTER, down);
else if (*code == XK_Tab)
zr_input_key(ctx, ZR_KEY_TAB, down);
else if (*code == XK_space && !down)
zr_input_char(ctx, ' ');
else if (*code == XK_Left)
zr_input_key(ctx, ZR_KEY_LEFT, down);
else if (*code == XK_Right)
zr_input_key(ctx, ZR_KEY_RIGHT, down);
else if (*code == XK_BackSpace)
zr_input_key(ctx, ZR_KEY_BACKSPACE, down);
else if (*code > 32 && *code < 128) {
if (*code == 'c')
zr_input_key(ctx, ZR_KEY_COPY, down && (evt->xkey.state & ControlMask));
else if (*code == 'v')
zr_input_key(ctx, ZR_KEY_PASTE, down && (evt->xkey.state & ControlMask));
else if (*code == 'x')
zr_input_key(ctx, ZR_KEY_CUT, down && (evt->xkey.state & ControlMask));
if (!down)
zr_input_unicode(ctx, (zr_rune)*code);
}
XFree(code);
}
static void
input_motion(struct zr_context *ctx, XEvent *evt)
{
const int x = evt->xmotion.x;
const int y = evt->xmotion.y;
zr_input_motion(ctx, x, y);
}
static void
input_button(struct zr_context *ctx, XEvent *evt, int down)
{
const int x = evt->xbutton.x;
const int y = evt->xbutton.y;
if (evt->xbutton.button == Button1)
zr_input_button(ctx, ZR_BUTTON_LEFT, x, y, down);
else if (evt->xbutton.button == Button2)
zr_input_button(ctx, ZR_BUTTON_MIDDLE, x, y, down);
else if (evt->xbutton.button == Button3)
zr_input_button(ctx, ZR_BUTTON_RIGHT, x, y, down);
else if (evt->xbutton.button == Button4)
zr_input_scroll(ctx, 1.0f);
else if (evt->xbutton.button == Button5)
zr_input_scroll(ctx, -1.0f);
}
int main(int argc, char **argv)
{
int i;
int running = 1;
const char *font_path;
struct opengl gl;
struct device device;
struct demo gui;
struct zr_font *font;
struct zr_font_atlas atlas;
struct XWindow win;
memset(&gl, 0, sizeof(gl));
memset(&win, 0, sizeof(win));
memset(&gui, 0, sizeof(gui));
font_path = (argc > 1) ? argv[1]: 0;
win.dpy = XOpenDisplay(NULL);
if (!win.dpy) die("Failed to open X display\n");
{
/* check glx version */
int glx_major, glx_minor;
if (!glXQueryVersion(win.dpy, &glx_major, &glx_minor))
die("[X11]: Error: Failed to query OpenGL version\n");
if ((glx_major == 1 && glx_minor < 3) || (glx_major < 1))
die("[X11]: Error: Invalid GLX version!\n");
fprintf(stdout, "[X11]: OpenGL version %d.%d\n", glx_major, glx_minor);
}
{
/* find and pick matching framebuffer visual */
int fb_count;
static GLint attr[] = {
GLX_X_RENDERABLE, True,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_STENCIL_SIZE, 8,
GLX_DOUBLEBUFFER, True,
None
};
GLXFBConfig *fbc;
fprintf(stdout, "[X11]: Query matching framebuffer configurations\n");
fbc = glXChooseFBConfig(win.dpy, DefaultScreen(win.dpy), attr, &fb_count);
if (!fbc) die("[X11]: Error: failed to retrieve framebuffer configuration\n");
fprintf(stdout, "[X11]: Found %d matching framebuffer configurations\n", fb_count);
{
/* pick framebuffer with most samples per pixel */
int fb_best = -1, best_num_samples = -1;
for (i = 0; i < fb_count; ++i) {
XVisualInfo *vi = glXGetVisualFromFBConfig(win.dpy, fbc[i]);
if (vi) {
int sample_buffer, samples;
glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLE_BUFFERS, &sample_buffer);
glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLES, &samples);
fprintf(stdout, "\tFramebuffer Config %d: Visual ID 0x%2x: "
"(SAMPLE_BUFFER: %d, SAMPLES: %d)\n", i, (unsigned int)vi->visualid,
sample_buffer, samples);
if ((fb_best < 0) || (sample_buffer && samples > best_num_samples))
fb_best = i; best_num_samples = samples;
}
}
win.fbc = fbc[fb_best];
XFree(fbc);
win.vis = glXGetVisualFromFBConfig(win.dpy, win.fbc);
fprintf(stdout, "[X11]: Chosen visual id: 0x%x\n", (unsigned)win.vis->visualid);
}
}
{
/* create window */
fprintf(stdout, "[X11]: Creating colormap\n");
win.cmap = XCreateColormap(win.dpy, RootWindow(win.dpy, win.vis->screen), win.vis->visual, AllocNone);
win.swa.colormap = win.cmap;
win.swa.background_pixmap = None;
win.swa.border_pixel = 0;
win.swa.event_mask =
ExposureMask | KeyPressMask | KeyReleaseMask |
ButtonPress | ButtonReleaseMask| ButtonMotionMask |
Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|
PointerMotionMask| StructureNotifyMask;
fprintf(stdout, "[X11]: Creating window\n");
win.win = XCreateWindow(win.dpy, RootWindow(win.dpy, win.vis->screen), 0, 0,
WINDOW_WIDTH, WINDOW_HEIGHT, 0, win.vis->depth, InputOutput,
win.vis->visual, CWBorderPixel|CWColormap|CWEventMask, &win.swa);
if (!win.win) die("[X11]: Failed to create window\n");
XFree(win.vis);
XStoreName(win.dpy, win.win, "Zahnrad");
fprintf(stdout, "[X11]: Mapping window\n");
XMapWindow(win.dpy, win.win);
}
{
/* create opengl context */
int(*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(gl_error_handler);
gl.extensions_str = glXQueryExtensionsString(win.dpy, DefaultScreen(win.dpy));
gl.create_context = (glxCreateContext)
glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
gl_err = FALSE;
if (!gl_check_extension(&gl, "GLX_ARB_create_context") || !gl.create_context) {
fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n");
fprintf(stdout, "[X11]: ... using old-style GLX context\n");
gl.ctx = glXCreateNewContext(win.dpy, win.fbc, GLX_RGBA_TYPE, 0, True);
} else {
GLint attr[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, OGL_MAJOR_VERSION,
GLX_CONTEXT_MINOR_VERSION_ARB, OGL_MINOR_VERSION,
None
};
fprintf(stdout, "[X11]: Creating Context...\n");
gl.ctx = gl.create_context(win.dpy, win.fbc, 0, True, attr);
XSync(win.dpy, False);
if (gl_err || !gl.ctx) {
/* Could not create GL 3.0 context. Fallback to old 2.x context.
* If a version below 3.0 is requested, implementations will
* return the newest context version compatible with OpenGL
* version less than version 3.0.*/
attr[1] = 1; attr[3] = 0;
gl_err = FALSE;
fprintf(stdout, "[X11] Failed to create OpenGL 3.0 context\n");
fprintf(stdout, "[X11] ... using old-style GLX context!\n");
gl.ctx = gl.create_context(win.dpy, win.fbc, 0, True, attr);
} else fprintf(stdout, "[X11] OpenGL 3.0 Context created\n");
}
XSync(win.dpy, False);
XSetErrorHandler(old_handler);
if (gl_err || !gl.ctx)
die("[X11]: Failed to create an OpenGL context\n");
if (!glXIsDirect(win.dpy, gl.ctx))
fprintf(stdout, "[X11] Optained indirect GLX rendering context\n");
else fprintf(stdout, "[X11] Optained direct GLX rendering context\n");
glXMakeCurrent(win.dpy, win.win, gl.ctx);
}
{
int failed = FALSE;
gl.version_str = (const char*)glGetString(GL_VERSION);
glGetIntegerv(GL_MAJOR_VERSION, &gl.major_version);
glGetIntegerv(GL_MINOR_VERSION, &gl.minor_version);
if (gl.major_version < 2)
die("[GL]: Graphics card does not fullfill minimum OpenGL 2.0 support\n");
gl.version = (float)gl.major_version + (float)gl.minor_version * 0.1f;
gl.renderer_str = (const char*)glGetString(GL_RENDERER);
gl.extensions_str = (const char*)glGetString(GL_EXTENSIONS);
gl.glsl_version_str = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
gl.vendor_str = (const char*)glGetString(GL_VENDOR);
if (!stricmpn(gl.vendor_str, "ATI", 4) ||
!stricmpn(gl.vendor_str, "AMD", 4))
gl.vendor = VENDOR_AMD;
else if (!stricmpn(gl.vendor_str, "NVIDIA", 6))
gl.vendor = VENDOR_NVIDIA;
else if (!stricmpn(gl.vendor_str, "Intel", 5))
gl.vendor = VENDOR_INTEL;
else gl.vendor = VENDOR_UNKNOWN;
fprintf(stdout, "[GL] OpenGL\n");
fprintf(stdout, "\tVersion: %d.%d\n", gl.major_version, gl.minor_version);
fprintf(stdout, "\tVendor: %s\n", gl.vendor_str);
fprintf(stdout, "\tRenderer: %s\n", gl.renderer_str);
fprintf(stdout, "\tGLSL: %s\n\n", gl.glsl_version_str);
/* Extensions */
fprintf(stdout, "[GL] Loading extensions...\n");
gl.glsl_available = (gl.version >= 2.0f);
if (gl.glsl_available) {
/* GLSL core in OpenGL > 2 */
glCreateShader = GL_EXT(glCreateShader);
glShaderSource = GL_EXT(glShaderSource);
glCompileShader = GL_EXT(glCompileShader);
glGetShaderiv = GL_EXT(glGetShaderiv);
glGetShaderInfoLog = GL_EXT(glGetShaderInfoLog);
glDeleteShader = GL_EXT(glDeleteShader);
glCreateProgram = GL_EXT(glCreateProgram);
glAttachShader = GL_EXT(glAttachShader);
glDetachShader = GL_EXT(glDetachShader);
glLinkProgram = GL_EXT(glLinkProgram);
glUseProgram = GL_EXT(glUseProgram);
glGetProgramiv = GL_EXT(glGetProgramiv);
glGetProgramInfoLog = GL_EXT(glGetProgramInfoLog);
glDeleteProgram = GL_EXT(glDeleteProgram);
glGetUniformLocation = GL_EXT(glGetUniformLocation);
glGetAttribLocation = GL_EXT(glGetAttribLocation);
glUniform1i = GL_EXT(glUniform1i);
glUniform1f = GL_EXT(glUniform1f);
glUniformMatrix3fv = GL_EXT(glUniformMatrix3fv);
glUniformMatrix4fv = GL_EXT(glUniformMatrix4fv);
}
gl.vertex_buffer_obj_available = gl_check_extension(&gl, "GL_ARB_vertex_buffer_object");
if (gl.vertex_buffer_obj_available) {
/* GL_ARB_vertex_buffer_object */
glGenBuffers = GL_EXT(glGenBuffers);
glBindBuffer = GL_EXT(glBindBuffer);
glBufferData = GL_EXT(glBufferData);
glBufferSubData = GL_EXT(glBufferSubData);
glMapBuffer = GL_EXT(glMapBuffer);
glUnmapBuffer = GL_EXT(glUnmapBuffer);
glDeleteBuffers = GL_EXT(glDeleteBuffers);
}
gl.fragment_program_available = gl_check_extension(&gl, "GL_ARB_fragment_program");
if (gl.fragment_program_available) {
/* GL_ARB_vertex_program / GL_ARB_fragment_program */
glVertexAttribPointer = GL_EXT(glVertexAttribPointer);
glEnableVertexAttribArray = GL_EXT(glEnableVertexAttribArray);
glDisableVertexAttribArray = GL_EXT(glDisableVertexAttribArray);
}
gl.vertex_array_obj_available = gl_check_extension(&gl, "GL_ARB_vertex_array_object");
if (gl.vertex_array_obj_available) {
/* GL_ARB_vertex_array_object */
glGenVertexArrays = GL_EXT(glGenVertexArrays);
glBindVertexArray = GL_EXT(glBindVertexArray);
glDeleteVertexArrays = GL_EXT(glDeleteVertexArrays);
}
gl.frame_buffer_object_available = gl_check_extension(&gl, "GL_ARB_framebuffer_object");
if (gl.frame_buffer_object_available) {
/* GL_ARB_framebuffer_object */
glGenerateMipmap = GL_EXT(glGenerateMipmap);
}
if (!gl.vertex_buffer_obj_available) {
fprintf(stdout, "[GL] Error: GL_ARB_vertex_buffer_object is not available!\n");
failed = TRUE;
}
if (!gl.fragment_program_available) {
fprintf(stdout, "[GL] Error: GL_ARB_fragment_program is not available!\n");
failed = TRUE;
}
if (!gl.vertex_array_obj_available) {
fprintf(stdout, "[GL] Error: GL_ARB_vertex_array_object is not available!\n");
failed = TRUE;
}
if (!gl.frame_buffer_object_available) {
fprintf(stdout, "[GL] Error: GL_ARB_framebuffer_object is not available!\n");
failed = TRUE;
}
if (failed) goto cleanup;
fprintf(stdout, "[GL] Extensions successfully loaded\n");
}
/* screen */
XGetWindowAttributes(win.dpy, win.win, &win.attr);
win.width = win.attr.width;
win.height = win.attr.height;
device_init(&device);
{
/* Font */
const void *image;
int width, height;
zr_font_atlas_init_default(&atlas);
zr_font_atlas_begin(&atlas);
if (font_path) font = zr_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
else font = zr_font_atlas_add_default(&atlas, 14.0f, NULL);
image = zr_font_atlas_bake(&atlas, &width, &height, ZR_FONT_ATLAS_RGBA32);
device_upload_atlas(&device, image, width, height);
zr_font_atlas_end(&atlas, zr_handle_id((int)device.font_tex), &device.null);
/* GUI */
memset(&gui, 0, sizeof(gui));
zr_buffer_init_default(&device.cmds);
zr_init_default(&gui.ctx, &font->handle);
}
device_init(&device);
glEnable(GL_TEXTURE_2D);
gui.icons.unchecked = icon_load("../../icon/unchecked.png");
gui.icons.checked = icon_load("../../icon/checked.png");
gui.icons.rocket = icon_load("../../icon/rocket.png");
gui.icons.cloud = icon_load("../../icon/cloud.png");
gui.icons.pen = icon_load("../../icon/pen.png");
gui.icons.play = icon_load("../../icon/play.png");
gui.icons.pause = icon_load("../../icon/pause.png");
gui.icons.stop = icon_load("../../icon/stop.png");
gui.icons.next = icon_load("../../icon/next.png");
gui.icons.prev = icon_load("../../icon/prev.png");
gui.icons.tools = icon_load("../../icon/tools.png");
gui.icons.dir = icon_load("../../icon/directory.png");
gui.icons.copy = icon_load("../../icon/copy.png");
gui.icons.convert = icon_load("../../icon/export.png");
gui.icons.del = icon_load("../../icon/delete.png");
gui.icons.edit = icon_load("../../icon/edit.png");
gui.icons.menu[0] = icon_load("../../icon/home.png");
gui.icons.menu[1] = icon_load("../../icon/phone.png");
gui.icons.menu[2] = icon_load("../../icon/plane.png");
gui.icons.menu[3] = icon_load("../../icon/wifi.png");
gui.icons.menu[4] = icon_load("../../icon/settings.png");
gui.icons.menu[5] = icon_load("../../icon/volume.png");
gui.icons.home = icon_load("../../icon/home.png");
gui.icons.directory = icon_load("../../icon/directory.png");
gui.icons.computer = icon_load("../../icon/computer.png");
gui.icons.desktop = icon_load("../../icon/desktop.png");
gui.icons.default_file = icon_load("../../icon/default.png");
gui.icons.text_file = icon_load("../../icon/text.png");
gui.icons.music_file = icon_load("../../icon/music.png");
gui.icons.font_file = icon_load("../../icon/font.png");
gui.icons.img_file = icon_load("../../icon/img.png");
gui.icons.movie_file = icon_load("../../icon/movie.png");
for (i = 0; i < 9; ++i) {
char buffer[256];
sprintf(buffer, "../../images/image%d.png", (i+1));
gui.icons.images[i] = icon_load(buffer);
}
while (running) {
/* input */
XEvent evt;
zr_input_begin(&gui.ctx);
while (XCheckWindowEvent(win.dpy, win.win, win.swa.event_mask, &evt)) {
if (evt.type == KeyPress)
input_key(&win, &gui.ctx, &evt, zr_true);
else if (evt.type == KeyRelease)
input_key(&win, &gui.ctx, &evt, zr_false);
else if (evt.type == ButtonPress)
input_button(&gui.ctx, &evt, zr_true);
else if (evt.type == ButtonRelease)
input_button(&gui.ctx, &evt, zr_false);
else if (evt.type == MotionNotify)
input_motion(&gui.ctx, &evt);
else if (evt.type == Expose || evt.type == ConfigureNotify) {
XGetWindowAttributes(win.dpy, win.win, &win.attr);
win.width = win.attr.width;
win.height = win.attr.height;
}
}
zr_input_end(&gui.ctx);
/* GUI */
XGetWindowAttributes(win.dpy, win.win, &win.attr);
running = run_demo(&gui);
/* Draw */
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
glViewport(0, 0, win.width, win.height);
device_draw(&device, &gui.ctx, win.width, win.height, ZR_ANTI_ALIASING_ON);
glXSwapBuffers(win.dpy, win.win);
}
cleanup:
zr_font_atlas_clear(&atlas);
zr_free(&gui.ctx);
zr_buffer_free(&device.cmds);
device_shutdown(&device);
glDeleteTextures(1,(const GLuint*)&gui.icons.unchecked.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.checked.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.rocket.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.cloud.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.pen.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.play.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.pause.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.stop.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.next.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.prev.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.tools.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.dir.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.del.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.home.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.computer.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.desktop.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.default_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.text_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.music_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.font_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.img_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.movie_file.handle.id);
for (i = 0; i < 9; ++i)
glDeleteTextures(1, (const GLuint*)&gui.icons.images[i].handle.id);
for (i = 0; i < 6; ++i)
glDeleteTextures(1, (const GLuint*)&gui.icons.menu[i].handle.id);
glXMakeCurrent(win.dpy, 0, 0);
glXDestroyContext(win.dpy, gl.ctx);
XUnmapWindow(win.dpy, win.win);
XFreeColormap(win.dpy, win.cmap);
XDestroyWindow(win.dpy, win.win);
XCloseDisplay(win.dpy);
return 0;
}

View File

@ -8,7 +8,7 @@ DCC = gcc
# Flags
CFLAGS = -std=c99 -pedantic -O2
SRC = ../../zahnrad.c sdl.c
SRC = main.c
OBJ = $(SRC:.c=.o)
ifeq ($(OS),Windows_NT)

142
demo/sdl/main.c Normal file
View File

@ -0,0 +1,142 @@
/* nuklear - v1.00 - public domain */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL2/SDL.h>
/* these defines are both needed for the header
* and source file. So if you split them remember
* to copy them as well. */
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#include "nuklear_sdl.h"
#include "nuklear_sdl.c"
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define MAX_VERTEX_MEMORY 512 * 1024
#define MAX_ELEMENT_MEMORY 128 * 1024
int
main(void)
{
/* Platform */
SDL_Window *win;
SDL_GLContext glContext;
struct nk_color background;
int win_width, win_height;
int running = 1;
/* GUI */
struct nk_context *ctx;
/* SDL setup */
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
win = SDL_CreateWindow("Demo",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN);
glContext = SDL_GL_CreateContext(win);
SDL_GetWindowSize(win, &win_width, &win_height);
/* OpenGL setup */
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glewExperimental = 1;
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to setup GLEW\n");
exit(1);
}
ctx = nk_sdl_init(win);
/* Load Fonts: if none of these are loaded a default font will be used */
{struct nk_font_atlas *atlas;
nk_sdl_font_stash_begin(&atlas);
/*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
/*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Robot-Regular.ttf", 14, 0);*/
/*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
/*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
/*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
/*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
nk_sdl_font_stash_end();
/*nk_style_set_font(ctx, &droid->handle)*/;}
background = nk_rgb(28,48,62);
while (running)
{
/* Input */
SDL_Event evt;
nk_input_begin(ctx);
while (SDL_PollEvent(&evt)) {
if (evt.type == SDL_QUIT) goto cleanup;
nk_sdl_handle_event(&evt);
}
nk_input_end(ctx);
/* GUI */
{struct nk_panel layout;
if (nk_begin(ctx, &layout, "Demo", nk_rect(50, 50, 210, 250),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
enum {EASY, HARD};
static int op = EASY;
static int property = 20;
nk_layout_row_static(ctx, 30, 80, 1);
if (nk_button_label(ctx, "button", NK_BUTTON_DEFAULT))
fprintf(stdout, "button pressed\n");
nk_layout_row_dynamic(ctx, 30, 2);
if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
nk_layout_row_dynamic(ctx, 22, 1);
nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
{struct nk_panel combo;
nk_layout_row_dynamic(ctx, 20, 1);
nk_label(ctx, "background:", NK_TEXT_LEFT);
nk_layout_row_dynamic(ctx, 25, 1);
if (nk_combo_begin_color(ctx, &combo, background, 400)) {
nk_layout_row_dynamic(ctx, 120, 1);
background = nk_color_picker(ctx, background, NK_RGBA);
nk_layout_row_dynamic(ctx, 25, 1);
background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
nk_combo_end(ctx);
}}
}
nk_end(ctx);}
/* Draw */
{float bg[4];
nk_color_fv(bg, background);
SDL_GetWindowSize(win, &win_width, &win_height);
glViewport(0, 0, win_width, win_height);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(bg[0], bg[1], bg[2], bg[3]);
nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY);
SDL_GL_SwapWindow(win);}
}
cleanup:
nk_sdl_shutdown();
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}

369
demo/sdl/nuklear_sdl.c Normal file
View File

@ -0,0 +1,369 @@
#include <string.h>
#include <SDL2/SDL.h>
#include "nuklear_sdl.h"
#define NK_IMPLEMENTATION
#include "../../nuklear.h"
struct nk_sdl_device {
struct nk_buffer cmds;
struct nk_draw_null_texture null;
GLuint vbo, vao, ebo;
GLuint prog;
GLuint vert_shdr;
GLuint frag_shdr;
GLint attrib_pos;
GLint attrib_uv;
GLint attrib_col;
GLint uniform_tex;
GLint uniform_proj;
GLuint font_tex;
};
static struct nk_sdl {
SDL_Window *win;
struct nk_sdl_device ogl;
struct nk_context ctx;
struct nk_font_atlas atlas;
} sdl;
NK_API void
nk_sdl_device_create(void)
{
GLint status;
static const GLchar *vertex_shader =
"#version 300 es\n"
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main() {\n"
" Frag_UV = TexCoord;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
static const GLchar *fragment_shader =
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
struct nk_sdl_device *dev = &sdl.ogl;
nk_buffer_init_default(&dev->cmds);
dev->prog = glCreateProgram();
dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
glCompileShader(dev->vert_shdr);
glCompileShader(dev->frag_shdr);
glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glAttachShader(dev->prog, dev->vert_shdr);
glAttachShader(dev->prog, dev->frag_shdr);
glLinkProgram(dev->prog);
glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
assert(status == GL_TRUE);
dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
{
/* buffer setup */
GLsizei vs = sizeof(struct nk_draw_vertex);
size_t vp = offsetof(struct nk_draw_vertex, position);
size_t vt = offsetof(struct nk_draw_vertex, uv);
size_t vc = offsetof(struct nk_draw_vertex, col);
glGenBuffers(1, &dev->vbo);
glGenBuffers(1, &dev->ebo);
glGenVertexArrays(1, &dev->vao);
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glEnableVertexAttribArray((GLuint)dev->attrib_pos);
glEnableVertexAttribArray((GLuint)dev->attrib_uv);
glEnableVertexAttribArray((GLuint)dev->attrib_col);
glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
NK_INTERN void
nk_sdl_device_upload_atlas(const void *image, int width, int height)
{
struct nk_sdl_device *dev = &sdl.ogl;
glGenTextures(1, &dev->font_tex);
glBindTexture(GL_TEXTURE_2D, dev->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image);
}
NK_API void
nk_sdl_device_destroy(void)
{
struct nk_sdl_device *dev = &sdl.ogl;
glDetachShader(dev->prog, dev->vert_shdr);
glDetachShader(dev->prog, dev->frag_shdr);
glDeleteShader(dev->vert_shdr);
glDeleteShader(dev->frag_shdr);
glDeleteProgram(dev->prog);
glDeleteTextures(1, &dev->font_tex);
glDeleteBuffers(1, &dev->vbo);
glDeleteBuffers(1, &dev->ebo);
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;
int width, height;
GLint last_prog, last_tex;
GLint last_ebo, last_vbo, last_vao;
GLfloat ortho[4][4] = {
{2.0f, 0.0f, 0.0f, 0.0f},
{0.0f,-2.0f, 0.0f, 0.0f},
{0.0f, 0.0f,-1.0f, 0.0f},
{-1.0f,1.0f, 0.0f, 1.0f},
};
SDL_GetWindowSize(sdl.win, &width, &height);
ortho[0][0] /= (GLfloat)width;
ortho[1][1] /= (GLfloat)height;
/* save previous opengl state */
glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
/* setup global state */
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
/* setup program */
glUseProgram(dev->prog);
glUniform1i(dev->uniform_tex, 0);
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
{
/* convert from command queue into draw list and draw to screen */
const struct nk_draw_command *cmd;
void *vertices, *elements;
const nk_draw_index *offset = NULL;
/* allocate vertex and element buffer */
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
/* load draw vertices & elements directly into vertex + element buffer */
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
{
/* fill converting configuration */
struct nk_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.curve_segment_count = 22;
config.arc_segment_count = 22;
config.null = dev->null;
/* setup buffers to load vertices and elements */
{struct nk_buffer vbuf, ebuf;
nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);
nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);
nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);}
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
/* iterate over and execute each draw command */
nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {
if (!cmd->elem_count) continue;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)cmd->clip_rect.x,
height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
(GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
nk_clear(&sdl.ctx);
}
/* restore old state */
glUseProgram((GLuint)last_prog);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
glBindVertexArray((GLuint)last_vao);
glDisable(GL_SCISSOR_TEST);
}
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 = 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(SDL_Window *win)
{
sdl.win = win;
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);
nk_sdl_device_upload_atlas(image, w, h);
nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.null);
if (sdl.atlas.default_font)
nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
}
NK_API void
nk_sdl_handle_event(SDL_Event *evt)
{
struct nk_context *ctx = &sdl.ctx;
if (evt->type == SDL_WINDOWEVENT) {
/* handle window resizing */
if (evt->window.event != SDL_WINDOWEVENT_RESIZED) return;
glViewport(0, 0, evt->window.data1, evt->window.data2);
} else 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);
else if (sym == SDLK_END)
nk_input_key(ctx, NK_KEY_TEXT_END, 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_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 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);
} else if (evt->type == SDL_MOUSEMOTION) {
nk_input_motion(ctx, evt->motion.x, evt->motion.y);
} else if (evt->type == SDL_TEXTINPUT) {
nk_glyph glyph;
memcpy(glyph, evt->text.text, NK_UTF_SIZE);
nk_input_glyph(ctx, glyph);
} else if (evt->type == SDL_MOUSEWHEEL) {
nk_input_scroll(ctx,(float)evt->wheel.y);
}
}
NK_API
void nk_sdl_shutdown(void)
{
nk_font_atlas_clear(&sdl.atlas);
nk_free(&sdl.ctx);
nk_sdl_device_destroy();
}

18
demo/sdl/nuklear_sdl.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef NK_SDL_H_
#define NK_SDL_H_
#include "../../nuklear.h"
#include <SDL2/SDL.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 void 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

View File

@ -1,568 +0,0 @@
/*
Copyright (c) 2016 Micha Mettke
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <math.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL2/SDL.h>
/* macros */
#define MAX_VERTEX_MEMORY 512 * 1024
#define MAX_ELEMENT_MEMORY 128 * 1024
#include "../../zahnrad.h"
#include "../demo.c"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wfloat-equal"
#pragma clang diagnostic ignored "-Wbad-function-cast"
#pragma clang diagnostic ignored "-Wcast-qual"
#pragma clang diagnostic ignored "-Wshadow"
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
#pragma clang diagnostic ignored "-Wdeclaration-after-statement"
#pragma clang diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wbad-function-cast"
#pragma GCC diagnostic ignored "-Wcast-qual"
#pragma GCC diagnostic ignored "-Wshadow"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
#pragma GCC diagnostic ignored "-Wtype-limits"
#pragma GCC diagnostic ignored "-Wswitch-default"
#pragma GCC diagnostic ignored "-Wunused-function"
#elif _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4456)
#endif
#define STB_IMAGE_IMPLEMENTATION
#include "../stb_image.h"
#ifdef __clang__
#pragma clang diagnostic pop
#elif defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic pop
#elif _MSC_VER
#pragma warning (pop)
#endif
/* ==============================================================
*
* Utility
*
* ===============================================================*/
static void
die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputs("\n", stderr);
exit(EXIT_FAILURE);
}
static struct zr_image
icon_load(const char *filename)
{
int x,y,n;
GLuint tex;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
if (!data) die("[SDL]: failed to load image: %s", filename);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
return zr_image_id((int)tex);
}
struct device {
GLuint vbo, vao, ebo;
GLuint prog;
GLuint vert_shdr;
GLuint frag_shdr;
GLint attrib_pos;
GLint attrib_uv;
GLint attrib_col;
GLint uniform_tex;
GLint uniform_proj;
GLuint font_tex;
struct zr_draw_null_texture null;
struct zr_buffer cmds;
};
static void
device_init(struct device *dev)
{
GLint status;
static const GLchar *vertex_shader =
"#version 300 es\n"
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main() {\n"
" Frag_UV = TexCoord;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
static const GLchar *fragment_shader =
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
dev->prog = glCreateProgram();
dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
glCompileShader(dev->vert_shdr);
glCompileShader(dev->frag_shdr);
glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glAttachShader(dev->prog, dev->vert_shdr);
glAttachShader(dev->prog, dev->frag_shdr);
glLinkProgram(dev->prog);
glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
assert(status == GL_TRUE);
dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
{
/* buffer setup */
GLsizei vs = sizeof(struct zr_draw_vertex);
size_t vp = offsetof(struct zr_draw_vertex, position);
size_t vt = offsetof(struct zr_draw_vertex, uv);
size_t vc = offsetof(struct zr_draw_vertex, col);
glGenBuffers(1, &dev->vbo);
glGenBuffers(1, &dev->ebo);
glGenVertexArrays(1, &dev->vao);
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glEnableVertexAttribArray((GLuint)dev->attrib_pos);
glEnableVertexAttribArray((GLuint)dev->attrib_uv);
glEnableVertexAttribArray((GLuint)dev->attrib_col);
glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
static void
device_upload_atlas(struct device *dev, const void *image, int width, int height)
{
glGenTextures(1, &dev->font_tex);
glBindTexture(GL_TEXTURE_2D, dev->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image);
}
static void
device_shutdown(struct device *dev)
{
glDetachShader(dev->prog, dev->vert_shdr);
glDetachShader(dev->prog, dev->frag_shdr);
glDeleteShader(dev->vert_shdr);
glDeleteShader(dev->frag_shdr);
glDeleteProgram(dev->prog);
glDeleteTextures(1, &dev->font_tex);
glDeleteBuffers(1, &dev->vbo);
glDeleteBuffers(1, &dev->ebo);
glDeleteVertexArrays(1, &dev->vao);
}
static void
device_draw(struct device *dev, struct zr_context *ctx, int width, int height,
enum zr_anti_aliasing AA)
{
GLint last_prog, last_tex;
GLint last_ebo, last_vbo, last_vao;
GLfloat ortho[4][4] = {
{2.0f, 0.0f, 0.0f, 0.0f},
{0.0f,-2.0f, 0.0f, 0.0f},
{0.0f, 0.0f,-1.0f, 0.0f},
{-1.0f,1.0f, 0.0f, 1.0f},
};
ortho[0][0] /= (GLfloat)width;
ortho[1][1] /= (GLfloat)height;
/* save previous opengl state */
glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
/* setup global state */
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
/* setup program */
glUseProgram(dev->prog);
glUniform1i(dev->uniform_tex, 0);
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
{
/* convert from command queue into draw list and draw to screen */
const struct zr_draw_command *cmd;
void *vertices, *elements;
const zr_draw_index *offset = NULL;
/* allocate vertex and element buffer */
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
/* load draw vertices & elements directly into vertex + element buffer */
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
{
struct zr_buffer vbuf, ebuf;
/* fill converting configuration */
struct zr_convert_config config;
memset(&config, 0, sizeof(config));
config.circle_segment_count = 22;
config.arc_segment_count = 22;
config.curve_segment_count = 22;
config.global_alpha = 1.0f;
config.null = dev->null;
config.shape_AA = AA;
config.line_AA = AA;
/* setup buffers to load vertices and elements */
zr_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
/* iterate over and execute each draw command */
zr_draw_foreach(cmd, ctx, &dev->cmds)
{
if (!cmd->elem_count) continue;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)cmd->clip_rect.x,
height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
(GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
zr_clear(ctx);
}
/* restore old state */
glUseProgram((GLuint)last_prog);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
glBindVertexArray((GLuint)last_vao);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
}
static void
input_key(struct zr_context *ctx, SDL_Event *evt, int down)
{
const Uint8* state = SDL_GetKeyboardState(NULL);
SDL_Keycode sym = evt->key.keysym.sym;
if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT)
zr_input_key(ctx, ZR_KEY_SHIFT, down);
else if (sym == SDLK_DELETE)
zr_input_key(ctx, ZR_KEY_DEL, down);
else if (sym == SDLK_RETURN)
zr_input_key(ctx, ZR_KEY_ENTER, down);
else if (sym == SDLK_TAB)
zr_input_key(ctx, ZR_KEY_TAB, down);
else if (sym == SDLK_BACKSPACE)
zr_input_key(ctx, ZR_KEY_BACKSPACE, down);
else if (sym == SDLK_LEFT)
zr_input_key(ctx, ZR_KEY_LEFT, down);
else if (sym == SDLK_RIGHT)
zr_input_key(ctx, ZR_KEY_RIGHT, down);
else if (sym == SDLK_c)
zr_input_key(ctx, ZR_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]);
else if (sym == SDLK_v)
zr_input_key(ctx, ZR_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]);
else if (sym == SDLK_x)
zr_input_key(ctx, ZR_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]);
}
static void
input_motion(struct zr_context *ctx, SDL_Event *evt)
{
const int x = evt->motion.x;
const int y = evt->motion.y;
zr_input_motion(ctx, x, y);
}
static void
input_button(struct zr_context *ctx, SDL_Event *evt, int down)
{
const int x = evt->button.x;
const int y = evt->button.y;
if (evt->button.button == SDL_BUTTON_LEFT)
zr_input_button(ctx, ZR_BUTTON_LEFT, x, y, down);
if (evt->button.button == SDL_BUTTON_MIDDLE)
zr_input_button(ctx, ZR_BUTTON_MIDDLE, x, y, down);
if (evt->button.button == SDL_BUTTON_RIGHT)
zr_input_button(ctx, ZR_BUTTON_RIGHT, x, y, down);
}
static void
input_text(struct zr_context *ctx, SDL_Event *evt)
{
zr_glyph glyph;
memcpy(glyph, evt->text.text, ZR_UTF_SIZE);
zr_input_glyph(ctx, glyph);
}
static void
resize(SDL_Event *evt)
{
if (evt->window.event != SDL_WINDOWEVENT_RESIZED) return;
glViewport(0, 0, evt->window.data1, evt->window.data2);
}
int
main(int argc, char *argv[])
{
/* Platform */
int i;
const char *font_path;
SDL_Window *win;
SDL_GLContext glContext;
int win_width, win_height;
int running = 1;
/* GUI */
struct device device;
struct demo gui;
struct zr_font *font;
struct zr_font_atlas atlas;
font_path = (argc > 1) ? argv[1]: 0;
/* SDL */
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
win = SDL_CreateWindow("Demo",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN);
glContext = SDL_GL_CreateContext(win);
SDL_GetWindowSize(win, &win_width, &win_height);
/* OpenGL */
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glewExperimental = 1;
if (glewInit() != GLEW_OK)
die("Failed to setup GLEW\n");
device_init(&device);
{
/* Font */
const void *image;
int width, height;
zr_font_atlas_init_default(&atlas);
zr_font_atlas_begin(&atlas);
if (font_path) font = zr_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
else font = zr_font_atlas_add_default(&atlas, 14.0f, NULL);
image = zr_font_atlas_bake(&atlas, &width, &height, ZR_FONT_ATLAS_RGBA32);
device_upload_atlas(&device, image, width, height);
zr_font_atlas_end(&atlas, zr_handle_id((int)device.font_tex), &device.null);
/* GUI */
memset(&gui, 0, sizeof(gui));
zr_buffer_init_default(&device.cmds);
zr_init_default(&gui.ctx, &font->handle);
}
/* icons */
glEnable(GL_TEXTURE_2D);
gui.icons.unchecked = icon_load("../../icon/unchecked.png");
gui.icons.checked = icon_load("../../icon/checked.png");
gui.icons.rocket = icon_load("../../icon/rocket.png");
gui.icons.cloud = icon_load("../../icon/cloud.png");
gui.icons.pen = icon_load("../../icon/pen.png");
gui.icons.play = icon_load("../../icon/play.png");
gui.icons.pause = icon_load("../../icon/pause.png");
gui.icons.stop = icon_load("../../icon/stop.png");
gui.icons.next = icon_load("../../icon/next.png");
gui.icons.prev = icon_load("../../icon/prev.png");
gui.icons.tools = icon_load("../../icon/tools.png");
gui.icons.dir = icon_load("../../icon/directory.png");
gui.icons.copy = icon_load("../../icon/copy.png");
gui.icons.convert = icon_load("../../icon/export.png");
gui.icons.del = icon_load("../../icon/delete.png");
gui.icons.edit = icon_load("../../icon/edit.png");
gui.icons.menu[0] = icon_load("../../icon/home.png");
gui.icons.menu[1] = icon_load("../../icon/phone.png");
gui.icons.menu[2] = icon_load("../../icon/plane.png");
gui.icons.menu[3] = icon_load("../../icon/wifi.png");
gui.icons.menu[4] = icon_load("../../icon/settings.png");
gui.icons.menu[5] = icon_load("../../icon/volume.png");
gui.icons.home = icon_load("../../icon/home.png");
gui.icons.directory = icon_load("../../icon/directory.png");
gui.icons.computer = icon_load("../../icon/computer.png");
gui.icons.desktop = icon_load("../../icon/desktop.png");
gui.icons.default_file = icon_load("../../icon/default.png");
gui.icons.text_file = icon_load("../../icon/text.png");
gui.icons.music_file = icon_load("../../icon/music.png");
gui.icons.font_file = icon_load("../../icon/font.png");
gui.icons.img_file = icon_load("../../icon/img.png");
gui.icons.movie_file = icon_load("../../icon/movie.png");
for (i = 0; i < 9; ++i) {
char buffer[256];
sprintf(buffer, "../../images/image%d.png", (i+1));
gui.icons.images[i] = icon_load(buffer);
}
while (running) {
/* Input */
SDL_Event evt;
zr_input_begin(&gui.ctx);
while (SDL_PollEvent(&evt)) {
if (evt.type == SDL_WINDOWEVENT) resize(&evt);
else if (evt.type == SDL_QUIT) goto cleanup;
else if (evt.type == SDL_KEYUP)
input_key(&gui.ctx, &evt, zr_false);
else if (evt.type == SDL_KEYDOWN)
input_key(&gui.ctx, &evt, zr_true);
else if (evt.type == SDL_MOUSEBUTTONDOWN)
input_button(&gui.ctx, &evt, zr_true);
else if (evt.type == SDL_MOUSEBUTTONUP)
input_button(&gui.ctx, &evt, zr_false);
else if (evt.type == SDL_MOUSEMOTION)
input_motion(&gui.ctx, &evt);
else if (evt.type == SDL_TEXTINPUT)
input_text(&gui.ctx, &evt);
else if (evt.type == SDL_MOUSEWHEEL)
zr_input_scroll(&gui.ctx,(float)evt.wheel.y);
}
zr_input_end(&gui.ctx);
/* GUI */
SDL_GetWindowSize(win, &win_width, &win_height);
running = run_demo(&gui);
/* Draw */
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
device_draw(&device, &gui.ctx, win_width, win_height, ZR_ANTI_ALIASING_ON);
SDL_GL_SwapWindow(win);
}
cleanup:
/* Cleanup */
glDeleteTextures(1,(const GLuint*)&gui.icons.unchecked.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.checked.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.rocket.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.cloud.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.pen.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.play.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.pause.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.stop.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.next.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.prev.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.tools.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.dir.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.del.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.home.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.computer.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.desktop.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.default_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.text_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.music_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.font_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.img_file.handle.id);
glDeleteTextures(1,(const GLuint*)&gui.icons.movie_file.handle.id);
for (i = 0; i < 9; ++i)
glDeleteTextures(1, (const GLuint*)&gui.icons.images[i].handle.id);
for (i = 0; i < 6; ++i)
glDeleteTextures(1, (const GLuint*)&gui.icons.menu[i].handle.id);
zr_free(&gui.ctx);
zr_font_atlas_clear(&atlas);
zr_buffer_free(&device.cmds);
device_shutdown(&device);
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}

View File

@ -8,7 +8,7 @@ DCC = gcc
# Flags
CFLAGS = -std=c89 -pedantic -O2
SRC = xlib.c ../../zahnrad.c
SRC = main.c
OBJ = $(SRC:.c=.o)
# Modes

167
demo/x11/main.c Normal file
View File

@ -0,0 +1,167 @@
/* nuklear - v1.00 - public domain */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#define DTIME 20
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#include "nuklear_xlib.h"
#include "nuklear_xlib.c"
typedef struct XWindow XWindow;
struct XWindow {
Display *dpy;
Window root;
Visual *vis;
Colormap cmap;
XWindowAttributes attr;
XSetWindowAttributes swa;
Window win;
int screen;
XFont *font;
unsigned int width;
unsigned int height;
};
static void
die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputs("\n", stderr);
exit(EXIT_FAILURE);
}
static void*
xcalloc(size_t siz, size_t n)
{
void *ptr = calloc(siz, n);
if (!ptr) die("Out of memory\n");
return ptr;
}
static long
timestamp(void)
{
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0) return 0;
return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
}
static void
sleep_for(long t)
{
struct timespec req;
const time_t sec = (int)(t/1000);
const long ms = t - (sec * 1000);
req.tv_sec = sec;
req.tv_nsec = ms * 1000000L;
while(-1 == nanosleep(&req, &req));
}
int
main(void)
{
long dt;
long started;
int running = 1;
XWindow xw;
struct nk_context *ctx;
/* X11 */
memset(&xw, 0, sizeof xw);
xw.dpy = XOpenDisplay(NULL);
xw.root = DefaultRootWindow(xw.dpy);
xw.screen = XDefaultScreen(xw.dpy);
xw.vis = XDefaultVisual(xw.dpy, xw.screen);
xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone);
xw.swa.colormap = xw.cmap;
xw.swa.event_mask =
ExposureMask | KeyPressMask | KeyReleaseMask |
ButtonPress | ButtonReleaseMask| ButtonMotionMask |
Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|
PointerMotionMask | KeymapStateMask;
xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0,
XDefaultDepth(xw.dpy, xw.screen), InputOutput,
xw.vis, CWEventMask | CWColormap, &xw.swa);
XStoreName(xw.dpy, xw.win, "X11");
XMapWindow(xw.dpy, xw.win);
XGetWindowAttributes(xw.dpy, xw.win, &xw.attr);
xw.width = (unsigned int)xw.attr.width;
xw.height = (unsigned int)xw.attr.height;
/* GUI */
xw.font = nk_xfont_create(xw.dpy, "fixed");
ctx = nk_xlib_init(xw.font, xw.dpy, xw.screen, xw.win, xw.width, xw.height);
while (running)
{
/* Input */
XEvent evt;
started = timestamp();
nk_input_begin(ctx);
while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &evt)){
if (XFilterEvent(&evt, xw.win)) continue;
nk_xlib_handle_event(xw.dpy, xw.screen, xw.win, &evt);
}
nk_input_end(ctx);
/* GUI */
{struct nk_panel layout;
if (nk_begin(ctx, &layout, "Demo", nk_rect(50, 50, 200, 300),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
enum {EASY, HARD};
static int op = EASY;
static int property = 20;
nk_layout_row_static(ctx, 30, 80, 1);
if (nk_button_label(ctx, "button", NK_BUTTON_DEFAULT))
fprintf(stdout, "button pressed\n");
nk_layout_row_dynamic(ctx, 30, 2);
if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
nk_layout_row_dynamic(ctx, 22, 1);
nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
nk_layout_row_dynamic(ctx, 100, 1);
}
nk_end(ctx);}
if (nk_window_is_closed(ctx, "Demo")) break;
/* Draw */
XClearWindow(xw.dpy, xw.win);
nk_xlib_render(xw.win, nk_rgb(30,30,30));
XFlush(xw.dpy);
/* Timing */
dt = timestamp() - started;
if (dt < DTIME)
sleep_for(DTIME - dt);
}
nk_xfont_del(xw.dpy, xw.font);
nk_xlib_shutdown();
XUnmapWindow(xw.dpy, xw.win);
XFreeColormap(xw.dpy, xw.cmap);
XDestroyWindow(xw.dpy, xw.win);
XCloseDisplay(xw.dpy);
return 0;
}

611
demo/x11/nuklear_xlib.c Normal file
View File

@ -0,0 +1,611 @@
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/Xlocale.h>
#define NK_IMPLEMENTATION
#include "nuklear_xlib.h"
#include "../../nuklear.h"
typedef struct XSurface XSurface;
struct XFont {
int ascent;
int descent;
int height;
XFontSet set;
XFontStruct *xfont;
};
struct XSurface {
GC gc;
Display *dpy;
int screen;
Window root;
Drawable drawable;
unsigned int w, h;
};
static struct {
struct nk_context ctx;
struct XSurface *surf;
} xlib;
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) ((a) < (b) ? (b) : (a))
#endif
static unsigned long
color_from_byte(const nk_byte *c)
{
unsigned long res = 0;
res |= (unsigned long)c[0] << 16;
res |= (unsigned long)c[1] << 8;
res |= (unsigned long)c[2] << 0;
return (res);
}
static XSurface*
nk_xsurf_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
{
XSurface *surface = (XSurface*)calloc(1, sizeof(XSurface));
surface->w = w;
surface->h = h;
surface->dpy = dpy;
surface->screen = screen;
surface->root = root;
surface->gc = XCreateGC(dpy, root, 0, NULL);
XSetLineAttributes(dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter);
surface->drawable = XCreatePixmap(dpy, root, w, h, 32);
return surface;
}
static void
nk_xsurf_resize(XSurface *surf, unsigned int w, unsigned int h)
{
if(!surf) return;
if (surf->w == w && surf->h == h) return;
surf->w = w; surf->h = h;
if(surf->drawable) XFreePixmap(surf->dpy, surf->drawable);
surf->drawable = XCreatePixmap(surf->dpy, surf->root, w, h,
(unsigned int)DefaultDepth(surf->dpy, surf->screen));
}
static void
nk_xsurf_scissor(XSurface *surf, float x, float y, float w, float h)
{
XRectangle clip_rect;
clip_rect.x = (short)(x-1);
clip_rect.y = (short)(y-1);
clip_rect.width = (unsigned short)(w+2);
clip_rect.height = (unsigned short)(h+2);
XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted);
}
static void
nk_xsurf_stroke_line(XSurface *surf, short x0, short y0, short x1,
short y1, unsigned int line_thickness, struct nk_color col)
{
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
XDrawLine(surf->dpy, surf->drawable, surf->gc, (int)x0, (int)y0, (int)x1, (int)y1);
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
nk_xsurf_stroke_rect(XSurface* surf, short x, short y, unsigned short w,
unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)
{
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
if (r == 0) {
XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
} else {
short xc = x + r;
short yc = y + r;
short wc = (short)(w - 2 * r);
short hc = (short)(h - 2 * r);
XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y, xc+wc, y);
XDrawLine(surf->dpy, surf->drawable, surf->gc, x+w, yc, x+w, yc+wc);
XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h);
XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, yc+hc, x);
XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
(unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
(unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
(unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
(unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
}
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
nk_xsurf_fill_rect(XSurface* surf, short x, short y, unsigned short w,
unsigned short h, unsigned short r, struct nk_color col)
{
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
if (r == 0) {
XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
} else {
short xc = x + r;
short yc = y + r;
short wc = (short)(w - 2 * r);
short hc = (short)(h - 2 * r);
XPoint pnts[12];
pnts[0].x = x;
pnts[0].y = yc;
pnts[1].x = xc;
pnts[1].y = yc;
pnts[2].x = xc;
pnts[2].y = y;
pnts[3].x = xc + wc;
pnts[3].y = y;
pnts[4].x = xc + wc;
pnts[4].y = yc;
pnts[5].x = x + w;
pnts[5].y = yc;
pnts[6].x = x + w;
pnts[6].y = yc + hc;
pnts[7].x = xc + wc;
pnts[7].y = yc + hc;
pnts[8].x = xc + wc;
pnts[8].y = y + h;
pnts[9].x = xc;
pnts[9].y = y + h;
pnts[10].x = xc;
pnts[10].y = yc + hc;
pnts[11].x = x;
pnts[11].y = yc + hc;
XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 12, Convex, CoordModeOrigin);
XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
(unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
(unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
(unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
(unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
}
}
static void
nk_xsurf_fill_triangle(XSurface *surf, short x0, short y0, short x1,
short y1, short x2, short y2, struct nk_color col)
{
XPoint pnts[3];
unsigned long c = color_from_byte(&col.r);
pnts[0].x = (short)x0;
pnts[0].y = (short)y0;
pnts[1].x = (short)x1;
pnts[1].y = (short)y1;
pnts[2].x = (short)x2;
pnts[2].y = (short)y2;
XSetForeground(surf->dpy, surf->gc, c);
XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin);
}
static void
nk_xsurf_stroke_triangle(XSurface *surf, short x0, short y0, short x1,
short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)
{
XPoint pnts[3];
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
XDrawLine(surf->dpy, surf->drawable, surf->gc, x0, y0, x1, y1);
XDrawLine(surf->dpy, surf->drawable, surf->gc, x1, y1, x2, y2);
XDrawLine(surf->dpy, surf->drawable, surf->gc, x2, y2, x0, y0);
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
nk_xsurf_fill_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count,
struct nk_color col)
{
int i = 0;
#define MAX_POINTS 64
XPoint xpnts[MAX_POINTS];
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
for (i = 0; i < count && i < MAX_POINTS; ++i) {
xpnts[i].x = pnts[i].x;
xpnts[i].y = pnts[i].y;
}
XFillPolygon(surf->dpy, surf->drawable, surf->gc, xpnts, count, Convex, CoordModeOrigin);
#undef MAX_POINTS
}
static void
nk_xsurf_stroke_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count,
unsigned short line_thickness, struct nk_color col)
{
int i = 0;
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
for (i = 1; i < count; ++i)
XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y);
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
nk_xsurf_stroke_polyline(XSurface *surf, const struct nk_vec2i *pnts,
int count, unsigned short line_thickness, struct nk_color col)
{
int i = 0;
unsigned long c = color_from_byte(&col.r);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
XSetForeground(surf->dpy, surf->gc, c);
for (i = 0; i < count-1; ++i)
XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i].x, pnts[i].y, pnts[i+1].x, pnts[i+1].y);
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
nk_xsurf_fill_circle(XSurface *surf, short x, short y, unsigned short w,
unsigned short h, struct nk_color col)
{
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
XFillArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
(unsigned)w, (unsigned)h, 0, 360 * 64);
}
static void
nk_xsurf_stroke_circle(XSurface *surf, short x, short y, unsigned short w,
unsigned short h, unsigned short line_thickness, struct nk_color col)
{
unsigned long c = color_from_byte(&col.r);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
XSetForeground(surf->dpy, surf->gc, c);
XDrawArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
(unsigned)w, (unsigned)h, 0, 360 * 64);
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
nk_xsurf_stroke_curve(XSurface *surf, struct nk_vec2i p1,
struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,
unsigned int num_segments, unsigned short line_thickness, struct nk_color col)
{
unsigned int i_step;
float t_step;
struct nk_vec2i last = p1;
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
num_segments = MAX(num_segments, 1);
t_step = 1.0f/(float)num_segments;
for (i_step = 1; i_step <= num_segments; ++i_step) {
float t = t_step * (float)i_step;
float u = 1.0f - t;
float w1 = u*u*u;
float w2 = 3*u*u*t;
float w3 = 3*u*t*t;
float w4 = t * t *t;
float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;
float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;
nk_xsurf_stroke_line(surf, last.x, last.y, (short)x, (short)y, line_thickness,col);
last.x = (short)x; last.y = (short)y;
}
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
nk_xsurf_draw_text(XSurface *surf, short x, short y, unsigned short w, unsigned short h,
const char *text, int len, XFont *font, struct nk_color cbg, struct nk_color cfg)
{
int tx, ty;
unsigned long bg = color_from_byte(&cbg.r);
unsigned long fg = color_from_byte(&cfg.r);
XSetForeground(surf->dpy, surf->gc, bg);
XFillRectangle(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, (unsigned)w, (unsigned)h);
if(!text || !font || !len) return;
tx = (int)x;
ty = (int)y + font->ascent;
XSetForeground(surf->dpy, surf->gc, fg);
if(font->set)
XmbDrawString(surf->dpy,surf->drawable,font->set,surf->gc,tx,ty,(const char*)text,(int)len);
else
XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len);
}
static void
nk_xsurf_clear(XSurface *surf, unsigned long color)
{
XSetForeground(surf->dpy, surf->gc, color);
XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h);
}
static void
nk_xsurf_blit(Drawable target, XSurface *surf, unsigned int w, unsigned int h)
{
XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, w, h, 0, 0);
}
static void
nk_xsurf_del(XSurface *surf)
{
XFreePixmap(surf->dpy, surf->drawable);
XFreeGC(surf->dpy, surf->gc);
free(surf);
}
XFont*
nk_xfont_create(Display *dpy, const char *name)
{
int n;
char *def, **missing;
XFont *font = (XFont*)calloc(1, sizeof(XFont));
font->set = XCreateFontSet(dpy, name, &missing, &n, &def);
if(missing) {
while(n--)
fprintf(stderr, "missing fontset: %s\n", missing[n]);
XFreeStringList(missing);
}
if(font->set) {
XFontStruct **xfonts;
char **font_names;
XExtentsOfFontSet(font->set);
n = XFontsOfFontSet(font->set, &xfonts, &font_names);
while(n--) {
font->ascent = MAX(font->ascent, (*xfonts)->ascent);
font->descent = MAX(font->descent,(*xfonts)->descent);
xfonts++;
}
} else {
if(!(font->xfont = XLoadQueryFont(dpy, name))
&& !(font->xfont = XLoadQueryFont(dpy, "fixed"))) {
free(font);
return 0;
}
font->ascent = font->xfont->ascent;
font->descent = font->xfont->descent;
}
font->height = font->ascent + font->descent;
return font;
}
static float
nk_xfont_get_text_width(nk_handle handle, float height, const char *text, int len)
{
XFont *font = (XFont*)handle.ptr;
XRectangle r;
if(!font || !text)
return 0;
if(font->set) {
XmbTextExtents(font->set, (const char*)text, len, NULL, &r);
return (float)r.width;
} else{
int w = XTextWidth(font->xfont, (const char*)text, len);
return (float)w;
}
}
void
nk_xfont_del(Display *dpy, XFont *font)
{
if(!font) return;
if(font->set)
XFreeFontSet(dpy, font->set);
else
XFreeFont(dpy, font->xfont);
free(font);
}
NK_API struct nk_context*
nk_xlib_init(XFont *xfont, Display *dpy, int screen, Window root,
unsigned int w, unsigned int h)
{
struct nk_user_font font;
font.userdata = nk_handle_ptr(xfont);
font.height = (float)xfont->height;
font.width = nk_xfont_get_text_width;
if (!setlocale(LC_ALL,"")) return 0;
if (!XSupportsLocale()) return 0;
if (!XSetLocaleModifiers("@im=none")) return 0;
xlib.surf = nk_xsurf_create(dpy, screen, root, w, h);
nk_init_default(&xlib.ctx, &font);
return &xlib.ctx;
}
NK_API void
nk_xlib_set_font(XFont *xfont)
{
struct nk_user_font font;
font.userdata = nk_handle_ptr(xfont);
font.height = (float)xfont->height;
font.width = nk_xfont_get_text_width;
nk_style_set_font(&xlib.ctx, &font);
}
NK_API void
nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt)
{
struct nk_context *ctx = &xlib.ctx;
if (evt->type == KeyPress || evt->type == KeyRelease)
{
/* Key handler */
int ret, down = (evt->type == KeyPress);
KeySym *code = XGetKeyboardMapping(xlib.surf->dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down);
else if (*code == XK_Delete) nk_input_key(ctx, NK_KEY_DEL, down);
else if (*code == XK_Return) nk_input_key(ctx, NK_KEY_ENTER, down);
else if (*code == XK_Tab) nk_input_key(ctx, NK_KEY_TAB, down);
else if (*code == XK_Left) nk_input_key(ctx, NK_KEY_LEFT, down);
else if (*code == XK_Right) nk_input_key(ctx, NK_KEY_RIGHT, down);
else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);
else if (*code == XK_Home) nk_input_key(ctx, NK_KEY_TEXT_START, down);
else if (*code == XK_End) nk_input_key(ctx, NK_KEY_TEXT_END, down);
else if (*code == XK_space && !down) nk_input_char(ctx, ' ');
else {
if (*code == 'c' && (evt->xkey.state & ControlMask))
nk_input_key(ctx, NK_KEY_COPY, down);
else if (*code == 'v' && (evt->xkey.state & ControlMask))
nk_input_key(ctx, NK_KEY_PASTE, down);
else if (*code == 'x' && (evt->xkey.state & ControlMask))
nk_input_key(ctx, NK_KEY_CUT, down);
else if (*code == 'z' && (evt->xkey.state & ControlMask))
nk_input_key(ctx, NK_KEY_TEXT_UNDO, down);
else if (*code == 'r' && (evt->xkey.state & ControlMask))
nk_input_key(ctx, NK_KEY_TEXT_REDO, down);
else if (*code == XK_Left && (evt->xkey.state & ControlMask))
nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
else if (*code == XK_Right && (evt->xkey.state & ControlMask))
nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
else if (*code == 'b' && (evt->xkey.state & ControlMask))
nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down);
else if (*code == 'e' && (evt->xkey.state & ControlMask))
nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down);
else if (!down) {
char buf[32];
if ((*code >= 'a' && *code <= 'z') || (*code >= 'A' && *code <= 'Z')) {
KeySym keysym = 0;
if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)
nk_input_glyph(ctx, buf);
}
}
}
XFree(code);
} else if (evt->type == ButtonPress || evt->type == ButtonRelease) {
/* Button handler */
int down = (evt->type == ButtonPress);
const int x = evt->xbutton.x, y = evt->xbutton.y;
if (evt->xbutton.button == Button1)
nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
if (evt->xbutton.button == Button2)
nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
else if (evt->xbutton.button == Button3)
nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
else if (evt->xbutton.button == Button4)
nk_input_scroll(ctx, 1.0f);
else if (evt->xbutton.button == Button5)
nk_input_scroll(ctx, -1.0f);
} else if (evt->type == MotionNotify) {
/* Mouse motion handler */
const int x = evt->xmotion.x, y = evt->xmotion.y;
nk_input_motion(ctx, x, y);
} else if (evt->type == Expose || evt->type == ConfigureNotify) {
/* Window resize handler */
unsigned int width, height;
XWindowAttributes attr;
XGetWindowAttributes(dpy, win, &attr);
width = (unsigned int)attr.width;
height = (unsigned int)attr.height;
nk_xsurf_resize(xlib.surf, width, height);
} else if (evt->type == KeymapNotify)
XRefreshKeyboardMapping(&evt->xmapping);
}
NK_API void
nk_xlib_shutdown(void)
{
nk_xsurf_del(xlib.surf);
nk_free(&xlib.ctx);
}
NK_API void
nk_xlib_render(Drawable screen, struct nk_color clear)
{
const struct nk_command *cmd;
struct nk_context *ctx = &xlib.ctx;
XSurface *surf = xlib.surf;
nk_xsurf_clear(xlib.surf, color_from_byte(&clear.r));
nk_foreach(cmd, &xlib.ctx)
{
switch (cmd->type) {
case NK_COMMAND_NOP: break;
case NK_COMMAND_SCISSOR: {
const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;
nk_xsurf_scissor(surf, s->x, s->y, s->w, s->h);
} break;
case NK_COMMAND_LINE: {
const struct nk_command_line *l = (const struct nk_command_line *)cmd;
nk_xsurf_stroke_line(surf, l->begin.x, l->begin.y, l->end.x,
l->end.y, l->line_thickness, l->color);
} break;
case NK_COMMAND_RECT: {
const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;
nk_xsurf_stroke_rect(surf, r->x, r->y, r->w, r->h,
(unsigned short)r->rounding, r->line_thickness, r->color);
} break;
case NK_COMMAND_RECT_FILLED: {
const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;
nk_xsurf_fill_rect(surf, r->x, r->y, r->w, r->h,
(unsigned short)r->rounding, r->color);
} break;
case NK_COMMAND_CIRCLE: {
const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;
nk_xsurf_stroke_circle(surf, c->x, c->y, c->w, c->h, c->line_thickness, c->color);
} break;
case NK_COMMAND_CIRCLE_FILLED: {
const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;
nk_xsurf_fill_circle(surf, c->x, c->y, c->w, c->h, c->color);
} break;
case NK_COMMAND_TRIANGLE: {
const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;
nk_xsurf_stroke_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y,
t->c.x, t->c.y, t->line_thickness, t->color);
} break;
case NK_COMMAND_TRIANGLE_FILLED: {
const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;
nk_xsurf_fill_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y,
t->c.x, t->c.y, t->color);
} break;
case NK_COMMAND_POLYGON: {
const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;
nk_xsurf_stroke_polygon(surf, p->points, p->point_count, p->line_thickness,p->color);
} break;
case NK_COMMAND_POLYGON_FILLED: {
const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;
nk_xsurf_fill_polygon(surf, p->points, p->point_count, p->color);
} break;
case NK_COMMAND_POLYLINE: {
const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;
nk_xsurf_stroke_polyline(surf, p->points, p->point_count, p->line_thickness, p->color);
} break;
case NK_COMMAND_TEXT: {
const struct nk_command_text *t = (const struct nk_command_text*)cmd;
nk_xsurf_draw_text(surf, t->x, t->y, t->w, t->h,
(const char*)t->string, t->length,
(XFont*)t->font->userdata.ptr,
t->background, t->foreground);
} break;
case NK_COMMAND_CURVE: {
const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;
nk_xsurf_stroke_curve(surf, q->begin, q->ctrl[0], q->ctrl[1],
q->end, 22, q->line_thickness, q->color);
} break;
case NK_COMMAND_RECT_MULTI_COLOR:
case NK_COMMAND_IMAGE:
case NK_COMMAND_ARC:
case NK_COMMAND_ARC_FILLED:
default: break;
}
}
nk_clear(ctx);
nk_xsurf_blit(screen, surf, surf->w, surf->h);
}

17
demo/x11/nuklear_xlib.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef NK_XLIB_H_
#define NK_XLIB_H_
#include "../../nuklear.h"
typedef struct XFont XFont;
NK_API struct nk_context* nk_xlib_init(XFont *font, Display *dpy, int screen, Window root, unsigned int w, unsigned int h);
NK_API void nk_xlib_set_font(XFont *font);
NK_API void nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt);
NK_API void nk_xlib_render(Drawable screen, struct nk_color clear);
NK_API void nk_xlib_shutdown(void);
/* font */
NK_API XFont* nk_xfont_create(Display *dpy, const char *name);
NK_API void nk_xfont_del(Display *dpy, XFont *font);
#endif

View File

@ -1,794 +0,0 @@
/*
Copyright (c) 2016 Micha Mettke
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/Xlocale.h>
/* macros */
#define DTIME 16
#include "../../zahnrad.h"
#define DEMO_DO_NOT_DRAW_IMAGES
#define DEMO_DO_NOT_USE_COLOR_PICKER
#include "../demo.c"
typedef struct XFont XFont;
typedef struct XSurface XSurface;
typedef struct XWindow XWindow;
struct XFont {
int ascent;
int descent;
int height;
XFontSet set;
XFontStruct *xfont;
};
struct XSurface {
GC gc;
Display *dpy;
int screen;
Window root;
Drawable drawable;
unsigned int w, h;
};
struct XWindow {
Display *dpy;
Window root;
Visual *vis;
XFont *font;
XSurface *surf;
Colormap cmap;
XWindowAttributes attr;
XSetWindowAttributes swa;
Window win;
int screen;
unsigned int width;
unsigned int height;
};
static void
die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputs("\n", stderr);
exit(EXIT_FAILURE);
}
static void*
xcalloc(size_t siz, size_t n)
{
void *ptr = calloc(siz, n);
if (!ptr) die("Out of memory\n");
return ptr;
}
static long
timestamp(void)
{
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0) return 0;
return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
}
static void
sleep_for(long t)
{
struct timespec req;
const time_t sec = (int)(t/1000);
const long ms = t - (sec * 1000);
req.tv_sec = sec;
req.tv_nsec = ms * 1000000L;
while(-1 == nanosleep(&req, &req));
}
static XFont*
font_create(Display *dpy, const char *name)
{
int n;
char *def, **missing;
XFont *font = (XFont*)xcalloc(1, sizeof(XFont));
font->set = XCreateFontSet(dpy, name, &missing, &n, &def);
if(missing) {
while(n--)
fprintf(stderr, "missing fontset: %s\n", missing[n]);
XFreeStringList(missing);
}
if(font->set) {
XFontStruct **xfonts;
char **font_names;
XExtentsOfFontSet(font->set);
n = XFontsOfFontSet(font->set, &xfonts, &font_names);
while(n--) {
font->ascent = MAX(font->ascent, (*xfonts)->ascent);
font->descent = MAX(font->descent,(*xfonts)->descent);
xfonts++;
}
} else {
if(!(font->xfont = XLoadQueryFont(dpy, name))
&& !(font->xfont = XLoadQueryFont(dpy, "fixed")))
die("error, cannot load font: '%s'\n", name);
font->ascent = font->xfont->ascent;
font->descent = font->xfont->descent;
}
font->height = font->ascent + font->descent;
return font;
}
static zr_size
font_get_text_width(zr_handle handle, float height, const char *text, zr_size len)
{
XFont *font = (XFont*)handle.ptr;
XRectangle r;
if(!font || !text)
return 0;
UNUSED(height);
if(font->set) {
XmbTextExtents(font->set, (const char*)text, (int)len, NULL, &r);
return r.width;
} else return (zr_size)XTextWidth(font->xfont, (const char*)text, (int)len);
}
static void
font_del(Display *dpy, XFont *font)
{
if(!font) return;
if(font->set)
XFreeFontSet(dpy, font->set);
else
XFreeFont(dpy, font->xfont);
free(font);
}
static unsigned long
color_from_byte(const zr_byte *c)
{
unsigned long res = 0;
res |= (unsigned long)c[0] << 16;
res |= (unsigned long)c[1] << 8;
res |= (unsigned long)c[2] << 0;
return (res);
}
static void
color_to_byte(unsigned char *c, unsigned long pixel)
{
c[0] = (pixel & ((unsigned long)0xFF << 16)) >> 16;
c[1] = (pixel & ((unsigned long)0xFF << 8)) >> 8;
c[2] = (pixel & ((unsigned long)0xFF << 0)) >> 0;
c[3] = (pixel & ((unsigned long)0xFF << 24)) >> 24;
}
static XSurface*
surface_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
{
XSurface *surface = (XSurface*)xcalloc(1, sizeof(XSurface));
surface->w = w;
surface->h = h;
surface->dpy = dpy;
surface->screen = screen;
surface->root = root;
surface->gc = XCreateGC(dpy, root, 0, NULL);
XSetLineAttributes(dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter);
surface->drawable = XCreatePixmap(dpy, root, w, h, 32);
return surface;
}
static void
surface_resize(XSurface *surf, unsigned int w, unsigned int h)
{
if(!surf) return;
if (surf->w == w && surf->h == h) return;
surf->w = w; surf->h = h;
if(surf->drawable) XFreePixmap(surf->dpy, surf->drawable);
surf->drawable = XCreatePixmap(surf->dpy, surf->root, w, h,
(unsigned int)DefaultDepth(surf->dpy, surf->screen));
}
static void
surface_scissor(XSurface *surf, float x, float y, float w, float h)
{
XRectangle clip_rect;
clip_rect.x = (short)(x-1);
clip_rect.y = (short)(y-1);
clip_rect.width = (unsigned short)(w+2);
clip_rect.height = (unsigned short)(h+2);
XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted);
}
static void
surface_stroke_line(XSurface *surf, short x0, short y0, short x1,
short y1, unsigned int line_thickness, struct zr_color col)
{
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
XDrawLine(surf->dpy, surf->drawable, surf->gc, (int)x0, (int)y0, (int)x1, (int)y1);
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
surface_stroke_rect(XSurface* surf, short x, short y, unsigned short w,
unsigned short h, unsigned short r, unsigned short line_thickness, struct zr_color col)
{
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
if (r == 0) {
XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
} else {
short xc = x + r;
short yc = y + r;
short wc = (short)(w - 2 * r);
short hc = (short)(h - 2 * r);
XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y, xc+wc, y);
XDrawLine(surf->dpy, surf->drawable, surf->gc, x+w, yc, x+w, yc+wc);
XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h);
XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, yc+hc, x);
XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
(unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
(unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
(unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
(unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
}
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
surface_fill_rect(XSurface* surf, short x, short y, unsigned short w,
unsigned short h, unsigned short r, struct zr_color col)
{
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
if (r == 0) {
XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
} else {
short xc = x + r;
short yc = y + r;
short wc = (short)(w - 2 * r);
short hc = (short)(h - 2 * r);
XPoint pnts[12];
pnts[0].x = x;
pnts[0].y = yc;
pnts[1].x = xc;
pnts[1].y = yc;
pnts[2].x = xc;
pnts[2].y = y;
pnts[3].x = xc + wc;
pnts[3].y = y;
pnts[4].x = xc + wc;
pnts[4].y = yc;
pnts[5].x = x + w;
pnts[5].y = yc;
pnts[6].x = x + w;
pnts[6].y = yc + hc;
pnts[7].x = xc + wc;
pnts[7].y = yc + hc;
pnts[8].x = xc + wc;
pnts[8].y = y + h;
pnts[9].x = xc;
pnts[9].y = y + h;
pnts[10].x = xc;
pnts[10].y = yc + hc;
pnts[11].x = x;
pnts[11].y = yc + hc;
XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 12, Convex, CoordModeOrigin);
XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
(unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
(unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
(unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
(unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
}
}
static void
surface_fill_triangle(XSurface *surf, short x0, short y0, short x1,
short y1, short x2, short y2, struct zr_color col)
{
XPoint pnts[3];
unsigned long c = color_from_byte(&col.r);
pnts[0].x = (short)x0;
pnts[0].y = (short)y0;
pnts[1].x = (short)x1;
pnts[1].y = (short)y1;
pnts[2].x = (short)x2;
pnts[2].y = (short)y2;
XSetForeground(surf->dpy, surf->gc, c);
XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin);
}
static void
surface_stroke_triangle(XSurface *surf, short x0, short y0, short x1,
short y1, short x2, short y2, unsigned short line_thickness, struct zr_color col)
{
XPoint pnts[3];
unsigned long c = color_from_byte(&col.r);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
XDrawLine(surf->dpy, surf->drawable, surf->gc, x0, y0, x1, y1);
XDrawLine(surf->dpy, surf->drawable, surf->gc, x1, y1, x2, y2);
XDrawLine(surf->dpy, surf->drawable, surf->gc, x2, y2, x0, y0);
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
surface_fill_polygon(XSurface *surf, const struct zr_vec2i *pnts, int count,
struct zr_color col)
{
int i = 0;
#define MAX_POINTS 64
XPoint xpnts[MAX_POINTS];
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
for (i = 0; i < count && i < MAX_POINTS; ++i) {
xpnts[i].x = pnts[i].x;
xpnts[i].y = pnts[i].y;
}
XFillPolygon(surf->dpy, surf->drawable, surf->gc, xpnts, count, Convex, CoordModeOrigin);
#undef MAX_POINTS
}
static void
surface_stroke_polygon(XSurface *surf, const struct zr_vec2i *pnts, int count,
unsigned short line_thickness, struct zr_color col)
{
int i = 0;
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
for (i = 1; i < count; ++i)
XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);
XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y);
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
surface_stroke_polyline(XSurface *surf, const struct zr_vec2i *pnts,
int count, unsigned short line_thickness, struct zr_color col)
{
int i = 0;
unsigned long c = color_from_byte(&col.r);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
XSetForeground(surf->dpy, surf->gc, c);
for (i = 0; i < count-1; ++i)
XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i].x, pnts[i].y, pnts[i+1].x, pnts[i+1].y);
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
surface_fill_circle(XSurface *surf, short x, short y, unsigned short w,
unsigned short h, struct zr_color col)
{
unsigned long c = color_from_byte(&col.r);
XSetForeground(surf->dpy, surf->gc, c);
XFillArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
(unsigned)w, (unsigned)h, 0, 360 * 64);
}
static void
surface_stroke_circle(XSurface *surf, short x, short y, unsigned short w,
unsigned short h, unsigned short line_thickness, struct zr_color col)
{
unsigned long c = color_from_byte(&col.r);
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
XSetForeground(surf->dpy, surf->gc, c);
XDrawArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
(unsigned)w, (unsigned)h, 0, 360 * 64);
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
surface_stroke_curve(XSurface *surf, struct zr_vec2i p1,
struct zr_vec2i p2, struct zr_vec2i p3, struct zr_vec2i p4,
unsigned int num_segments, unsigned short line_thickness, struct zr_color col)
{
unsigned int i_step;
float t_step;
struct zr_vec2i last = p1;
XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
num_segments = MAX(num_segments, 1);
t_step = 1.0f/(float)num_segments;
for (i_step = 1; i_step <= num_segments; ++i_step) {
float t = t_step * (float)i_step;
float u = 1.0f - t;
float w1 = u*u*u;
float w2 = 3*u*u*t;
float w3 = 3*u*t*t;
float w4 = t * t *t;
float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;
float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;
surface_stroke_line(surf, last.x, last.y, (short)x, (short)y, line_thickness,col);
last.x = (short)x; last.y = (short)y;
}
XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
}
static void
surface_draw_text(XSurface *surf, short x, short y, unsigned short w, unsigned short h,
const char *text, size_t len, XFont *font, struct zr_color cbg, struct zr_color cfg)
{
int tx, ty, th;
unsigned long bg = color_from_byte(&cbg.r);
unsigned long fg = color_from_byte(&cfg.r);
XSetForeground(surf->dpy, surf->gc, bg);
XFillRectangle(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, (unsigned)w, (unsigned)h);
if(!text || !font || !len) return;
tx = (int)x;
th = font->ascent + font->descent;
ty = (int)y + font->ascent;
XSetForeground(surf->dpy, surf->gc, fg);
if(font->set)
XmbDrawString(surf->dpy,surf->drawable,font->set,surf->gc,tx,ty,(const char*)text,(int)len);
else
XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len);
}
static void
surface_clear(XSurface *surf, unsigned long color)
{
XSetForeground(surf->dpy, surf->gc, color);
XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h);
}
static void
surface_blit(XSurface *dst_surf, XSurface *src_surf,
int dst_x, int dst_y, int dst_w, int dst_h,
int src_x, int src_y, int src_w, int src_h)
{
GC gc;
XImage *dst, *src;
XGCValues gcvalues;
int x = 0, y = 0;
/*@optimize: there is probably a more performant way to do this since this is slow as FUCK */
src = XGetImage(src_surf->dpy, src_surf->drawable, 0, 0, src_surf->w, src_surf->h, AllPlanes, ZPixmap);
dst = XGetImage(dst_surf->dpy, dst_surf->drawable, 0, 0, dst_surf->w, dst_surf->h, AllPlanes, ZPixmap);
for (y = 0; y < dst_h; ++y) {
int dst_off_y = dst_y + y;
int src_off_y = src_y + (int)((float)y * (float)src_h/(float)dst_h);
for (x = 0; x < dst_w; ++x) {
unsigned long dpx, spx, pixel;
struct zr_color dst_col_b, src_col_b, res;
float dst_col[4], src_col[4], res_col[4];
int dst_off_x = dst_x + x;
int src_off_x = src_x + (int)((float)x * (float)src_w/(float)dst_w);
/* acquire both source and destination pixel */
spx = XGetPixel(src, src_off_x, src_off_y);
dpx = XGetPixel(dst, dst_off_x, dst_off_y);
/* convert from 32-bit integer to byte */
color_to_byte(&dst_col_b.r, dpx);
color_to_byte(&src_col_b.r, spx);
/* convert from byte to float */
zr_color_f(&dst_col[0], &dst_col[1], &dst_col[2], &dst_col[3], dst_col_b);
zr_color_f(&src_col[0], &src_col[1], &src_col[2], &src_col[3], src_col_b);
/* perform simple alpha-blending */
res_col[0] = (1.0f - src_col[3]) * dst_col[0] + src_col[3] * src_col[0];
res_col[1] = (1.0f - src_col[3]) * dst_col[1] + src_col[3] * src_col[1];
res_col[2] = (1.0f - src_col[3]) * dst_col[2] + src_col[3] * src_col[2];
res_col[3] = 255;
/* convert from float to byte */
res = zr_rgb_f(res_col[0], res_col[1], res_col[2]);
pixel = color_from_byte(&res.r);
/* finally write pixel to surface */
XPutPixel(dst, dst_off_x, dst_off_y, pixel);
}
}
gc = XCreateGC(dst_surf->dpy, dst_surf->drawable, 0, &gcvalues);
XPutImage(dst_surf->dpy, dst_surf->drawable, gc, dst, 0, 0, 0, 0,
(unsigned int)dst_surf->w, (unsigned int)dst_surf->h);
XDestroyImage(src);
XDestroyImage(dst);
}
static void
surface_blit_to_screen(Drawable target, XSurface *surf, unsigned int width, unsigned int height)
{
XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, width, height, 0, 0);
}
static void
surface_del(XSurface *surf)
{
XFreePixmap(surf->dpy, surf->drawable);
XFreeGC(surf->dpy, surf->gc);
free(surf);
}
static void
input_key(struct XWindow *xw, struct zr_context *ctx, XEvent *evt, int down)
{
int ret;
KeySym *code = XGetKeyboardMapping(xw->dpy, (KeyCode)evt->xkey.keycode, 1, &ret);
if (*code == XK_Shift_L || *code == XK_Shift_R)
zr_input_key(ctx, ZR_KEY_SHIFT, down);
else if (*code == XK_Delete)
zr_input_key(ctx, ZR_KEY_DEL, down);
else if (*code == XK_Return)
zr_input_key(ctx, ZR_KEY_ENTER, down);
else if (*code == XK_Tab) {
zr_input_key(ctx, ZR_KEY_TAB, down);
} else if (*code == XK_space && !down)
zr_input_char(ctx, ' ');
else if (*code == XK_Left)
zr_input_key(ctx, ZR_KEY_LEFT, down);
else if (*code == XK_Right)
zr_input_key(ctx, ZR_KEY_RIGHT, down);
else if (*code == XK_BackSpace)
zr_input_key(ctx, ZR_KEY_BACKSPACE, down);
else {
if (*code == 'c' && (evt->xkey.state & ControlMask))
zr_input_key(ctx, ZR_KEY_COPY, down);
else if (*code == 'v' && (evt->xkey.state & ControlMask))
zr_input_key(ctx, ZR_KEY_PASTE, down);
else if (*code == 'x' && (evt->xkey.state & ControlMask))
zr_input_key(ctx, ZR_KEY_CUT, down);
else if (!down) {
KeySym keysym = 0;
char buf[32];
XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL);
zr_input_glyph(ctx, buf);
}
}
XFree(code);
}
static void
input_motion(struct zr_context *ctx, XEvent *evt)
{
const int x = evt->xmotion.x;
const int y = evt->xmotion.y;
zr_input_motion(ctx, x, y);
}
static void
input_button(struct zr_context *ctx, XEvent *evt, int down)
{
const int x = evt->xbutton.x;
const int y = evt->xbutton.y;
if (evt->xbutton.button == Button1)
zr_input_button(ctx, ZR_BUTTON_LEFT, x, y, down);
if (evt->xbutton.button == Button2)
zr_input_button(ctx, ZR_BUTTON_MIDDLE, x, y, down);
else if (evt->xbutton.button == Button3)
zr_input_button(ctx, ZR_BUTTON_RIGHT, x, y, down);
else if (evt->xbutton.button == Button4)
zr_input_scroll(ctx, 1.0f);
else if (evt->xbutton.button == Button5)
zr_input_scroll(ctx, -1.0f);
}
static void
resize(struct XWindow *xw, XSurface *surf)
{
XGetWindowAttributes(xw->dpy, xw->win, &xw->attr);
xw->width = (unsigned int)xw->attr.width;
xw->height = (unsigned int)xw->attr.height;
surface_resize(surf, xw->width, xw->height);
}
int
main(int argc, char *argv[])
{
long dt;
long started;
XWindow xw;
struct demo gui;
struct zr_user_font font;
int running = 1;
/* X11 */
UNUSED(argc); UNUSED(argv);
memset(&xw, 0, sizeof xw);
if (setlocale(LC_ALL, "") == NULL) return 9;
if (!XSupportsLocale()) return 10;
if (!XSetLocaleModifiers("@im=none")) return 11;
xw.dpy = XOpenDisplay(NULL);
xw.root = DefaultRootWindow(xw.dpy);
xw.screen = XDefaultScreen(xw.dpy);
xw.vis = XDefaultVisual(xw.dpy, xw.screen);
xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone);
xw.swa.colormap = xw.cmap;
xw.swa.event_mask =
ExposureMask | KeyPressMask | KeyReleaseMask |
ButtonPress | ButtonReleaseMask| ButtonMotionMask |
Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|
PointerMotionMask | KeymapStateMask;
xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0,
XDefaultDepth(xw.dpy, xw.screen), InputOutput,
xw.vis, CWEventMask | CWColormap, &xw.swa);
XStoreName(xw.dpy, xw.win, "X11");
XMapWindow(xw.dpy, xw.win);
XGetWindowAttributes(xw.dpy, xw.win, &xw.attr);
xw.width = (unsigned int)xw.attr.width;
xw.height = (unsigned int)xw.attr.height;
xw.surf = surface_create(xw.dpy, xw.screen, xw.win, xw.width, xw.height);
xw.font = font_create(xw.dpy, "fixed");
/* GUI */
font.userdata = zr_handle_ptr(xw.font);
font.height = (float)xw.font->height;
font.width = font_get_text_width;
memset(&gui, 0, sizeof gui);
gui.memory = calloc(MAX_MEMORY, 1);
zr_init_fixed(&gui.ctx, gui.memory, MAX_MEMORY, &font);
while (running) {
/* Input */
XEvent evt;
started = timestamp();
zr_input_begin(&gui.ctx);
while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &evt)) {
if (XFilterEvent(&evt, xw.win)) continue;
if (evt.type == KeyPress)
input_key(&xw, &gui.ctx, &evt, zr_true);
else if (evt.type == KeyRelease)
input_key(&xw, &gui.ctx, &evt, zr_false);
else if (evt.type == ButtonPress)
input_button(&gui.ctx, &evt, zr_true);
else if (evt.type == ButtonRelease)
input_button(&gui.ctx, &evt, zr_false);
else if (evt.type == MotionNotify)
input_motion(&gui.ctx, &evt);
else if (evt.type == Expose || evt.type == ConfigureNotify)
resize(&xw, xw.surf);
else if (evt.type == KeymapNotify)
XRefreshKeyboardMapping(&evt.xmapping);
}
zr_input_end(&gui.ctx);
/* GUI */
running = run_demo(&gui);
/* Draw */
XClearWindow(xw.dpy, xw.win);
surface_clear(xw.surf, 0x00303030);
{
const struct zr_command *cmd;
zr_foreach(cmd, &gui.ctx) {
switch (cmd->type) {
case ZR_COMMAND_NOP: break;
case ZR_COMMAND_SCISSOR: {
const struct zr_command_scissor *s = zr_command(scissor, cmd);
surface_scissor(xw.surf, s->x, s->y, s->w, s->h);
} break;
case ZR_COMMAND_LINE: {
const struct zr_command_line *l = zr_command(line, cmd);
surface_stroke_line(xw.surf, l->begin.x, l->begin.y, l->end.x,
l->end.y, l->line_thickness, l->color);
} break;
case ZR_COMMAND_RECT: {
const struct zr_command_rect *r = zr_command(rect, cmd);
surface_stroke_rect(xw.surf, r->x, r->y, r->w, r->h,
(uint16_t)r->rounding, r->line_thickness, r->color);
} break;
case ZR_COMMAND_RECT_FILLED: {
const struct zr_command_rect_filled *r = zr_command(rect_filled, cmd);
surface_fill_rect(xw.surf, r->x, r->y, r->w, r->h,
(uint16_t)r->rounding, r->color);
} break;
case ZR_COMMAND_CIRCLE: {
const struct zr_command_circle *c = zr_command(circle, cmd);
surface_stroke_circle(xw.surf, c->x, c->y, c->w, c->h, c->line_thickness, c->color);
} break;
case ZR_COMMAND_CIRCLE_FILLED: {
const struct zr_command_circle_filled *c = zr_command(circle_filled, cmd);
surface_fill_circle(xw.surf, c->x, c->y, c->w, c->h, c->color);
} break;
case ZR_COMMAND_TRIANGLE: {
const struct zr_command_triangle*t = zr_command(triangle, cmd);
surface_stroke_triangle(xw.surf, t->a.x, t->a.y, t->b.x, t->b.y,
t->c.x, t->c.y, t->line_thickness, t->color);
} break;
case ZR_COMMAND_TRIANGLE_FILLED: {
const struct zr_command_triangle_filled *t = zr_command(triangle_filled, cmd);
surface_fill_triangle(xw.surf, t->a.x, t->a.y, t->b.x, t->b.y,
t->c.x, t->c.y, t->color);
} break;
case ZR_COMMAND_POLYGON: {
const struct zr_command_polygon *p = zr_command(polygon, cmd);
surface_stroke_polygon(xw.surf, p->points, p->point_count, p->line_thickness,p->color);
} break;
case ZR_COMMAND_POLYGON_FILLED: {
const struct zr_command_polygon_filled *p = zr_command(polygon_filled, cmd);
surface_fill_polygon(xw.surf, p->points, p->point_count, p->color);
} break;
case ZR_COMMAND_POLYLINE: {
const struct zr_command_polyline *p = zr_command(polyline, cmd);
surface_stroke_polyline(xw.surf, p->points, p->point_count, p->line_thickness, p->color);
} break;
case ZR_COMMAND_TEXT: {
const struct zr_command_text *t = zr_command(text, cmd);
surface_draw_text(xw.surf, t->x, t->y, t->w, t->h,
(const char*)t->string, t->length,
(XFont*)t->font->userdata.ptr,
t->background, t->foreground);
} break;
case ZR_COMMAND_CURVE: {
const struct zr_command_curve *q = zr_command(curve, cmd);
surface_stroke_curve(xw.surf, q->begin, q->ctrl[0], q->ctrl[1],
q->end, 22, q->line_thickness, q->color);
} break;
case ZR_COMMAND_RECT_MULTI_COLOR:
case ZR_COMMAND_IMAGE:
case ZR_COMMAND_ARC:
case ZR_COMMAND_ARC_FILLED:
default: break;
}
}
zr_clear(&gui.ctx);
}
surface_blit_to_screen(xw.win, xw.surf, xw.width, xw.height);
XFlush(xw.dpy);
/* Timing */
dt = timestamp() - started;
if (dt < DTIME)
sleep_for(DTIME - dt);
}
free(gui.memory);
font_del(xw.dpy, xw.font);
surface_del(xw.surf);
XUnmapWindow(xw.dpy, xw.win);
XFreeColormap(xw.dpy, xw.cmap);
XDestroyWindow(xw.dpy, xw.win);
XCloseDisplay(xw.dpy);
return 0;
}

34
example/Makefile Normal file
View File

@ -0,0 +1,34 @@
# Compiler
CC = clang
# Flags
CFLAGS = -std=c99 -pedantic -O2
ifeq ($(OS),Windows_NT)
BIN := $(BIN).exe
LIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32
else
LIBS = -lglfw -lGL -lm -lGLU -lGLEW
endif
all: node_editor file_browser overview extended
node_editor:
@mkdir -p bin
rm -f bin/node_editor $(OBJS)
$(CC) $(CFLAGS) -o bin/node_editor node_editor.c $(LIBS)
file_browser:
@mkdir -p bin
rm -f bin/file_browser $(OBJS)
$(CC) $(CFLAGS) -o bin/file_browser file_browser.c $(LIBS)
overview:
@mkdir -p bin
rm -f bin/overview $(OBJS)
$(CC) $(CFLAGS) -o bin/overview overview.c $(LIBS)
extended:
@mkdir -p bin
rm -f bin/extended $(OBJS)
$(CC) $(CFLAGS) -o bin/extended extended.c $(LIBS)

882
example/extended.c Normal file
View File

@ -0,0 +1,882 @@
/* nuklear - v1.00 - public domain */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include <limits.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GLFW/glfw3.h>
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#include "../nuklear.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
/* macros */
#define WINDOW_WIDTH 1200
#define WINDOW_HEIGHT 800
#define MAX_VERTEX_MEMORY 512 * 1024
#define MAX_ELEMENT_MEMORY 128 * 1024
#define UNUSED(a) (void)a
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) < (b) ? (b) : (a))
#define LEN(a) (sizeof(a)/sizeof(a)[0])
struct icons {
struct nk_image unchecked;
struct nk_image checked;
struct nk_image rocket;
struct nk_image cloud;
struct nk_image pen;
struct nk_image play;
struct nk_image pause;
struct nk_image stop;
struct nk_image prev;
struct nk_image next;
struct nk_image tools;
struct nk_image dir;
struct nk_image copy;
struct nk_image convert;
struct nk_image del;
struct nk_image edit;
struct nk_image images[9];
struct nk_image menu[6];
};
/* ===============================================================
*
* CUSTOM WIDGET
*
* ===============================================================*/
static int
ui_piemenu(struct nk_context *ctx, struct nk_vec2 pos, float radius,
struct nk_image *icons, int item_count)
{
int ret = -1;
struct nk_rect total_space;
struct nk_panel popup;
struct nk_rect bounds;
int active_item = 0;
/* pie menu popup */
struct nk_color border = ctx->style.window.border_color;
struct nk_style_item background = ctx->style.window.fixed_background;
ctx->style.window.fixed_background = nk_style_item_hide();
ctx->style.window.border_color = nk_rgba(0,0,0,0);
total_space = nk_window_get_content_region(ctx);
nk_popup_begin(ctx, &popup, NK_POPUP_STATIC, "piemenu", NK_WINDOW_NO_SCROLLBAR,
nk_rect(pos.x - total_space.x - radius, pos.y - radius - total_space.y,
2*radius,2*radius));
total_space = nk_window_get_content_region(ctx);
nk_layout_row_dynamic(ctx, total_space.h, 1);
{
int i = 0;
struct nk_command_buffer* out = nk_window_get_canvas(ctx);
const struct nk_input *in = &ctx->input;
{
/* allocate complete popup space for the menu */
enum nk_widget_layout_states state;
total_space = nk_window_get_content_region(ctx);
total_space.x = total_space.y = 0;
state = nk_widget(&bounds, ctx);
}
/* outer circle */
nk_fill_circle(out, bounds, nk_rgb(50,50,50));
{
/* circle buttons */
float step = (2 * 3.141592654f) / (float)(MAX(1,item_count));
float a_min = 0; float a_max = step;
struct nk_vec2 center = nk_vec2(bounds.x + bounds.w / 2.0f, bounds.y + bounds.h / 2.0f);
struct nk_vec2 drag = nk_vec2(in->mouse.pos.x - center.x, in->mouse.pos.y - center.y);
float angle = (float)atan2(drag.y, drag.x);
if (angle < -0.0f) angle += 2.0f * 3.141592654f;
active_item = (int)(angle/step);
for (i = 0; i < item_count; ++i) {
struct nk_rect content;
float rx, ry, dx, dy, a;
nk_fill_arc(out, center.x, center.y, (bounds.w/2.0f),
a_min, a_max, (active_item == i) ? nk_rgb(45,100,255): nk_rgb(60,60,60));
/* seperator line */
rx = bounds.w/2.0f; ry = 0;
dx = rx * (float)cos(a_min) - ry * (float)sin(a_min);
dy = rx * (float)sin(a_min) + ry * (float)cos(a_min);
nk_stroke_line(out, center.x, center.y,
center.x + dx, center.y + dy, 1.0f, nk_rgb(50,50,50));
/* button content */
a = a_min + (a_max - a_min)/2.0f;
rx = bounds.w/2.5f; ry = 0;
content.w = 30; content.h = 30;
content.x = center.x + ((rx * (float)cos(a) - ry * (float)sin(a)) - content.w/2.0f);
content.y = center.y + (rx * (float)sin(a) + ry * (float)cos(a) - content.h/2.0f);
nk_draw_image(out, content, &icons[i]);
a_min = a_max; a_max += step;
}
}
{
/* inner circle */
struct nk_rect inner;
inner.x = bounds.x + bounds.w/2 - bounds.w/4;
inner.y = bounds.y + bounds.h/2 - bounds.h/4;
inner.w = bounds.w/2; inner.h = bounds.h/2;
nk_fill_circle(out, inner, nk_rgb(45,45,45));
/* active icon content */
bounds.w = inner.w / 2.0f;
bounds.h = inner.h / 2.0f;
bounds.x = inner.x + inner.w/2 - bounds.w/2;
bounds.y = inner.y + inner.h/2 - bounds.h/2;
nk_draw_image(out, bounds, &icons[active_item]);
}
}
nk_layout_space_end(ctx);
nk_popup_end(ctx);
ctx->style.window.fixed_background = background;
ctx->style.window.border_color = border;
if (!nk_input_is_mouse_down(&ctx->input, NK_BUTTON_RIGHT))
return active_item;
else return ret;
}
/* ===============================================================
*
* GRID
*
* ===============================================================*/
static void
grid_demo(struct nk_context *ctx)
{
static char text[3][64];
static int text_len[3];
static const char *items[] = {"Item 0","item 1","item 2"};
static int selected_item = 0;
static int check = 1;
struct nk_panel layout;
int i;
struct nk_panel combo;
ctx->style.font.height = 20;
if (nk_begin(ctx, &layout, "Grid Demo", nk_rect(600, 350, 275, 250),
NK_WINDOW_TITLE|NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|
NK_WINDOW_BORDER_HEADER|NK_WINDOW_NO_SCROLLBAR))
{
ctx->style.font.height = 18;
nk_layout_row_dynamic(ctx, 30, 2);
nk_label(ctx, "Floating point:", NK_TEXT_RIGHT);
nk_edit_string(ctx, NK_EDIT_FIELD, text[0], &text_len[0], 64, nk_filter_float);
nk_label(ctx, "Hexadeximal:", NK_TEXT_RIGHT);
nk_edit_string(ctx, NK_EDIT_FIELD, text[1], &text_len[1], 64, nk_filter_hex);
nk_label(ctx, "Binary:", NK_TEXT_RIGHT);
nk_edit_string(ctx, NK_EDIT_FIELD, text[2], &text_len[2], 64, nk_filter_binary);
nk_label(ctx, "Checkbox:", NK_TEXT_RIGHT);
nk_checkbox_label(ctx, "Check me", &check);
nk_label(ctx, "Combobox:", NK_TEXT_RIGHT);
if (nk_combo_begin_label(ctx, &combo, items[selected_item], 200)) {
nk_layout_row_dynamic(ctx, 30, 1);
for (i = 0; i < 3; ++i)
if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))
selected_item = i;
nk_combo_end(ctx);
}
}
nk_end(ctx);
ctx->style.font.height = 14;
}
/* ===============================================================
*
* BUTTON DEMO
*
* ===============================================================*/
static void
ui_header(struct nk_context *ctx, const char *title)
{
ctx->style.font.height = 18;
nk_layout_row_dynamic(ctx, 20, 1);
nk_label(ctx, title, NK_TEXT_LEFT);
}
static void
ui_widget(struct nk_context *ctx, float height, float font_height)
{
static const float ratio[] = {0.15f, 0.85f};
ctx->style.font.height = font_height;
nk_layout_row(ctx, NK_DYNAMIC, height, 2, ratio);
nk_spacing(ctx, 1);
}
static void
ui_widget_centered(struct nk_context *ctx, float height, float font_height)
{
static const float ratio[] = {0.15f, 0.50f, 0.35f};
ctx->style.font.height = font_height;
nk_layout_row(ctx, NK_DYNAMIC, height, 3, ratio);
nk_spacing(ctx, 1);
}
static void
button_demo(struct nk_context *ctx, struct icons *img)
{
struct nk_panel layout;
struct nk_panel menu;
static int option = 1;
static int toggle0 = 1;
static int toggle1 = 0;
static int toggle2 = 1;
ctx->style.font.height = 20;
nk_begin(ctx, &layout, "Button Demo", nk_rect(50,50,255,610),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_BORDER_HEADER|NK_WINDOW_TITLE);
/*------------------------------------------------
* MENU
*------------------------------------------------*/
nk_menubar_begin(ctx);
{
/* toolbar */
nk_layout_row_static(ctx, 40, 40, 4);
if (nk_menu_begin_image(ctx, &menu, "Music", img->play, 120))
{
/* settings */
nk_layout_row_dynamic(ctx, 25, 1);
nk_menu_item_image_label(ctx, img->play, "Play", NK_TEXT_RIGHT);
nk_menu_item_image_label(ctx, img->stop, "Stop", NK_TEXT_RIGHT);
nk_menu_item_image_label(ctx, img->pause, "Pause", NK_TEXT_RIGHT);
nk_menu_item_image_label(ctx, img->next, "Next", NK_TEXT_RIGHT);
nk_menu_item_image_label(ctx, img->prev, "Prev", NK_TEXT_RIGHT);
nk_menu_end(ctx);
}
nk_button_image(ctx, img->tools, NK_BUTTON_DEFAULT);
nk_button_image(ctx, img->cloud, NK_BUTTON_DEFAULT);
nk_button_image(ctx, img->pen, NK_BUTTON_DEFAULT);
}
nk_menubar_end(ctx);
/*------------------------------------------------
* BUTTON
*------------------------------------------------*/
ui_header(ctx, "Push buttons");
ui_widget(ctx, 35, 22);
if (nk_button_label(ctx, "Push me", NK_BUTTON_DEFAULT))
fprintf(stdout, "pushed!\n");
ui_widget(ctx, 35, 22);
if (nk_button_image_label(ctx, img->rocket, "Styled", NK_TEXT_CENTERED, NK_BUTTON_DEFAULT))
fprintf(stdout, "rocket!\n");
/*------------------------------------------------
* REPEATER
*------------------------------------------------*/
ui_header(ctx, "Repeater");
ui_widget(ctx, 35, 22);
if (nk_button_label(ctx, "Press me", NK_BUTTON_REPEATER))
fprintf(stdout, "pressed!\n");
/*------------------------------------------------
* TOGGLE
*------------------------------------------------*/
ui_header(ctx, "Toggle buttons");
ui_widget(ctx, 35, 22);
if (nk_button_image_label(ctx, (toggle0) ? img->checked: img->unchecked,
"Toggle", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) toggle0 = !toggle0;
ui_widget(ctx, 35, 22);
if (nk_button_image_label(ctx, (toggle1) ? img->checked: img->unchecked,
"Toggle", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) toggle1 = !toggle1;
ui_widget(ctx, 35, 22);
if (nk_button_image_label(ctx, (toggle2) ? img->checked: img->unchecked,
"Toggle", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) toggle2 = !toggle2;
/*------------------------------------------------
* RADIO
*------------------------------------------------*/
ui_header(ctx, "Radio buttons");
ui_widget(ctx, 35, 22);
if (nk_button_symbol_label(ctx, (option == 0)?NK_SYMBOL_CIRCLE_FILLED:NK_SYMBOL_CIRCLE,
"Select", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) option = 0;
ui_widget(ctx, 35, 22);
if (nk_button_symbol_label(ctx, (option == 1)?NK_SYMBOL_CIRCLE_FILLED:NK_SYMBOL_CIRCLE,
"Select", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) option = 1;
ui_widget(ctx, 35, 22);
if (nk_button_symbol_label(ctx, (option == 2)?NK_SYMBOL_CIRCLE_FILLED:NK_SYMBOL_CIRCLE,
"Select", NK_TEXT_LEFT, NK_BUTTON_DEFAULT)) option = 2;
/*------------------------------------------------
* CONTEXTUAL
*------------------------------------------------*/
if (nk_contextual_begin(ctx, &menu, NK_WINDOW_NO_SCROLLBAR, nk_vec2(120, 200), nk_window_get_bounds(ctx))) {
ctx->style.font.height = 18;
nk_layout_row_dynamic(ctx, 25, 1);
if (nk_contextual_item_image_label(ctx, img->copy, "Clone", NK_TEXT_RIGHT))
fprintf(stdout, "pressed clone!\n");
if (nk_contextual_item_image_label(ctx, img->del, "Delete", NK_TEXT_RIGHT))
fprintf(stdout, "pressed delete!\n");
if (nk_contextual_item_image_label(ctx, img->convert, "Convert", NK_TEXT_RIGHT))
fprintf(stdout, "pressed convert!\n");
if (nk_contextual_item_image_label(ctx, img->edit, "Edit", NK_TEXT_RIGHT))
fprintf(stdout, "pressed edit!\n");
nk_contextual_end(ctx);
}
ctx->style.font.height = 14;
nk_end(ctx);
}
/* ===============================================================
*
* BASIC DEMO
*
* ===============================================================*/
static void
basic_demo(struct nk_context *ctx, struct icons *img)
{
static int image_active;
static int check0 = 1;
static int check1 = 0;
static size_t prog = 80;
static int selected_item = 0;
static int selected_image = 3;
static int selected_icon = 0;
static const char *items[] = {"Item 0","item 1","item 2"};
static int piemenu_active = 0;
static struct nk_vec2 piemenu_pos;
int i = 0;
struct nk_panel layout;
struct nk_panel combo;
ctx->style.font.height = 20;
nk_begin(ctx, &layout, "Basic Demo", nk_rect(320, 50, 275, 610),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_BORDER_HEADER|NK_WINDOW_TITLE);
/*------------------------------------------------
* POPUP BUTTON
*------------------------------------------------*/
ui_header(ctx, "Popup & Scrollbar & Images");
ui_widget(ctx, 35, 22);
if (nk_button_image_label(ctx, img->dir,
"Images", NK_TEXT_CENTERED, NK_BUTTON_DEFAULT))
image_active = !image_active;
/*------------------------------------------------
* SELECTED IMAGE
*------------------------------------------------*/
ui_header(ctx, "Selected Image");
ui_widget_centered(ctx, 100, 22);
nk_image(ctx, img->images[selected_image]);
/*------------------------------------------------
* IMAGE POPUP
*------------------------------------------------*/
if (image_active) {
struct nk_panel popup;
if (nk_popup_begin(ctx, &popup, NK_POPUP_STATIC, "Image Popup", 0, nk_rect(265, 0, 320, 220))) {
nk_layout_row_static(ctx, 82, 82, 3);
for (i = 0; i < 9; ++i) {
if (nk_button_image(ctx, img->images[i], NK_BUTTON_DEFAULT)) {
selected_image = i;
image_active = 0;
nk_popup_close(ctx);
}
}
nk_popup_end(ctx);
}
}
/*------------------------------------------------
* COMBOBOX
*------------------------------------------------*/
ui_header(ctx, "Combo box");
ui_widget(ctx, 40, 22);
if (nk_combo_begin_label(ctx, &combo, items[selected_item], 200)) {
nk_layout_row_dynamic(ctx, 35, 1);
for (i = 0; i < 3; ++i)
if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))
selected_item = i;
nk_combo_end(ctx);
}
ui_widget(ctx, 40, 22);
if (nk_combo_begin_image_label(ctx, &combo, items[selected_icon], img->images[selected_icon], 200)) {
nk_layout_row_dynamic(ctx, 35, 1);
for (i = 0; i < 3; ++i)
if (nk_combo_item_image_label(ctx, img->images[i], items[i], NK_TEXT_RIGHT))
selected_icon = i;
nk_combo_end(ctx);
}
/*------------------------------------------------
* CHECKBOX
*------------------------------------------------*/
ui_header(ctx, "Checkbox");
ui_widget(ctx, 30, 22);
nk_checkbox_label(ctx, "Flag 1", &check0);
ui_widget(ctx, 30, 22);
nk_checkbox_label(ctx, "Flag 2", &check1);
/*------------------------------------------------
* PROGRESSBAR
*------------------------------------------------*/
ui_header(ctx, "Progressbar");
ui_widget(ctx, 35, 22);
nk_progress(ctx, &prog, 100, nk_true);
/*------------------------------------------------
* PIEMENU
*------------------------------------------------*/
if (nk_input_is_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_RIGHT,
layout.bounds,nk_true)){
piemenu_pos = ctx->input.mouse.pos;
piemenu_active = 1;
}
if (piemenu_active) {
int ret = ui_piemenu(ctx, piemenu_pos, 140, &img->menu[0], 6);
if (ret != -1) {
fprintf(stdout, "piemenu selected: %d\n", ret);
piemenu_active = 0;
}
}
ctx->style.font.height = 14;
nk_end(ctx);
}
/* ===============================================================
*
* DEVICE
*
* ===============================================================*/
struct device {
struct nk_buffer cmds;
struct nk_draw_null_texture null;
GLuint vbo, vao, ebo;
GLuint prog;
GLuint vert_shdr;
GLuint frag_shdr;
GLint attrib_pos;
GLint attrib_uv;
GLint attrib_col;
GLint uniform_tex;
GLint uniform_proj;
GLuint font_tex;
};
static void
die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputs("\n", stderr);
exit(EXIT_FAILURE);
}
static struct nk_image
icon_load(const char *filename)
{
int x,y,n;
GLuint tex;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
if (!data) die("[SDL]: failed to load image: %s", filename);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
return nk_image_id((int)tex);
}
static void
device_init(struct device *dev)
{
GLint status;
static const GLchar *vertex_shader =
"#version 300 es\n"
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main() {\n"
" Frag_UV = TexCoord;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
static const GLchar *fragment_shader =
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
nk_buffer_init_default(&dev->cmds);
dev->prog = glCreateProgram();
dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
glCompileShader(dev->vert_shdr);
glCompileShader(dev->frag_shdr);
glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glAttachShader(dev->prog, dev->vert_shdr);
glAttachShader(dev->prog, dev->frag_shdr);
glLinkProgram(dev->prog);
glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
assert(status == GL_TRUE);
dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
{
/* buffer setup */
GLsizei vs = sizeof(struct nk_draw_vertex);
size_t vp = offsetof(struct nk_draw_vertex, position);
size_t vt = offsetof(struct nk_draw_vertex, uv);
size_t vc = offsetof(struct nk_draw_vertex, col);
glGenBuffers(1, &dev->vbo);
glGenBuffers(1, &dev->ebo);
glGenVertexArrays(1, &dev->vao);
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glEnableVertexAttribArray((GLuint)dev->attrib_pos);
glEnableVertexAttribArray((GLuint)dev->attrib_uv);
glEnableVertexAttribArray((GLuint)dev->attrib_col);
glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
static void
device_upload_atlas(struct device *dev, const void *image, int width, int height)
{
glGenTextures(1, &dev->font_tex);
glBindTexture(GL_TEXTURE_2D, dev->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image);
}
static void
device_shutdown(struct device *dev)
{
glDetachShader(dev->prog, dev->vert_shdr);
glDetachShader(dev->prog, dev->frag_shdr);
glDeleteShader(dev->vert_shdr);
glDeleteShader(dev->frag_shdr);
glDeleteProgram(dev->prog);
glDeleteTextures(1, &dev->font_tex);
glDeleteBuffers(1, &dev->vbo);
glDeleteBuffers(1, &dev->ebo);
nk_buffer_free(&dev->cmds);
}
static void
device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
enum nk_anti_aliasing AA)
{
GLint last_prog, last_tex;
GLint last_ebo, last_vbo, last_vao;
GLfloat ortho[4][4] = {
{2.0f, 0.0f, 0.0f, 0.0f},
{0.0f,-2.0f, 0.0f, 0.0f},
{0.0f, 0.0f,-1.0f, 0.0f},
{-1.0f,1.0f, 0.0f, 1.0f},
};
ortho[0][0] /= (GLfloat)width;
ortho[1][1] /= (GLfloat)height;
/* save previous opengl state */
glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
/* setup global state */
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
/* setup program */
glUseProgram(dev->prog);
glUniform1i(dev->uniform_tex, 0);
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
{
/* convert from command queue into draw list and draw to screen */
const struct nk_draw_command *cmd;
void *vertices, *elements;
const nk_draw_index *offset = NULL;
/* allocate vertex and element buffer */
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
/* load draw vertices & elements directly into vertex + element buffer */
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
{
/* fill converting configuration */
struct nk_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.curve_segment_count = 22;
config.arc_segment_count = 22;
config.null = dev->null;
/* setup buffers to load vertices and elements */
{struct nk_buffer vbuf, ebuf;
nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
/* iterate over and execute each draw command */
nk_draw_foreach(cmd, ctx, &dev->cmds) {
if (!cmd->elem_count) continue;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)cmd->clip_rect.x,
height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
(GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
nk_clear(ctx);
}
/* restore old state */
glUseProgram((GLuint)last_prog);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
glBindVertexArray((GLuint)last_vao);
glDisable(GL_SCISSOR_TEST);
}
/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
static void text_input(GLFWwindow *win, unsigned int codepoint)
{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
static void scroll_input(GLFWwindow *win, double _, double yoff)
{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
int main(int argc, char *argv[])
{
/* Platform */
static GLFWwindow *win;
int width = 0, height = 0;
/* GUI */
struct device device;
struct nk_font *font;
struct nk_font_atlas atlas;
struct icons icons;
struct nk_context ctx;
/* GLFW */
glfwSetErrorCallback(error_callback);
if (!glfwInit()) {
fprintf(stdout, "[GFLW] failed to init!\n");
exit(1);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
glfwMakeContextCurrent(win);
glfwSetWindowUserPointer(win, &ctx);
glfwSetCharCallback(win, text_input);
glfwSetScrollCallback(win, scroll_input);
/* OpenGL */
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glewExperimental = 1;
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to setup GLEW\n");
exit(1);
}
{/* GUI */
device_init(&device);
{const void *image; int w, h;
const char *font_path = (argc > 1) ? argv[1]: 0;
nk_font_atlas_init_default(&atlas);
nk_font_atlas_begin(&atlas);
if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
else font = nk_font_atlas_add_default(&atlas, 14.0f, NULL);
image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
device_upload_atlas(&device, image, w, h);
nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);}
nk_init_default(&ctx, &font->handle);}
/* icons */
glEnable(GL_TEXTURE_2D);
icons.unchecked = icon_load("../icon/unchecked.png");
icons.checked = icon_load("../icon/checked.png");
icons.rocket = icon_load("../icon/rocket.png");
icons.cloud = icon_load("../icon/cloud.png");
icons.pen = icon_load("../icon/pen.png");
icons.play = icon_load("../icon/play.png");
icons.pause = icon_load("../icon/pause.png");
icons.stop = icon_load("../icon/stop.png");
icons.next = icon_load("../icon/next.png");
icons.prev = icon_load("../icon/prev.png");
icons.tools = icon_load("../icon/tools.png");
icons.dir = icon_load("../icon/directory.png");
icons.copy = icon_load("../icon/copy.png");
icons.convert = icon_load("../icon/export.png");
icons.del = icon_load("../icon/delete.png");
icons.edit = icon_load("../icon/edit.png");
icons.menu[0] = icon_load("../icon/home.png");
icons.menu[1] = icon_load("../icon/phone.png");
icons.menu[2] = icon_load("../icon/plane.png");
icons.menu[3] = icon_load("../icon/wifi.png");
icons.menu[4] = icon_load("../icon/settings.png");
icons.menu[5] = icon_load("../icon/volume.png");
{int i;
for (i = 0; i < 9; ++i) {
char buffer[256];
sprintf(buffer, "../images/image%d.png", (i+1));
icons.images[i] = icon_load(buffer);
}}
while (!glfwWindowShouldClose(win))
{
/* Input */
{double x, y;
nk_input_begin(&ctx);
glfwPollEvents();
nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) {
nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_SHIFT, 1);
} else {
nk_input_key(&ctx, NK_KEY_COPY, 0);
nk_input_key(&ctx, NK_KEY_PASTE, 0);
nk_input_key(&ctx, NK_KEY_CUT, 0);
nk_input_key(&ctx, NK_KEY_SHIFT, 0);
}
glfwGetCursorPos(win, &x, &y);
nk_input_motion(&ctx, (int)x, (int)y);
nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
nk_input_end(&ctx);}
/* GUI */
basic_demo(&ctx, &icons);
button_demo(&ctx, &icons);
grid_demo(&ctx);
/* Draw */
glfwGetWindowSize(win, &width, &height);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON);
glfwSwapBuffers(win);
}
glDeleteTextures(1,(const GLuint*)&icons.unchecked.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.checked.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.rocket.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.cloud.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.pen.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.play.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.pause.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.stop.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.next.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.prev.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.tools.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.dir.handle.id);
glDeleteTextures(1,(const GLuint*)&icons.del.handle.id);
nk_font_atlas_clear(&atlas);
nk_free(&ctx);
device_shutdown(&device);
glfwTerminate();
return 0;
}

889
example/file_browser.c Normal file
View File

@ -0,0 +1,889 @@
/* nuklear - v1.00 - public domain */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include <limits.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GLFW/glfw3.h>
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#include "../nuklear.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
/* macros */
#define WINDOW_WIDTH 1200
#define WINDOW_HEIGHT 800
#define MAX_VERTEX_MEMORY 512 * 1024
#define MAX_ELEMENT_MEMORY 128 * 1024
#define UNUSED(a) (void)a
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) < (b) ? (b) : (a))
#define LEN(a) (sizeof(a)/sizeof(a)[0])
/* ===============================================================
*
* GUI
*
* ===============================================================*/
struct icons {
struct nk_image desktop;
struct nk_image home;
struct nk_image computer;
struct nk_image directory;
struct nk_image default_file;
struct nk_image text_file;
struct nk_image music_file;
struct nk_image font_file;
struct nk_image img_file;
struct nk_image movie_file;
};
enum file_groups {
FILE_GROUP_DEFAULT,
FILE_GROUP_TEXT,
FILE_GROUP_MUSIC,
FILE_GROUP_FONT,
FILE_GROUP_IMAGE,
FILE_GROUP_MOVIE,
FILE_GROUP_MAX
};
enum file_types {
FILE_DEFAULT,
FILE_TEXT,
FILE_C_SOURCE,
FILE_CPP_SOURCE,
FILE_HEADER,
FILE_CPP_HEADER,
FILE_MP3,
FILE_WAV,
FILE_OGG,
FILE_TTF,
FILE_BMP,
FILE_PNG,
FILE_JPEG,
FILE_PCX,
FILE_TGA,
FILE_GIF,
FILE_MAX
};
struct file_group {
enum file_groups group;
const char *name;
struct nk_image *icon;
};
struct file {
enum file_types type;
const char *suffix;
enum file_groups group;
};
struct media {
int font;
int icon_sheet;
struct icons icons;
struct file_group group[FILE_GROUP_MAX];
struct file files[FILE_MAX];
};
#define MAX_PATH_LEN 512
struct file_browser {
/* path */
char file[MAX_PATH_LEN];
char home[MAX_PATH_LEN];
char desktop[MAX_PATH_LEN];
char directory[MAX_PATH_LEN];
/* directory content */
char **files;
char **directories;
size_t file_count;
size_t dir_count;
struct media *media;
};
#ifdef __unix__
#include <dirent.h>
#include <unistd.h>
#endif
#ifndef _WIN32
# include <pwd.h>
#endif
static void
die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputs("\n", stderr);
exit(EXIT_FAILURE);
}
static char*
file_load(const char* path, size_t* siz)
{
char *buf;
FILE *fd = fopen(path, "rb");
if (!fd) die("Failed to open file: %s\n", path);
fseek(fd, 0, SEEK_END);
*siz = (size_t)ftell(fd);
fseek(fd, 0, SEEK_SET);
buf = (char*)calloc(*siz, 1);
fread(buf, *siz, 1, fd);
fclose(fd);
return buf;
}
static char*
str_duplicate(const char *src)
{
char *ret;
size_t len = strlen(src);
if (!len) return 0;
ret = (char*)malloc(len+1);
if (!ret) return 0;
memcpy(ret, src, len);
ret[len] = '\0';
return ret;
}
static void
dir_free_list(char **list, size_t size)
{
size_t i;
for (i = 0; i < size; ++i)
free(list[i]);
free(list);
}
static char**
dir_list(const char *dir, int return_subdirs, size_t *count)
{
size_t n = 0;
char buffer[MAX_PATH_LEN];
char **results = NULL;
const DIR *none = NULL;
size_t capacity = 32;
size_t size;
DIR *z;
assert(dir);
assert(count);
strncpy(buffer, dir, MAX_PATH_LEN);
n = strlen(buffer);
if (n > 0 && (buffer[n-1] != '/'))
buffer[n++] = '/';
size = 0;
z = opendir(dir);
if (z != none) {
int nonempty = 1;
struct dirent *data = readdir(z);
nonempty = (data != NULL);
if (!nonempty) return NULL;
do {
DIR *y;
char *p;
int is_subdir;
if (data->d_name[0] == '.')
continue;
strncpy(buffer + n, data->d_name, MAX_PATH_LEN-n);
y = opendir(buffer);
is_subdir = (y != NULL);
if (y != NULL) closedir(y);
if ((return_subdirs && is_subdir) || (!is_subdir && !return_subdirs)){
if (!size) {
results = (char**)calloc(sizeof(char*), capacity);
} else if (size >= capacity) {
capacity = capacity * 2;
results = (char**)realloc(results, capacity * sizeof(char*));
}
p = str_duplicate(data->d_name);
results[size++] = p;
}
} while ((data = readdir(z)) != NULL);
}
if (z) closedir(z);
*count = size;
return results;
}
static struct file_group
FILE_GROUP(enum file_groups group, const char *name, struct nk_image *icon)
{
struct file_group fg;
fg.group = group;
fg.name = name;
fg.icon = icon;
return fg;
}
static struct file
FILE_DEF(enum file_types type, const char *suffix, enum file_groups group)
{
struct file fd;
fd.type = type;
fd.suffix = suffix;
fd.group = group;
return fd;
}
static struct nk_image*
media_icon_for_file(struct media *media, const char *file)
{
int i = 0;
const char *s = file;
char suffix[4];
int found = 0;
memset(suffix, 0, sizeof(suffix));
/* extract suffix .xxx from file */
while (*s++ != '\0') {
if (found && i < 3)
suffix[i++] = *s;
if (*s == '.') {
if (found){
found = 0;
break;
}
found = 1;
}
}
/* check for all file definition of all groups for fitting suffix*/
for (i = 0; i < FILE_MAX && found; ++i) {
struct file *d = &media->files[i];
{
const char *f = d->suffix;
s = suffix;
while (f && *f && *s && *s == *f) {
s++; f++;
}
/* found correct file definition so */
if (f && *s == '\0' && *f == '\0')
return media->group[d->group].icon;
}
}
return &media->icons.default_file;
}
static void
media_init(struct media *media)
{
/* file groups */
struct icons *icons = &media->icons;
media->group[FILE_GROUP_DEFAULT] = FILE_GROUP(FILE_GROUP_DEFAULT,"default",&icons->default_file);
media->group[FILE_GROUP_TEXT] = FILE_GROUP(FILE_GROUP_TEXT, "textual", &icons->text_file);
media->group[FILE_GROUP_MUSIC] = FILE_GROUP(FILE_GROUP_MUSIC, "music", &icons->music_file);
media->group[FILE_GROUP_FONT] = FILE_GROUP(FILE_GROUP_FONT, "font", &icons->font_file);
media->group[FILE_GROUP_IMAGE] = FILE_GROUP(FILE_GROUP_IMAGE, "image", &icons->img_file);
media->group[FILE_GROUP_MOVIE] = FILE_GROUP(FILE_GROUP_MOVIE, "movie", &icons->movie_file);
/* files */
media->files[FILE_DEFAULT] = FILE_DEF(FILE_DEFAULT, NULL, FILE_GROUP_DEFAULT);
media->files[FILE_TEXT] = FILE_DEF(FILE_TEXT, "txt", FILE_GROUP_TEXT);
media->files[FILE_C_SOURCE] = FILE_DEF(FILE_C_SOURCE, "c", FILE_GROUP_TEXT);
media->files[FILE_CPP_SOURCE] = FILE_DEF(FILE_CPP_SOURCE, "cpp", FILE_GROUP_TEXT);
media->files[FILE_HEADER] = FILE_DEF(FILE_HEADER, "h", FILE_GROUP_TEXT);
media->files[FILE_CPP_HEADER] = FILE_DEF(FILE_HEADER, "hpp", FILE_GROUP_TEXT);
media->files[FILE_MP3] = FILE_DEF(FILE_MP3, "mp3", FILE_GROUP_MUSIC);
media->files[FILE_WAV] = FILE_DEF(FILE_WAV, "wav", FILE_GROUP_MUSIC);
media->files[FILE_OGG] = FILE_DEF(FILE_OGG, "ogg", FILE_GROUP_MUSIC);
media->files[FILE_TTF] = FILE_DEF(FILE_TTF, "ttf", FILE_GROUP_FONT);
media->files[FILE_BMP] = FILE_DEF(FILE_BMP, "bmp", FILE_GROUP_IMAGE);
media->files[FILE_PNG] = FILE_DEF(FILE_PNG, "png", FILE_GROUP_IMAGE);
media->files[FILE_JPEG] = FILE_DEF(FILE_JPEG, "jpg", FILE_GROUP_IMAGE);
media->files[FILE_PCX] = FILE_DEF(FILE_PCX, "pcx", FILE_GROUP_IMAGE);
media->files[FILE_TGA] = FILE_DEF(FILE_TGA, "tga", FILE_GROUP_IMAGE);
media->files[FILE_GIF] = FILE_DEF(FILE_GIF, "gif", FILE_GROUP_IMAGE);
}
static void
file_browser_reload_directory_content(struct file_browser *browser, const char *path)
{
strncpy(browser->directory, path, MAX_PATH_LEN);
dir_free_list(browser->files, browser->file_count);
dir_free_list(browser->directories, browser->dir_count);
browser->files = dir_list(path, 0, &browser->file_count);
browser->directories = dir_list(path, 1, &browser->dir_count);
}
static void
file_browser_init(struct file_browser *browser, struct media *media)
{
memset(browser, 0, sizeof(*browser));
browser->media = media;
{
/* load files and sub-directory list */
const char *home = getenv("HOME");
#ifdef _WIN32
if (!home) home = getenv("USERPROFILE");
#else
if (!home) home = getpwuid(getuid())->pw_dir;
{
size_t l;
strncpy(browser->home, home, MAX_PATH_LEN);
l = strlen(browser->home);
strcpy(browser->home + l, "/");
strcpy(browser->directory, browser->home);
}
#endif
{
size_t l;
strcpy(browser->desktop, browser->home);
l = strlen(browser->desktop);
strcpy(browser->desktop + l, "desktop/");
}
browser->files = dir_list(browser->directory, 0, &browser->file_count);
browser->directories = dir_list(browser->directory, 1, &browser->dir_count);
}
}
static void
file_browser_free(struct file_browser *browser)
{
if (browser->files)
dir_free_list(browser->files, browser->file_count);
if (browser->directories)
dir_free_list(browser->directories, browser->dir_count);
browser->files = NULL;
browser->directories = NULL;
memset(browser, 0, sizeof(*browser));
}
static int
file_browser_run(struct file_browser *browser, struct nk_context *ctx)
{
int ret = 0;
struct nk_panel layout;
struct media *media = browser->media;
struct nk_rect total_space;
if (nk_begin(ctx, &layout, "File Browser", nk_rect(50, 50, 800, 600),
NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_CLOSABLE|NK_WINDOW_MOVABLE))
{
struct nk_panel sub;
static float ratio[] = {0.25f, NK_UNDEFINED};
float spacing_x = ctx->style.window.spacing.x;
/* output path directory selector in the menubar */
ctx->style.window.spacing.x = 0;
nk_menubar_begin(ctx);
{
char *d = browser->directory;
char *begin = d + 1;
nk_layout_row_dynamic(ctx, 25, 6);
while (*d++) {
if (*d == '/') {
*d = '\0';
if (nk_button_label(ctx, begin, NK_BUTTON_DEFAULT)) {
*d++ = '/'; *d = '\0';
file_browser_reload_directory_content(browser, browser->directory);
break;
}
*d = '/';
begin = d + 1;
}
}
}
nk_menubar_end(ctx);
ctx->style.window.spacing.x = spacing_x;
/* window layout */
total_space = nk_window_get_content_region(ctx);
nk_layout_row(ctx, NK_DYNAMIC, total_space.h, 2, ratio);
nk_group_begin(ctx, &sub, "Special", NK_WINDOW_NO_SCROLLBAR);
{
struct nk_image home = media->icons.home;
struct nk_image desktop = media->icons.desktop;
struct nk_image computer = media->icons.computer;
nk_layout_row_dynamic(ctx, 40, 1);
if (nk_button_image_label(ctx, home, "home", NK_TEXT_CENTERED, NK_BUTTON_DEFAULT))
file_browser_reload_directory_content(browser, browser->home);
if (nk_button_image_label(ctx,desktop,"desktop",NK_TEXT_CENTERED, NK_BUTTON_DEFAULT))
file_browser_reload_directory_content(browser, browser->desktop);
if (nk_button_image_label(ctx,computer,"computer",NK_TEXT_CENTERED,NK_BUTTON_DEFAULT))
file_browser_reload_directory_content(browser, "/");
nk_group_end(ctx);
}
/* output directory content window */
nk_group_begin(ctx, &sub, "Content", 0);
{
int index = -1;
size_t i = 0, j = 0, k = 0;
size_t rows = 0, cols = 0;
size_t count = browser->dir_count + browser->file_count;
cols = 4;
rows = count / cols;
for (i = 0; i <= rows; i += 1) {
{size_t n = j + cols;
nk_layout_row_dynamic(ctx, 135, (int)cols);
for (; j < count && j < n; ++j) {
/* draw one row of icons */
if (j < browser->dir_count) {
/* draw and execute directory buttons */
if (nk_button_image(ctx,media->icons.directory,NK_BUTTON_DEFAULT))
index = (int)j;
} else {
/* draw and execute files buttons */
struct nk_image *icon;
size_t fileIndex = ((size_t)j - browser->dir_count);
icon = media_icon_for_file(media,browser->files[fileIndex]);
if (nk_button_image(ctx, *icon, NK_BUTTON_DEFAULT)) {
strncpy(browser->file, browser->directory, MAX_PATH_LEN);
n = strlen(browser->file);
strncpy(browser->file + n, browser->files[fileIndex], MAX_PATH_LEN - n);
ret = 1;
}
}
}}
{size_t n = k + cols;
nk_layout_row_dynamic(ctx, 20, (int)cols);
for (; k < count && k < n; k++) {
/* draw one row of labels */
if (k < browser->dir_count) {
nk_label(ctx, browser->directories[k], NK_TEXT_CENTERED);
} else {
size_t t = k-browser->dir_count;
nk_label(ctx,browser->files[t],NK_TEXT_CENTERED);
}
}}
}
if (index != -1) {
size_t n = strlen(browser->directory);
strncpy(browser->directory + n, browser->directories[index], MAX_PATH_LEN - n);
n = strlen(browser->directory);
if (n < MAX_PATH_LEN - 1) {
browser->directory[n] = '/';
browser->directory[n+1] = '\0';
}
file_browser_reload_directory_content(browser, browser->directory);
sub.offset->y = 0;
}
nk_group_end(ctx);
}
}
nk_end(ctx);
return ret;
}
/* ===============================================================
*
* DEVICE
*
* ===============================================================*/
struct device {
struct nk_buffer cmds;
struct nk_draw_null_texture null;
GLuint vbo, vao, ebo;
GLuint prog;
GLuint vert_shdr;
GLuint frag_shdr;
GLint attrib_pos;
GLint attrib_uv;
GLint attrib_col;
GLint uniform_tex;
GLint uniform_proj;
GLuint font_tex;
};
static struct nk_image
icon_load(const char *filename)
{
int x,y,n;
GLuint tex;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
if (!data) die("[SDL]: failed to load image: %s", filename);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
return nk_image_id((int)tex);
}
static void
device_init(struct device *dev)
{
GLint status;
static const GLchar *vertex_shader =
"#version 300 es\n"
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main() {\n"
" Frag_UV = TexCoord;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
static const GLchar *fragment_shader =
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
nk_buffer_init_default(&dev->cmds);
dev->prog = glCreateProgram();
dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
glCompileShader(dev->vert_shdr);
glCompileShader(dev->frag_shdr);
glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glAttachShader(dev->prog, dev->vert_shdr);
glAttachShader(dev->prog, dev->frag_shdr);
glLinkProgram(dev->prog);
glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
assert(status == GL_TRUE);
dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
{
/* buffer setup */
GLsizei vs = sizeof(struct nk_draw_vertex);
size_t vp = offsetof(struct nk_draw_vertex, position);
size_t vt = offsetof(struct nk_draw_vertex, uv);
size_t vc = offsetof(struct nk_draw_vertex, col);
glGenBuffers(1, &dev->vbo);
glGenBuffers(1, &dev->ebo);
glGenVertexArrays(1, &dev->vao);
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glEnableVertexAttribArray((GLuint)dev->attrib_pos);
glEnableVertexAttribArray((GLuint)dev->attrib_uv);
glEnableVertexAttribArray((GLuint)dev->attrib_col);
glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
static void
device_upload_atlas(struct device *dev, const void *image, int width, int height)
{
glGenTextures(1, &dev->font_tex);
glBindTexture(GL_TEXTURE_2D, dev->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image);
}
static void
device_shutdown(struct device *dev)
{
glDetachShader(dev->prog, dev->vert_shdr);
glDetachShader(dev->prog, dev->frag_shdr);
glDeleteShader(dev->vert_shdr);
glDeleteShader(dev->frag_shdr);
glDeleteProgram(dev->prog);
glDeleteTextures(1, &dev->font_tex);
glDeleteBuffers(1, &dev->vbo);
glDeleteBuffers(1, &dev->ebo);
nk_buffer_free(&dev->cmds);
}
static void
device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
enum nk_anti_aliasing AA)
{
GLint last_prog, last_tex;
GLint last_ebo, last_vbo, last_vao;
GLfloat ortho[4][4] = {
{2.0f, 0.0f, 0.0f, 0.0f},
{0.0f,-2.0f, 0.0f, 0.0f},
{0.0f, 0.0f,-1.0f, 0.0f},
{-1.0f,1.0f, 0.0f, 1.0f},
};
ortho[0][0] /= (GLfloat)width;
ortho[1][1] /= (GLfloat)height;
/* save previous opengl state */
glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
/* setup global state */
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
/* setup program */
glUseProgram(dev->prog);
glUniform1i(dev->uniform_tex, 0);
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
{
/* convert from command queue into draw list and draw to screen */
const struct nk_draw_command *cmd;
void *vertices, *elements;
const nk_draw_index *offset = NULL;
/* allocate vertex and element buffer */
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
/* load draw vertices & elements directly into vertex + element buffer */
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
{
/* fill converting configuration */
struct nk_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.curve_segment_count = 22;
config.arc_segment_count = 22;
config.null = dev->null;
/* setup buffers to load vertices and elements */
{struct nk_buffer vbuf, ebuf;
nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
/* iterate over and execute each draw command */
nk_draw_foreach(cmd, ctx, &dev->cmds) {
if (!cmd->elem_count) continue;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)cmd->clip_rect.x,
height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
(GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
nk_clear(ctx);
}
/* restore old state */
glUseProgram((GLuint)last_prog);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
glBindVertexArray((GLuint)last_vao);
glDisable(GL_SCISSOR_TEST);
}
/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
static void text_input(GLFWwindow *win, unsigned int codepoint)
{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
static void scroll_input(GLFWwindow *win, double _, double yoff)
{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
int main(int argc, char *argv[])
{
/* Platform */
static GLFWwindow *win;
int width = 0, height = 0;
/* GUI */
struct device device;
struct nk_context ctx;
struct nk_font *font;
struct nk_font_atlas atlas;
struct file_browser browser;
struct media media;
/* GLFW */
glfwSetErrorCallback(error_callback);
if (!glfwInit()) {
fprintf(stdout, "[GFLW] failed to init!\n");
exit(1);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
glfwMakeContextCurrent(win);
glfwSetWindowUserPointer(win, &ctx);
glfwSetCharCallback(win, text_input);
glfwSetScrollCallback(win, scroll_input);
/* OpenGL */
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glewExperimental = 1;
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to setup GLEW\n");
exit(1);
}
{/* GUI */
device_init(&device);
{const void *image; int w, h;
const char *font_path = (argc > 1) ? argv[1]: 0;
nk_font_atlas_init_default(&atlas);
nk_font_atlas_begin(&atlas);
if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
else font = nk_font_atlas_add_default(&atlas, 14.0f, NULL);
image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
device_upload_atlas(&device, image, w, h);
nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);}
nk_init_default(&ctx, &font->handle);}
/* icons */
glEnable(GL_TEXTURE_2D);
media.icons.home = icon_load("../icon/home.png");
media.icons.directory = icon_load("../icon/directory.png");
media.icons.computer = icon_load("../icon/computer.png");
media.icons.desktop = icon_load("../icon/desktop.png");
media.icons.default_file = icon_load("../icon/default.png");
media.icons.text_file = icon_load("../icon/text.png");
media.icons.music_file = icon_load("../icon/music.png");
media.icons.font_file = icon_load("../icon/font.png");
media.icons.img_file = icon_load("../icon/img.png");
media.icons.movie_file = icon_load("../icon/movie.png");
media_init(&media);
file_browser_init(&browser, &media);
while (!glfwWindowShouldClose(win))
{
/* Input */
{double x, y;
nk_input_begin(&ctx);
glfwPollEvents();
nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) {
nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_SHIFT, 1);
} else {
nk_input_key(&ctx, NK_KEY_COPY, 0);
nk_input_key(&ctx, NK_KEY_PASTE, 0);
nk_input_key(&ctx, NK_KEY_CUT, 0);
nk_input_key(&ctx, NK_KEY_SHIFT, 0);
}
glfwGetCursorPos(win, &x, &y);
nk_input_motion(&ctx, (int)x, (int)y);
nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
nk_input_end(&ctx);}
/* GUI */
file_browser_run(&browser, &ctx);
/* Draw */
glfwGetWindowSize(win, &width, &height);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON);
glfwSwapBuffers(win);
}
glDeleteTextures(1,(const GLuint*)&media.icons.home.handle.id);
glDeleteTextures(1,(const GLuint*)&media.icons.directory.handle.id);
glDeleteTextures(1,(const GLuint*)&media.icons.computer.handle.id);
glDeleteTextures(1,(const GLuint*)&media.icons.desktop.handle.id);
glDeleteTextures(1,(const GLuint*)&media.icons.default_file.handle.id);
glDeleteTextures(1,(const GLuint*)&media.icons.text_file.handle.id);
glDeleteTextures(1,(const GLuint*)&media.icons.music_file.handle.id);
glDeleteTextures(1,(const GLuint*)&media.icons.font_file.handle.id);
glDeleteTextures(1,(const GLuint*)&media.icons.img_file.handle.id);
glDeleteTextures(1,(const GLuint*)&media.icons.movie_file.handle.id);
file_browser_free(&browser);
nk_font_atlas_clear(&atlas);
nk_free(&ctx);
device_shutdown(&device);
glfwTerminate();
return 0;
}

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 620 B

After

Width:  |  Height:  |  Size: 620 B

View File

Before

Width:  |  Height:  |  Size: 655 B

After

Width:  |  Height:  |  Size: 655 B

View File

Before

Width:  |  Height:  |  Size: 460 B

After

Width:  |  Height:  |  Size: 460 B

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 583 B

After

Width:  |  Height:  |  Size: 583 B

View File

Before

Width:  |  Height:  |  Size: 533 B

After

Width:  |  Height:  |  Size: 533 B

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 561 B

After

Width:  |  Height:  |  Size: 561 B

View File

Before

Width:  |  Height:  |  Size: 819 B

After

Width:  |  Height:  |  Size: 819 B

View File

Before

Width:  |  Height:  |  Size: 648 B

After

Width:  |  Height:  |  Size: 648 B

View File

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 626 B

View File

Before

Width:  |  Height:  |  Size: 610 B

After

Width:  |  Height:  |  Size: 610 B

View File

Before

Width:  |  Height:  |  Size: 703 B

After

Width:  |  Height:  |  Size: 703 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 566 B

After

Width:  |  Height:  |  Size: 566 B

View File

Before

Width:  |  Height:  |  Size: 701 B

After

Width:  |  Height:  |  Size: 701 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 520 B

View File

Before

Width:  |  Height:  |  Size: 601 B

After

Width:  |  Height:  |  Size: 601 B

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 128 KiB

View File

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 182 KiB

View File

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

715
example/node_editor.c Normal file
View File

@ -0,0 +1,715 @@
/* nuklear - v1.00 - public domain */
/* This is a simple node editor just to show a simple implementation and that
* it is possible to achieve it with this library. While all nodes inside this
* example use a simple color modifier as content you could change them
* to have your custom content depending on the node time.
* Biggest difference to most usual implementation is that this example does
* not has connectors on the right position of the property that it links.
* This is mainly done out of lazyness and could be implemented as well but
* requires calculating the position of all rows and add connectors.
* In addition adding and removing nodes is quite limited at the
* moment since it is based on a simple fixed array. If this is to be converted
* into something more serious it is probably best to extend it.*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include <limits.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GLFW/glfw3.h>
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#include "../nuklear.h"
/* macros */
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define MAX_VERTEX_MEMORY 512 * 1024
#define MAX_ELEMENT_MEMORY 128 * 1024
#define UNUSED(a) (void)a
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) < (b) ? (b) : (a))
#define LEN(a) (sizeof(a)/sizeof(a)[0])
/* ===============================================================
*
* NODE EDITOR
*
* ===============================================================*/
struct node {
int ID;
char name[32];
struct nk_rect bounds;
float value;
struct nk_color color;
int input_count;
int output_count;
struct node *next;
struct node *prev;
};
struct node_link {
int input_id;
int input_slot;
int output_id;
int output_slot;
struct nk_vec2 in;
struct nk_vec2 out;
};
struct node_linking {
int active;
struct node *node;
int input_id;
int input_slot;
};
struct node_editor {
struct node node_buf[32];
struct node_link links[64];
struct node *begin;
struct node *end;
int node_count;
int link_count;
struct nk_rect bounds;
struct node *selected;
int show_grid;
struct nk_vec2 scrolling;
struct node_linking linking;
};
static void
node_editor_push(struct node_editor *editor, struct node *node)
{
if (!editor->begin) {
node->next = NULL;
node->prev = NULL;
editor->begin = node;
editor->end = node;
} else {
node->prev = editor->end;
if (editor->end)
editor->end->next = node;
node->next = NULL;
editor->end = node;
}
}
static void
node_editor_pop(struct node_editor *editor, struct node *node)
{
if (node->next)
node->next->prev = node->prev;
if (node->prev)
node->prev->next = node->next;
if (editor->end == node)
editor->end = node->prev;
if (editor->begin == node)
editor->begin = node->next;
node->next = NULL;
node->prev = NULL;
}
static struct node*
node_editor_find(struct node_editor *editor, int ID)
{
struct node *iter = editor->begin;
while (iter) {
if (iter->ID == ID)
return iter;
iter = iter->next;
}
return NULL;
}
static void
node_editor_add(struct node_editor *editor, const char *name, struct nk_rect bounds,
struct nk_color col, int in_count, int out_count)
{
static int IDs = 0;
struct node *node;
assert((nk_size)editor->node_count < LEN(editor->node_buf));
node = &editor->node_buf[editor->node_count++];
node->ID = IDs++;
node->value = 0;
node->color = nk_rgb(255, 0, 0);
node->input_count = in_count;
node->output_count = out_count;
node->color = col;
node->bounds = bounds;
strcpy(node->name, name);
node_editor_push(editor, node);
}
static void
node_editor_link(struct node_editor *editor, int in_id, int in_slot,
int out_id, int out_slot)
{
struct node_link *link;
assert((nk_size)editor->link_count < LEN(editor->links));
link = &editor->links[editor->link_count++];
link->input_id = in_id;
link->input_slot = in_slot;
link->output_id = out_id;
link->output_slot = out_slot;
}
static void
node_editor_init(struct node_editor *editor)
{
memset(editor, 0, sizeof(*editor));
editor->begin = NULL;
editor->end = NULL;
node_editor_add(editor, "Source", nk_rect(-40, 10, 180, 220), nk_rgb(255, 0, 0), 0, 1);
node_editor_add(editor, "Source", nk_rect(-40, 260, 180, 220), nk_rgb(0, 255, 0), 0, 1);
node_editor_add(editor, "Combine", nk_rect(400, 100, 180, 220), nk_rgb(0,0,255), 2, 2);
node_editor_link(editor, 0, 0, 2, 0);
node_editor_link(editor, 1, 0, 2, 1);
editor->show_grid = nk_true;
}
static int
node_editor_run(struct node_editor *nodedit, struct nk_context *ctx)
{
int n = 0;
struct nk_rect total_space;
const struct nk_input *in = &ctx->input;
struct nk_command_buffer *canvas;
struct node *updated = 0;
struct nk_panel layout;
if (nk_begin(ctx, &layout, "Node Editor", nk_rect(50, 50, WINDOW_WIDTH, WINDOW_HEIGHT),
NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE))
{
/* allocate complete window space */
canvas = nk_window_get_canvas(ctx);
total_space = nk_window_get_content_region(ctx);
nk_layout_space_begin(ctx, NK_STATIC, total_space.h, nodedit->node_count);
{
struct nk_panel node, menu;
struct node *it = nodedit->begin;
struct nk_rect size = nk_layout_space_bounds(ctx);
if (nodedit->show_grid) {
/* display grid */
float x, y;
const float grid_size = 32.0f;
const struct nk_color grid_color = nk_rgb(50, 50, 50);
for (x = (float)fmod(size.x - nodedit->scrolling.x, grid_size); x < size.w; x += grid_size)
nk_stroke_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, 1.0f, grid_color);
for (y = (float)fmod(size.y - nodedit->scrolling.y, grid_size); y < size.h; y += grid_size)
nk_stroke_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, 1.0f, grid_color);
}
/* execute each node as a moveable group */
while (it) {
/* calculate scrolled node window position and size */
nk_layout_space_push(ctx, nk_rect(it->bounds.x - nodedit->scrolling.x,
it->bounds.y - nodedit->scrolling.y, it->bounds.w, it->bounds.h));
/* execute node window */
if (nk_group_begin(ctx, &node, it->name, NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE))
{
/* always have last selected node on top */
if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, node.bounds) &&
(!(it->prev && nk_input_mouse_clicked(in, NK_BUTTON_LEFT,
nk_layout_space_rect_to_screen(ctx, node.bounds)))) &&
nodedit->end != it)
{
updated = it;
}
/* ================= NODE CONTENT =====================*/
nk_layout_row_dynamic(ctx, 25, 1);
nk_button_color(ctx, it->color, NK_BUTTON_DEFAULT);
it->color.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, it->color.r, 255, 1,1);
it->color.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, it->color.g, 255, 1,1);
it->color.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, it->color.b, 255, 1,1);
it->color.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, it->color.a, 255, 1,1);
/* ====================================================*/
nk_group_end(ctx);
}
{
/* node connector and linking */
float space;
struct nk_rect bounds;
bounds = nk_layout_space_rect_to_local(ctx, node.bounds);
bounds.x += nodedit->scrolling.x - ctx->style.window.border;
bounds.y += nodedit->scrolling.y - ctx->style.window.border;
bounds.w += 2*ctx->style.window.border;
bounds.h += 2*ctx->style.window.border;
it->bounds = bounds;
/* output connector */
space = node.bounds.h / (float)((it->output_count) + 1);
for (n = 0; n < it->output_count; ++n) {
struct nk_rect circle;
circle.x = node.bounds.x + node.bounds.w-4;
circle.y = node.bounds.y + space * (float)(n+1);
circle.w = 8; circle.h = 8;
nk_fill_circle(canvas, circle, nk_rgb(100, 100, 100));
/* start linking process */
if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true)) {
nodedit->linking.active = nk_true;
nodedit->linking.node = it;
nodedit->linking.input_id = it->ID;
nodedit->linking.input_slot = n;
}
/* draw curve from linked node slot to mouse position */
if (nodedit->linking.active && nodedit->linking.node == it &&
nodedit->linking.input_slot == n) {
struct nk_vec2 l0 = nk_vec2(circle.x + 3, circle.y + 3);
struct nk_vec2 l1 = in->mouse.pos;
nk_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y,
l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, nk_rgb(100, 100, 100));
}
}
/* input connector */
space = node.bounds.h / (float)((it->input_count) + 1);
for (n = 0; n < it->input_count; ++n) {
struct nk_rect circle;
circle.x = node.bounds.x-4;
circle.y = node.bounds.y + space * (float)(n+1);
circle.w = 8; circle.h = 8;
nk_fill_circle(canvas, circle, nk_rgb(100, 100, 100));
if (nk_input_is_mouse_released(in, NK_BUTTON_LEFT) &&
nk_input_is_mouse_hovering_rect(in, circle) &&
nodedit->linking.active && nodedit->linking.node != it) {
nodedit->linking.active = nk_false;
node_editor_link(nodedit, nodedit->linking.input_id,
nodedit->linking.input_slot, it->ID, n);
}
}
}
it = it->next;
}
/* reset linking connection */
if (nodedit->linking.active && nk_input_is_mouse_released(in, NK_BUTTON_LEFT)) {
nodedit->linking.active = nk_false;
nodedit->linking.node = NULL;
fprintf(stdout, "linking failed\n");
}
/* draw each link */
for (n = 0; n < nodedit->link_count; ++n) {
struct node_link *link = &nodedit->links[n];
struct node *ni = node_editor_find(nodedit, link->input_id);
struct node *no = node_editor_find(nodedit, link->output_id);
float spacei = node.bounds.h / (float)((ni->output_count) + 1);
float spaceo = node.bounds.h / (float)((no->input_count) + 1);
struct nk_vec2 l0 = nk_layout_space_to_screen(ctx,
nk_vec2(ni->bounds.x + ni->bounds.w, 3.0f + ni->bounds.y + spacei * (float)(link->input_slot+1)));
struct nk_vec2 l1 = nk_layout_space_to_screen(ctx,
nk_vec2(no->bounds.x, 3.0f + no->bounds.y + spaceo * (float)(link->output_slot+1)));
l0.x -= nodedit->scrolling.x;
l0.y -= nodedit->scrolling.y;
l1.x -= nodedit->scrolling.x;
l1.y -= nodedit->scrolling.y;
nk_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y,
l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, nk_rgb(100, 100, 100));
}
if (updated) {
/* reshuffle nodes to have least recently selected node on top */
node_editor_pop(nodedit, updated);
node_editor_push(nodedit, updated);
}
/* node selection */
if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nk_layout_space_bounds(ctx))) {
it = nodedit->begin;
nodedit->selected = NULL;
nodedit->bounds = nk_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200);
while (it) {
struct nk_rect b = nk_layout_space_rect_to_screen(ctx, it->bounds);
b.x -= nodedit->scrolling.x;
b.y -= nodedit->scrolling.y;
if (nk_input_is_mouse_hovering_rect(in, b))
nodedit->selected = it;
it = it->next;
}
}
/* contextual menu */
if (nk_contextual_begin(ctx, &menu, 0, nk_vec2(100, 220), nk_window_get_bounds(ctx))) {
const char *grid_option[] = {"Show Grid", "Hide Grid"};
nk_layout_row_dynamic(ctx, 25, 1);
if (nk_contextual_item_label(ctx, "New", NK_TEXT_CENTERED))
node_editor_add(nodedit, "New", nk_rect(400, 260, 180, 220),
nk_rgb(255, 255, 255), 1, 2);
if (nk_contextual_item_label(ctx, grid_option[nodedit->show_grid],NK_TEXT_CENTERED))
nodedit->show_grid = !nodedit->show_grid;
nk_contextual_end(ctx);
}
}
nk_layout_space_end(ctx);
/* window content scrolling */
if (nk_input_is_mouse_hovering_rect(in, nk_window_get_bounds(ctx)) &&
nk_input_is_mouse_down(in, NK_BUTTON_MIDDLE)) {
nodedit->scrolling.x += in->mouse.delta.x;
nodedit->scrolling.y += in->mouse.delta.y;
}
}
nk_end(ctx);
return !nk_window_is_closed(ctx, "Node Editor");
}
/* ===============================================================
*
* DEVICE
*
* ===============================================================*/
struct device {
struct nk_buffer cmds;
struct nk_draw_null_texture null;
GLuint vbo, vao, ebo;
GLuint prog;
GLuint vert_shdr;
GLuint frag_shdr;
GLint attrib_pos;
GLint attrib_uv;
GLint attrib_col;
GLint uniform_tex;
GLint uniform_proj;
GLuint font_tex;
};
static void
device_init(struct device *dev)
{
GLint status;
static const GLchar *vertex_shader =
"#version 300 es\n"
"uniform mat4 ProjMtx;\n"
"in vec2 Position;\n"
"in vec2 TexCoord;\n"
"in vec4 Color;\n"
"out vec2 Frag_UV;\n"
"out vec4 Frag_Color;\n"
"void main() {\n"
" Frag_UV = TexCoord;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
static const GLchar *fragment_shader =
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D Texture;\n"
"in vec2 Frag_UV;\n"
"in vec4 Frag_Color;\n"
"out vec4 Out_Color;\n"
"void main(){\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
nk_buffer_init_default(&dev->cmds);
dev->prog = glCreateProgram();
dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
glCompileShader(dev->vert_shdr);
glCompileShader(dev->frag_shdr);
glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
assert(status == GL_TRUE);
glAttachShader(dev->prog, dev->vert_shdr);
glAttachShader(dev->prog, dev->frag_shdr);
glLinkProgram(dev->prog);
glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
assert(status == GL_TRUE);
dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
{
/* buffer setup */
GLsizei vs = sizeof(struct nk_draw_vertex);
size_t vp = offsetof(struct nk_draw_vertex, position);
size_t vt = offsetof(struct nk_draw_vertex, uv);
size_t vc = offsetof(struct nk_draw_vertex, col);
glGenBuffers(1, &dev->vbo);
glGenBuffers(1, &dev->ebo);
glGenVertexArrays(1, &dev->vao);
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glEnableVertexAttribArray((GLuint)dev->attrib_pos);
glEnableVertexAttribArray((GLuint)dev->attrib_uv);
glEnableVertexAttribArray((GLuint)dev->attrib_col);
glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
static void
device_upload_atlas(struct device *dev, const void *image, int width, int height)
{
glGenTextures(1, &dev->font_tex);
glBindTexture(GL_TEXTURE_2D, dev->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image);
}
static void
device_shutdown(struct device *dev)
{
glDetachShader(dev->prog, dev->vert_shdr);
glDetachShader(dev->prog, dev->frag_shdr);
glDeleteShader(dev->vert_shdr);
glDeleteShader(dev->frag_shdr);
glDeleteProgram(dev->prog);
glDeleteTextures(1, &dev->font_tex);
glDeleteBuffers(1, &dev->vbo);
glDeleteBuffers(1, &dev->ebo);
nk_buffer_free(&dev->cmds);
}
static void
device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
enum nk_anti_aliasing AA)
{
GLint last_prog, last_tex;
GLint last_ebo, last_vbo, last_vao;
GLfloat ortho[4][4] = {
{2.0f, 0.0f, 0.0f, 0.0f},
{0.0f,-2.0f, 0.0f, 0.0f},
{0.0f, 0.0f,-1.0f, 0.0f},
{-1.0f,1.0f, 0.0f, 1.0f},
};
ortho[0][0] /= (GLfloat)width;
ortho[1][1] /= (GLfloat)height;
/* save previous opengl state */
glGetIntegerv(GL_CURRENT_PROGRAM, &last_prog);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_tex);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_vao);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_ebo);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo);
/* setup global state */
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glActiveTexture(GL_TEXTURE0);
/* setup program */
glUseProgram(dev->prog);
glUniform1i(dev->uniform_tex, 0);
glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
{
/* convert from command queue into draw list and draw to screen */
const struct nk_draw_command *cmd;
void *vertices, *elements;
const nk_draw_index *offset = NULL;
/* allocate vertex and element buffer */
glBindVertexArray(dev->vao);
glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
/* load draw vertices & elements directly into vertex + element buffer */
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
{
/* fill converting configuration */
struct nk_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.curve_segment_count = 22;
config.arc_segment_count = 22;
config.null = dev->null;
/* setup buffers to load vertices and elements */
{struct nk_buffer vbuf, ebuf;
nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
/* iterate over and execute each draw command */
nk_draw_foreach(cmd, ctx, &dev->cmds) {
if (!cmd->elem_count) continue;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
glScissor((GLint)cmd->clip_rect.x,
height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h),
(GLint)cmd->clip_rect.w, (GLint)cmd->clip_rect.h);
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
nk_clear(ctx);
}
/* restore old state */
glUseProgram((GLuint)last_prog);
glBindTexture(GL_TEXTURE_2D, (GLuint)last_tex);
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)last_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)last_ebo);
glBindVertexArray((GLuint)last_vao);
glDisable(GL_SCISSOR_TEST);
}
/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/
static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);}
static void text_input(GLFWwindow *win, unsigned int codepoint)
{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
static void scroll_input(GLFWwindow *win, double _, double yoff)
{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
int main(int argc, char *argv[])
{
/* Platform */
static GLFWwindow *win;
int width = 0, height = 0;
/* GUI */
struct device device;
struct nk_context ctx;
struct nk_font *font;
struct nk_font_atlas atlas;
struct node_editor node;
/* GLFW */
glfwSetErrorCallback(error_callback);
if (!glfwInit()) {
fprintf(stdout, "[GFLW] failed to init!\n");
exit(1);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Demo", NULL, NULL);
glfwMakeContextCurrent(win);
glfwSetWindowUserPointer(win, &ctx);
glfwSetCharCallback(win, text_input);
glfwSetScrollCallback(win, scroll_input);
/* OpenGL */
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glewExperimental = 1;
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to setup GLEW\n");
exit(1);
}
{/* GUI */
device_init(&device);
{const void *image; int w, h;
const char *font_path = (argc > 1) ? argv[1]: 0;
nk_font_atlas_init_default(&atlas);
nk_font_atlas_begin(&atlas);
if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 14.0f, NULL);
else font = nk_font_atlas_add_default(&atlas, 14.0f, NULL);
image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
device_upload_atlas(&device, image, w, h);
nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.null);}
nk_init_default(&ctx, &font->handle);}
node_editor_init(&node);
while (!glfwWindowShouldClose(win))
{
/* Input */
{double x, y;
nk_input_begin(&ctx);
glfwPollEvents();
nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL)) {
nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);
nk_input_key(&ctx, NK_KEY_SHIFT, 1);
} else {
nk_input_key(&ctx, NK_KEY_COPY, 0);
nk_input_key(&ctx, NK_KEY_PASTE, 0);
nk_input_key(&ctx, NK_KEY_CUT, 0);
nk_input_key(&ctx, NK_KEY_SHIFT, 0);
}
glfwGetCursorPos(win, &x, &y);
nk_input_motion(&ctx, (int)x, (int)y);
nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
nk_input_end(&ctx);}
/* GUI */
if (!node_editor_run(&node, &ctx)) break;
/* Draw */
glfwGetWindowSize(win, &width, &height);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON);
glfwSwapBuffers(win);
}
nk_font_atlas_clear(&atlas);
nk_free(&ctx);
device_shutdown(&device);
glfwTerminate();
return 0;
}

1466
example/overview.c Normal file

File diff suppressed because it is too large Load Diff

132
example/style.c Normal file
View File

@ -0,0 +1,132 @@
enum theme {THEME_BLACK, THEME_WHITE, THEME_RED, THEME_BLUE, THEME_DARK};
void
set_style(struct nk_context *ctx, enum theme theme)
{
struct nk_color table[NK_COLOR_COUNT];
if (theme == THEME_WHITE) {
table[NK_COLOR_TEXT] = nk_rgba(70, 70, 70, 255);
table[NK_COLOR_WINDOW] = nk_rgba(175, 175, 175, 255);
table[NK_COLOR_HEADER] = nk_rgba(175, 175, 175, 255);
table[NK_COLOR_BORDER] = nk_rgba(0, 0, 0, 255);
table[NK_COLOR_BUTTON] = nk_rgba(185, 185, 185, 255);
table[NK_COLOR_BUTTON_HOVER] = nk_rgba(170, 170, 170, 255);
table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(160, 160, 160, 255);
table[NK_COLOR_TOGGLE] = nk_rgba(150, 150, 150, 255);
table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(120, 120, 120, 255);
table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(175, 175, 175, 255);
table[NK_COLOR_SELECT] = nk_rgba(190, 190, 190, 255);
table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(175, 175, 175, 255);
table[NK_COLOR_SLIDER] = nk_rgba(190, 190, 190, 255);
table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(80, 80, 80, 255);
table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(70, 70, 70, 255);
table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(60, 60, 60, 255);
table[NK_COLOR_PROPERTY] = nk_rgba(175, 175, 175, 255);
table[NK_COLOR_EDIT] = nk_rgba(150, 150, 150, 255);
table[NK_COLOR_EDIT_CURSOR] = nk_rgba(0, 0, 0, 255);
table[NK_COLOR_COMBO] = nk_rgba(175, 175, 175, 255);
table[NK_COLOR_CHART] = nk_rgba(160, 160, 160, 255);
table[NK_COLOR_CHART_COLOR] = nk_rgba(45, 45, 45, 255);
table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255);
table[NK_COLOR_SCROLLBAR] = nk_rgba(180, 180, 180, 255);
table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(140, 140, 140, 255);
table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(150, 150, 150, 255);
table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(160, 160, 160, 255);
table[NK_COLOR_TAB_HEADER] = nk_rgba(180, 180, 180, 255);
nk_style_from_table(ctx, table);
} else if (theme == THEME_RED) {
table[NK_COLOR_TEXT] = nk_rgba(190, 190, 190, 255);
table[NK_COLOR_WINDOW] = nk_rgba(30, 33, 40, 215);
table[NK_COLOR_HEADER] = nk_rgba(181, 45, 69, 220);
table[NK_COLOR_BORDER] = nk_rgba(51, 55, 67, 255);
table[NK_COLOR_BUTTON] = nk_rgba(181, 45, 69, 255);
table[NK_COLOR_BUTTON_HOVER] = nk_rgba(190, 50, 70, 255);
table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(195, 55, 75, 255);
table[NK_COLOR_TOGGLE] = nk_rgba(51, 55, 67, 255);
table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 60, 60, 255);
table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(181, 45, 69, 255);
table[NK_COLOR_SELECT] = nk_rgba(51, 55, 67, 255);
table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(181, 45, 69, 255);
table[NK_COLOR_SLIDER] = nk_rgba(51, 55, 67, 255);
table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(181, 45, 69, 255);
table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(186, 50, 74, 255);
table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(191, 55, 79, 255);
table[NK_COLOR_PROPERTY] = nk_rgba(51, 55, 67, 255);
table[NK_COLOR_EDIT] = nk_rgba(51, 55, 67, 225);
table[NK_COLOR_EDIT_CURSOR] = nk_rgba(190, 190, 190, 255);
table[NK_COLOR_COMBO] = nk_rgba(51, 55, 67, 255);
table[NK_COLOR_CHART] = nk_rgba(51, 55, 67, 255);
table[NK_COLOR_CHART_COLOR] = nk_rgba(170, 40, 60, 255);
table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255);
table[NK_COLOR_SCROLLBAR] = nk_rgba(30, 33, 40, 255);
table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255);
table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255);
table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255);
table[NK_COLOR_TAB_HEADER] = nk_rgba(181, 45, 69, 220);
nk_style_from_table(ctx, table);
} else if (theme == THEME_BLUE) {
table[NK_COLOR_TEXT] = nk_rgba(20, 20, 20, 255);
table[NK_COLOR_WINDOW] = nk_rgba(202, 212, 214, 215);
table[NK_COLOR_HEADER] = nk_rgba(137, 182, 224, 220);
table[NK_COLOR_BORDER] = nk_rgba(140, 159, 173, 255);
table[NK_COLOR_BUTTON] = nk_rgba(137, 182, 224, 255);
table[NK_COLOR_BUTTON_HOVER] = nk_rgba(142, 187, 229, 255);
table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(147, 192, 234, 255);
table[NK_COLOR_TOGGLE] = nk_rgba(177, 210, 210, 255);
table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(182, 215, 215, 255);
table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(137, 182, 224, 255);
table[NK_COLOR_SELECT] = nk_rgba(177, 210, 210, 255);
table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(137, 182, 224, 255);
table[NK_COLOR_SLIDER] = nk_rgba(177, 210, 210, 255);
table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(137, 182, 224, 245);
table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(142, 188, 229, 255);
table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(147, 193, 234, 255);
table[NK_COLOR_PROPERTY] = nk_rgba(210, 210, 210, 255);
table[NK_COLOR_EDIT] = nk_rgba(210, 210, 210, 225);
table[NK_COLOR_EDIT_CURSOR] = nk_rgba(20, 20, 20, 255);
table[NK_COLOR_COMBO] = nk_rgba(210, 210, 210, 255);
table[NK_COLOR_CHART] = nk_rgba(210, 210, 210, 255);
table[NK_COLOR_CHART_COLOR] = nk_rgba(137, 182, 224, 255);
table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba( 255, 0, 0, 255);
table[NK_COLOR_SCROLLBAR] = nk_rgba(190, 200, 200, 255);
table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255);
table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255);
table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255);
table[NK_COLOR_TAB_HEADER] = nk_rgba(156, 193, 220, 255);
nk_style_from_table(ctx, table);
} else if (theme == THEME_DARK) {
table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255);
table[NK_COLOR_WINDOW] = nk_rgba(57, 67, 71, 215);
table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 220);
table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255);
table[NK_COLOR_BUTTON] = nk_rgba(48, 83, 111, 255);
table[NK_COLOR_BUTTON_HOVER] = nk_rgba(58, 93, 121, 255);
table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(63, 98, 126, 255);
table[NK_COLOR_TOGGLE] = nk_rgba(50, 58, 61, 255);
table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 53, 56, 255);
table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(48, 83, 111, 255);
table[NK_COLOR_SELECT] = nk_rgba(57, 67, 61, 255);
table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(48, 83, 111, 255);
table[NK_COLOR_SLIDER] = nk_rgba(50, 58, 61, 255);
table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(48, 83, 111, 245);
table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);
table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);
table[NK_COLOR_PROPERTY] = nk_rgba(50, 58, 61, 255);
table[NK_COLOR_EDIT] = nk_rgba(50, 58, 61, 225);
table[NK_COLOR_EDIT_CURSOR] = nk_rgba(210, 210, 210, 255);
table[NK_COLOR_COMBO] = nk_rgba(50, 58, 61, 255);
table[NK_COLOR_CHART] = nk_rgba(50, 58, 61, 255);
table[NK_COLOR_CHART_COLOR] = nk_rgba(48, 83, 111, 255);
table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);
table[NK_COLOR_SCROLLBAR] = nk_rgba(50, 58, 61, 255);
table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(48, 83, 111, 255);
table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);
table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);
table[NK_COLOR_TAB_HEADER] = nk_rgba(48, 83, 111, 255);
nk_style_from_table(ctx, table);
} else {
nk_style_default(ctx);
}
}

Binary file not shown.

Binary file not shown.

BIN
extra_font/ProggyClean.ttf Normal file

Binary file not shown.

BIN
extra_font/ProggyTiny.ttf Normal file

Binary file not shown.

BIN
extra_font/Raleway-Bold.ttf Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More