diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..f30379bd
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(dust3d)
+
+file(GLOB_RECURSE sources
+ src/glw_osx.m
+ src/glw_internal.h
+ src/glw_style.h
+ src/glw.c
+ src/glw.h
+ src/dmemory.h
+ src/dmemory.c
+ src/3dstruct.h
+ src/array.h
+ src/array.c
+ src/dict.h
+ src/dict.c
+ src/bmesh.h
+ src/bmesh.c
+ src/matrix.h
+ src/matrix.c
+ src/subdivide.h
+ src/subdivide.c
+ src/vector3d.h
+ src/vector3d.c
+ src/convexhull.h
+ src/convexhull.c
+ src/draw.h
+ src/draw.c
+ src/editor.c
+)
+
+IF(APPLE)
+ add_executable(dust3d MACOSX_BUNDLE ${sources})
+ find_package(OpenGL REQUIRED)
+ include_directories(${OPENGL_INCLUDE_DIRS})
+ target_link_libraries(dust3d ${OPENGL_LIBRARIES})
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AppKit -framework Quartz")
+ set_target_properties(dust3d PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/src/Info.plist)
+ install(TARGETS dust3d
+ DESTINATION ".")
+ENDIF (APPLE)
diff --git a/README.md b/README.md
index 21180566..1820b190 100644
--- a/README.md
+++ b/README.md
@@ -10,25 +10,6 @@ I was inspired by Jimmy Gunawan's blogs of monster generation, here is the first
of 3D Articulated Shapes](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.357.7134&rep=rep1&type=pdf)(Authors: Zhongping Ji, Ligang Liu, Yigang Wang). I started to think of monster model generation for game development from years ago, thanks for this paper, Dust3D is achievable now.
From my initial thought, Dust3D should be a tool like [Makehuman](http://www.makehuman.org), with more versatile features, not only can make human, but also be able to **generate monsters automatically**.
-Build
-============
-*Generate Xcode Project*
-```
-$ cd build
-$ qmake -spec macx-xcode
-```
-*Generate VC Project*
-```
-$ cd build
-$ qmake -tp vc
-```
-*Generate Makefile*
-```
-$ cd build
-$ qmake
-$ make
-```
-
TODO & Progress
==============
- [x] Drawing Primitives (Dec 15, 2016 ~ Dec 17, 2016)
@@ -83,7 +64,10 @@ This todo already done in the B-Mesh algorithm implementation.
**Feb 8, 2017:**
There are lots of changes to the UI part of Dust3D, though not commit yet because of many things have not been finalize.
I removed the Qt, the counterpart of the build system is CMake, and instead of using Qt based OpenGL windows, I am using my own implemented OpenGL support library. I considered using the most popular [Dear ImGui](https://github.com/ocornut/imgui) library, but I really want remove the C++ from the codebase. It's a good start of the skeleton editor UI!
-
+
+ **Feb 11, 2017:**
+ Qt removed, so C++ removed, but Objective-C imported for just support the OpenGL environment on OSX.
+
- [ ] Render rigid animation
- [ ] png exporter for isometric 2.5D game
diff --git a/build/dust3d.pro b/build/dust3d.pro
deleted file mode 100644
index c3509d64..00000000
--- a/build/dust3d.pro
+++ /dev/null
@@ -1,38 +0,0 @@
-TARGET = dust3d
-TEMPLATE = app
-
-QT += widgets opengl
-CONFIG += debug
-
-VPATH += ../src
-INCLUDEPATH += ../src
-
-SOURCES += main.cpp \
- mainwindow.cpp \
- render.cpp \
- vector3d.c \
- draw.cpp \
- array.c \
- bmesh.c \
- matrix.c \
- convexhull.c \
- dict.c \
- osutil.cpp \
- subdivide.c \
- skinnedmesh.c \
- dmemory.c
-
-HEADERS += mainwindow.h \
- render.h \
- vector3d.h \
- draw.h \
- array.h \
- bmesh.h \
- matrix.h \
- convexhull.h \
- dict.h \
- 3dstruct.h \
- osutil.h \
- subdivide.h \
- skinnedmesh.h \
- dmemory.h
\ No newline at end of file
diff --git a/src/Info.plist b/src/Info.plist
new file mode 100644
index 00000000..4e619f32
--- /dev/null
+++ b/src/Info.plist
@@ -0,0 +1,30 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIconFile
+
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSMinimumSystemVersion
+ $(MACOSX_DEPLOYMENT_TARGET)
+ NSHumanReadableCopyright
+ Copyright © 2017 dust3d. All rights reserved.
+ NSPrincipalClass
+ NSApplication
+
+
diff --git a/src/bmesh.c b/src/bmesh.c
index f40cacf3..f055104b 100644
--- a/src/bmesh.c
+++ b/src/bmesh.c
@@ -11,7 +11,6 @@
#include "matrix.h"
#include "convexhull.h"
#include "subdivide.h"
-#include "draw.h"
#define BMESH_MAX_PARENT_BALL_DEPTH 1000
#define BMESH_INTVAL_DIST_DIV 10
@@ -547,10 +546,6 @@ static convexHull *createConvexHullForBall(bmesh *bm, int depth,
for (i = 0; i < arrayGetLength(ballPtrArray); ++i) {
bmeshBall *ballItem = *((bmeshBall **)arrayGetItem(ballPtrArray, i));
ballItem->convexHullCount++;
- drawDebugPrintf("convexHullCount:%d", ballItem->convexHullCount);
- if (ballItem->convexHullCount == 1) {
- drawDebugPoint(&ballItem->position, ballItem->index);
- }
}
arrayDestroy(ballPtrArray);
@@ -727,7 +722,7 @@ static void bmeshGenerateInbetweenMeshFrom(bmesh *bm, int depth,
bmeshAddWallsBetweenQuadsToModel(bm, &ball->position, ¤tFace,
&childFace);
bmeshAddQuadToModel(bm, &childFace);
- drawQuad(&childFace);
+ //drawQuad(&childFace);
}
}
else if (1 == ball->convexHullCount && !ball->meshGenerated) {
diff --git a/src/convexhull.c b/src/convexhull.c
index 7b776a82..5466b103 100644
--- a/src/convexhull.c
+++ b/src/convexhull.c
@@ -6,7 +6,6 @@
#include "convexhull.h"
#include "array.h"
#include "dict.h"
-#include "draw.h"
//
// Implement Gift wrapping method which describled in http://dccg.upc.edu/people/vera/wp-content/uploads/2014/11/GA2014-ConvexHulls3D-Roger-Hernando.pdf
diff --git a/src/draw.cpp b/src/draw.c
similarity index 96%
rename from src/draw.cpp
rename to src/draw.c
index 8ceedfee..5a3932a9 100644
--- a/src/draw.cpp
+++ b/src/draw.c
@@ -1,9 +1,8 @@
-#include
-#include
#include
#include
#include
#include
+#include
#include "draw.h"
static GLUquadricObj *quadricId = 0;
@@ -88,8 +87,6 @@ int drawCylinder(vec3 *topOrigin, vec3 *bottomOrigin, float radius, int slices,
}
int drawGrid(float size, float step) {
- glDisable(GL_LIGHTING);
-
// x z plane
glBegin(GL_LINES);
for (GLfloat i = -size; i <= size; i += step) {
@@ -105,8 +102,6 @@ int drawGrid(float size, float step) {
}
}
glEnd();
-
- glEnable(GL_LIGHTING);
return 0;
}
@@ -115,7 +110,8 @@ int drawPrintf(int x, int y, const char *fmt, ...) {
char text[1024];
va_start(args, fmt);
vsnprintf(text, sizeof(text), fmt, args);
- return drawText(x, y, text);
+ //return drawText(x, y, text);
+ return 0;
}
static const float drawDebugColors[][4] = {
diff --git a/src/draw.h b/src/draw.h
index 92fe6e72..9b842091 100644
--- a/src/draw.h
+++ b/src/draw.h
@@ -12,6 +12,10 @@
extern "C" {
#endif
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
int drawInit(void);
int drawSphere(vec3 *origin, float radius, int slices, int stacks);
void drawTriangle(triangle *poly);
diff --git a/src/editor.c b/src/editor.c
new file mode 100644
index 00000000..3becdc32
--- /dev/null
+++ b/src/editor.c
@@ -0,0 +1,229 @@
+#ifdef __APPLE__
+#include
+#elif defined(_WIN32)
+#include
+#include
+#endif
+#include
+#include
+#include
+#include "glw.h"
+#include "glw_style.h"
+#include "draw.h"
+#include "bmesh.h"
+
+#define GEN_ID __LINE__
+
+#define ED_MODE_EDIT 0
+#define ED_MODE_ANIMATION 1
+
+#define ED_BACKGROUND_COLOR 0xe4e2e4
+
+#define ED_SIDEBAR_WIDTH 400
+#define ED_SPACING 10
+
+#define ED_TOPBAR_HEIGHT 100
+#define ED_TOOLBAR_HEIGHT 50
+
+#define ED_GL_BACKGROUND_COLOR GLW_BACKGROUND_COLOR
+
+typedef struct editor {
+ glwWin *win;
+ float cameraAngleX;
+ float cameraAngleY;
+ float cameraDistance;
+ int newImId;
+ int showBoneChecked;
+ int width;
+ int height;
+ int mode;
+ int glLeft;
+ int glTop;
+ int glWidth;
+ int glHeight;
+ int mouseX;
+ int mouseY;
+ bmesh *bm;
+} editor;
+
+#include "../data/bmesh_test_2.h"
+
+static void display(glwWin *win) {
+ editor *ed = glwGetUserData(win);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+ glLoadIdentity();
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, ed->width, ed->height, 0, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ {
+ char *list[] = {"Open..", "New..", "Save As..", 0};
+ glwImButtonGroup(win, GEN_ID, 100, 30, 300, list, -1);
+ }
+
+ {
+ char *titles[] = {"Library", "Property", 0};
+ glwImTabBox(win, GEN_ID, ED_SPACING / 2, ED_TOPBAR_HEIGHT, ED_SIDEBAR_WIDTH,
+ ed->height - ED_TOPBAR_HEIGHT - ED_SPACING / 2,
+ titles, 0);
+ }
+
+ {
+ int x = ED_SPACING / 2 + ED_SIDEBAR_WIDTH + ED_SPACING;
+ int y = ED_TOPBAR_HEIGHT;
+ int width = ed->width - ED_SIDEBAR_WIDTH - ED_SPACING / 2 - ED_SPACING - ED_SPACING / 2;
+ int height = ed->height - ED_TOPBAR_HEIGHT - ED_SPACING / 2;
+ char *titles[] = {"Edit View", "Animation View", 0};
+ ed->mode = glwImTabBox(win, GEN_ID,
+ x, y, width, height,
+ titles, ed->mode);
+ if (ED_MODE_EDIT == ed->mode) {
+ int glWinY = glwImNextY(win);
+ int bottomY = y + height - ED_TOOLBAR_HEIGHT;
+ glwImBottomBar(win, GEN_ID, x, bottomY, width, ED_TOOLBAR_HEIGHT);
+ ed->showBoneChecked = glwImCheck(win, GEN_ID, x + ED_SPACING + ED_SPACING,
+ bottomY + (ED_TOOLBAR_HEIGHT - glwImLineHeight(win)) / 2 + 2,
+ "Show Bone",
+ ed->showBoneChecked);
+
+ ed->glLeft = x + 1;
+ ed->glTop = glWinY;
+ ed->glWidth = width - 3;
+ ed->glHeight = bottomY - glWinY;
+
+ if (0 == ed->bm) {
+ bmeshBall ball;
+ bmeshBone bone;
+ unsigned int i;
+ ed->bm = bmeshCreate();
+
+ for (i = 0; i < sizeof(bmeshTestBalls) / sizeof(bmeshTestBalls[0]); ++i) {
+ memset(&ball, 0, sizeof(ball));
+ ball.position.x = bmeshTestBalls[i][1];
+ ball.position.y = bmeshTestBalls[i][2];
+ ball.position.z = bmeshTestBalls[i][3];
+ ball.radius = bmeshTestBalls[i][4];
+ ball.type = bmeshTestBalls[i][5];
+ bmeshAddBall(ed->bm, &ball);
+ }
+
+ for (i = 0; i < sizeof(bmeshTestBones) / sizeof(bmeshTestBones[0]); ++i) {
+ memset(&bone, 0, sizeof(bone));
+ bone.firstBallIndex = bmeshTestBones[i][0];
+ bone.secondBallIndex = bmeshTestBones[i][1];
+ bmeshAddBone(ed->bm, &bone);
+ }
+
+ bmeshGenerate(ed->bm);
+ }
+
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(ed->glLeft, ED_SPACING / 2 + ED_TOOLBAR_HEIGHT + 1,
+ ed->glWidth, ed->glHeight);
+ glPushMatrix();
+ glTranslatef(x + 1, glWinY, 0);
+
+ glColor3f(glwR(ED_GL_BACKGROUND_COLOR),
+ glwG(ED_GL_BACKGROUND_COLOR),
+ glwB(ED_GL_BACKGROUND_COLOR));
+ glRecti(0, 0, ed->glWidth, ed->glHeight);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(60.0f, (float)ed->glWidth / ed->glHeight, 1, 1000);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glPushMatrix();
+ glTranslatef(0, 0, -ed->cameraDistance);
+ glRotatef(ed->cameraAngleX, 1, 0, 0);
+ glRotatef(ed->cameraAngleY, 0, 1, 0);
+
+ drawGrid(10, 1);
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_CULL_FACE);
+ bmeshDraw(ed->bm);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+
+ glPopMatrix();
+
+ glPopMatrix();
+ glDisable(GL_SCISSOR_TEST);
+ }
+ }
+}
+
+static void reshape(glwWin *win, int width, int height) {
+ editor *ed = glwGetUserData(win);
+
+ glShadeModel(GL_SMOOTH);
+ glEnable(GL_LIGHT0);
+
+ glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
+ glEnable(GL_COLOR_MATERIAL);
+
+ ed->width = width;
+ ed->height = height;
+
+ glEnable(GL_LINE_SMOOTH);
+ glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_ALPHA_TEST);
+ //glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glClearColor(glwR(ED_BACKGROUND_COLOR),
+ glwG(ED_BACKGROUND_COLOR),
+ glwB(ED_BACKGROUND_COLOR), 1);
+
+ glViewport(0, 0, (GLsizei)width, (GLsizei)height);
+}
+
+static void mouse(glwWin *win, int button, int state,
+ int x, int y){
+ editor *ed = glwGetUserData(win);
+ if (!glwPointTest(x, y, ed->glLeft, ed->glTop,
+ ed->glWidth, ed->glHeight, 0)) {
+ return;
+ }
+ if (GLW_DOWN == state) {
+ ed->mouseX = x;
+ ed->mouseY = y;
+ }
+}
+
+static void motion(glwWin *win, int x, int y) {
+ editor *ed = glwGetUserData(win);
+ if (!glwPointTest(x, y, ed->glLeft, ed->glTop,
+ ed->glWidth, ed->glHeight, 0)) {
+ return;
+ }
+ ed->cameraAngleY += (x - ed->mouseX);
+ ed->cameraAngleX += (y - ed->mouseY);
+ ed->mouseX = x;
+ ed->mouseY = y;
+}
+
+int main(int argc, char *argv[]) {
+ editor ed;
+ glwInit();
+ memset(&ed, 0, sizeof(ed));
+ ed.cameraAngleX = 30;
+ ed.cameraAngleY = -312;
+ ed.cameraDistance = 14.4;
+ ed.win = glwCreateWindow(0, 0, 0, 0);
+ glwSetUserData(ed.win, &ed);
+ glwReshapeFunc(ed.win, reshape);
+ glwDisplayFunc(ed.win, display);
+ glwMouseFunc(ed.win, mouse);
+ glwMotionFunc(ed.win, motion);
+ glwMainLoop();
+ return 0;
+}
diff --git a/src/glw.c b/src/glw.c
new file mode 100644
index 00000000..9b1ed943
--- /dev/null
+++ b/src/glw.c
@@ -0,0 +1,690 @@
+#include
+#include
+#include
+#include
+#include "glw_internal.h"
+#include "glw_style.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+void glwDrawSystemText(glwWin *win, int x, int y, char *text) {
+ int vleft, vwidth;
+ float tleft, twidth;
+ glwSystemFontTexture *systemFontTexture = glwGetSystemFontTexture(win);
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, systemFontTexture->texId);
+ for (vleft = 0; *text; vleft += vwidth, text++) {
+ int idx = (*text) - GLW_SYSTEM_FONT_BEGIN_CHAR;
+ if (idx < 0 || idx > GLW_SYSTEM_FONT_CHAR_NUM) {
+ continue;
+ }
+ tleft = (float)systemFontTexture->lefts[idx] /
+ systemFontTexture->size.width;
+ vwidth = systemFontTexture->widths[idx];
+ twidth = (float)vwidth / systemFontTexture->originSize.width;
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(tleft, 0);
+ glVertex2i(x + vleft, y);
+
+ glTexCoord2f(tleft + twidth, 0);
+ glVertex2i(x + vleft + vwidth, y);
+
+ glTexCoord2f(tleft + twidth, 1);
+ glVertex2i(x + vleft + vwidth, y + systemFontTexture->originSize.height);
+
+ glTexCoord2f(tleft, 1);
+ glVertex2i(x + vleft, y + systemFontTexture->originSize.height);
+ glEnd();
+ }
+ glDisable(GL_TEXTURE_2D);
+}
+
+void glwMouseEvent(glwWin *win, int button, int state, int x, int y) {
+ glwImGui *imGUI = glwGetImGUI(win);
+ imGUI->mouseButton = button;
+ imGUI->mouseState = state;
+ imGUI->mouseX = x;
+ imGUI->mouseY = y;
+}
+
+int glwPointTest(int x, int y, int left, int top, int width, int height,
+ int allowOffset) {
+ int right = left + width - 1 + allowOffset;
+ int bottom = top + height - 1 + allowOffset;
+ left -= allowOffset;
+ top -= allowOffset;
+ return x >= left && x <= right && y >= top && y <= bottom;
+}
+
+void glwInitSystemFontTexture(glwWin *win) {
+ char asciiTable[GLW_SYSTEM_FONT_CHAR_NUM + 1];
+ int i;
+ GLuint texture = 0;
+ glwFont *font;
+ int pixelsWide = 0;
+ int pixelsHigh = 0;
+ float scaleX, scaleY;
+ glwSystemFontTexture *systemFontTexture = glwGetSystemFontTexture(win);
+
+ for (i = 0; i <= GLW_SYSTEM_FONT_CHAR_NUM; ++i) {
+ asciiTable[i] = GLW_SYSTEM_FONT_BEGIN_CHAR + i;
+ }
+ asciiTable[GLW_SYSTEM_FONT_CHAR_NUM] = '\0';
+
+ font = glwCreateFont(GLW_SYSTEM_FONT_NAME, GLW_SYSTEM_FONT_WEIGHT,
+ GLW_SYSTEM_FONT_SIZE, 0);
+ systemFontTexture->lefts[0] = 0;
+ systemFontTexture->size.width = 0;
+ systemFontTexture->size.height = 0;
+ for (i = 0; i < GLW_SYSTEM_FONT_CHAR_NUM; ++i) {
+ char ch[2] = {asciiTable[i], '\0'};
+ glwSize chSize = glwMeasureText(ch, font);
+ if (chSize.height > systemFontTexture->size.height) {
+ systemFontTexture->size.height = chSize.height;
+ }
+ systemFontTexture->size.width += chSize.width;
+ systemFontTexture->widths[i] = chSize.width;
+ if (i > 0) {
+ systemFontTexture->lefts[i] = (float)(systemFontTexture->lefts[i - 1] +
+ systemFontTexture->widths[i - 1]);
+ }
+ }
+ systemFontTexture->originSize = systemFontTexture->size;
+ for (i = 0; i < GLW_SYSTEM_FONT_CHAR_NUM; ++i) {
+ char ch[2] = {asciiTable[i], '\0'};
+ glwSize chSize = {systemFontTexture->widths[i],
+ systemFontTexture->originSize.height};
+ unsigned char *rgba = glwRenderTextToRGBA(ch, font, chSize,
+ &pixelsWide, &pixelsHigh);
+ if (0 == i) {
+ scaleX = (float)pixelsWide / chSize.width;
+ scaleY = (float)pixelsHigh / chSize.height;
+ systemFontTexture->size.width *= scaleX;
+ systemFontTexture->size.height *= scaleY;
+ glEnable(GL_TEXTURE_2D);
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glTexImage2D(GL_TEXTURE_2D, 0, 4,
+ (GLsizei)(systemFontTexture->size.width),
+ (GLsizei)(systemFontTexture->size.height), 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ }
+ systemFontTexture->lefts[i] *= scaleX;
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ systemFontTexture->lefts[i], 0,
+ (GLsizei)pixelsWide,
+ (GLsizei)pixelsHigh,
+ GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+ free(rgba);
+ }
+ systemFontTexture->texId = (int)texture;
+ glwDestroyFont(font);
+}
+
+static glwVec2 glwRoundedCorners[GLW_SMALL_ROUNDED_CORNER_SLICES] = {{0}};
+
+static void createRoundedCorners(glwVec2 *arr, int num) {
+ float slice = M_PI / 2 / num;
+ int i;
+ float a = 0;
+ for (i = 0; i < num; a += slice, ++i) {
+ arr[i].x = cosf(a);
+ arr[i].y = sinf(a);
+ }
+}
+
+void glwInitPrimitives(void) {
+ createRoundedCorners(glwRoundedCorners, GLW_SMALL_ROUNDED_CORNER_SLICES);
+}
+
+static void glwDrawRightTopVertexs(float left, float top, float right,
+ float bottom, float radius) {
+ int i;
+ for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
+ glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
+ top + radius - radius * glwRoundedCorners[i].y);
+ }
+}
+
+static void glwDrawRightBottomVertexs(float left, float top, float right,
+ float bottom, float radius) {
+ int i;
+ for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
+ glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
+ bottom - radius + radius * glwRoundedCorners[i].y);
+ }
+}
+
+static void glwDrawLeftBottomVertexs(float left, float top, float right,
+ float bottom, float radius) {
+ int i;
+ for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
+ glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
+ bottom - radius + radius * glwRoundedCorners[i].y);
+ }
+}
+
+static void glwDrawLeftTopVertexs(float left, float top, float right,
+ float bottom, float radius) {
+ int i;
+ for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
+ glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
+ top + radius - radius * glwRoundedCorners[i].y);
+ }
+}
+
+void glwDrawCheckSymbol(int x, int y, int width, int height,
+ unsigned int color) {
+ glColor3f(glwR(color), glwG(color), glwB(color));
+ glLineWidth(2);
+ glBegin(GL_LINE_STRIP);
+ glVertex2f(x + width * 0.15, y + height * 0.3);
+ glVertex2f(x + width * 0.45, y + height * 0.65);
+ glVertex2f(x + width * 1.05, y - height * 0.05);
+ glEnd();
+ glLineWidth(1);
+}
+
+void glwDrawDropdownArrow(int x, int y, int width, int height,
+ unsigned int color) {
+ glColor3f(glwR(color), glwG(color), glwB(color));
+ glBegin(GL_TRIANGLES);
+ glVertex2f(x, y);
+ glVertex2f(x + width, y);
+ glVertex2f(x + width * 0.5, y + height);
+ glEnd();
+}
+
+void glwDrawVLine(int x, int y, int width, int height,
+ unsigned int color) {
+ glColor3f(glwR(color), glwG(color), glwB(color));
+ glLineWidth(width);
+ glBegin(GL_LINES);
+ glVertex2f(x, y);
+ glVertex2f(x, y + height - 1);
+ glEnd();
+ glLineWidth(1);
+}
+
+void glwDrawHLine(int x, int y, int width, int height,
+ unsigned int color) {
+ glColor3f(glwR(color), glwG(color), glwB(color));
+ glLineWidth(height);
+ glBegin(GL_LINES);
+ glVertex2f(x, y);
+ glVertex2f(x + width - 1, y);
+ glEnd();
+ glLineWidth(1);
+}
+
+void glwDrawRoundedRectBorder(float x, float y, float width, float height,
+ float radius, unsigned int color) {
+ float left = x;
+ float top = y;
+ float bottom = y + height - 1;
+ float right = x + width - 1;
+ glDisable(GL_TEXTURE_2D);
+ glColor3f(glwR(color), glwG(color), glwB(color));
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(left, top + radius);
+ glwDrawLeftTopVertexs(left, top, right, bottom, radius);
+ glVertex2f(left + radius, top);
+
+ glVertex2f(right - radius, top);
+ glwDrawRightTopVertexs(left, top, right, bottom, radius);
+ glVertex2f(right, top + radius);
+
+ glVertex2f(right, bottom - radius);
+ glwDrawRightBottomVertexs(left, top, right, bottom, radius);
+ glVertex2f(right - radius, bottom);
+
+ glVertex2f(left + radius, bottom);
+ glwDrawLeftBottomVertexs(left, top, right, bottom, radius);
+ glVertex2f(left, bottom - radius);
+ glEnd();
+}
+
+void glwDrawTopRoundedRectBorder(float x, float y, float width, float height,
+ float radius, unsigned int color) {
+ float left = x;
+ float top = y;
+ float bottom = y + height - 1;
+ float right = x + width - 1;
+ glDisable(GL_TEXTURE_2D);
+ glColor3f(glwR(color), glwG(color), glwB(color));
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(left, top + radius);
+ glwDrawLeftTopVertexs(left, top, right, bottom, radius);
+ glVertex2f(left + radius, top);
+
+ glVertex2f(right - radius, top);
+ glwDrawRightTopVertexs(left, top, right, bottom, radius);
+ glVertex2f(right, top + radius);
+
+ glVertex2f(right, bottom);
+ glVertex2f(left, bottom);
+ glEnd();
+}
+
+void glwDrawLeftRoundedRectGradientFill(float x, float y,
+ float width, float height,
+ float radius, unsigned int topColor, unsigned int bottomColor) {
+ float left = x;
+ float top = y;
+ float bottom = y + height - 1;
+ float right = x + width - 1;
+ int i;
+ glDisable(GL_TEXTURE_2D);
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
+ glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
+ glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
+ bottom - radius + radius * glwRoundedCorners[i].y);
+ glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
+ glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
+ top + radius - radius * glwRoundedCorners[i].y);
+ }
+ glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
+ glVertex2f(right, bottom);
+ glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
+ glVertex2f(right, top);
+ glEnd();
+}
+
+void glwDrawTopRoundedRectGradientFill(float x, float y,
+ float width, float height,
+ float radius, unsigned int topColor, unsigned int bottomColor) {
+ float left = x;
+ float top = y;
+ float bottom = y + height - 1;
+ float right = x + width - 1;
+ int i;
+ glDisable(GL_TEXTURE_2D);
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
+ glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
+ glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
+ bottom);
+ glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
+ glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
+ top + radius - radius * glwRoundedCorners[i].y);
+ }
+ for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
+ glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
+ glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
+ bottom);
+ glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
+ glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
+ top + radius - radius * glwRoundedCorners[i].y);
+ }
+ glEnd();
+}
+
+void glwDrawRectGradientFill(float x, float y,
+ float width, float height,
+ unsigned int topColor, unsigned int bottomColor) {
+ float left = x;
+ float top = y;
+ float bottom = y + height - 1;
+ float right = x + width - 1;
+ glDisable(GL_TEXTURE_2D);
+ glBegin(GL_QUAD_STRIP);
+ glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
+ glVertex2f(left, bottom);
+ glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
+ glVertex2f(left, top);
+ glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
+ glVertex2f(right, bottom);
+ glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
+ glVertex2f(right, top);
+ glEnd();
+}
+
+void glwDrawRightRoundedRectGradientFill(float x, float y,
+ float width, float height,
+ float radius, unsigned int topColor, unsigned int bottomColor) {
+ float left = x;
+ float top = y;
+ float bottom = y + height - 1;
+ float right = x + width - 1;
+ int i;
+ glDisable(GL_TEXTURE_2D);
+ glBegin(GL_QUAD_STRIP);
+ glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
+ glVertex2f(left, bottom);
+ glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
+ glVertex2f(left, top);
+ for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
+ glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
+ glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
+ bottom - radius + radius * glwRoundedCorners[i].y);
+ glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
+ glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
+ top + radius - radius * glwRoundedCorners[i].y);
+ }
+ glEnd();
+}
+
+void glwDrawRoundedRectGradientFill(float x, float y, float width, float height,
+ float radius, unsigned int topColor, unsigned int bottomColor) {
+ float left = x;
+ float top = y;
+ float bottom = y + height - 1;
+ float right = x + width - 1;
+ int i;
+ glDisable(GL_TEXTURE_2D);
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < GLW_SMALL_ROUNDED_CORNER_SLICES; ++i) {
+ glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
+ glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
+ bottom - radius + radius * glwRoundedCorners[i].y);
+ glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
+ glVertex2f(left + radius - radius * glwRoundedCorners[i].x,
+ top + radius - radius * glwRoundedCorners[i].y);
+ }
+ for (i = GLW_SMALL_ROUNDED_CORNER_SLICES - 1; i >= 0; --i) {
+ glColor3f(glwR(bottomColor), glwG(bottomColor), glwB(bottomColor));
+ glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
+ bottom - radius + radius * glwRoundedCorners[i].y);
+ glColor3f(glwR(topColor), glwG(topColor), glwB(topColor));
+ glVertex2f(right - radius + radius * glwRoundedCorners[i].x,
+ top + radius - radius * glwRoundedCorners[i].y);
+ }
+ glEnd();
+}
+
+void glwDrawButtonBackground(float x, float y, float width, float height,
+ glwCtrlState state) {
+ switch (state)
+ {
+ case GLW_CTRL_STATE_PRESS:
+ glwDrawRoundedRectGradientFill(x, y, width, height,
+ GLW_BUTTON_CORNER_RADIUS,
+ GLW_FILL_GRADIENT_COLOR_1_H, GLW_FILL_GRADIENT_COLOR_2_H);
+ break;
+ case GLW_CTRL_STATE_NORMAL:
+ default:
+ glwDrawRoundedRectGradientFill(x, y, width, height,
+ GLW_BUTTON_CORNER_RADIUS,
+ GLW_FILL_GRADIENT_COLOR_1, GLW_FILL_GRADIENT_COLOR_2);
+ break;
+ }
+ glwDrawRoundedRectBorder(x, y, width, height,
+ GLW_BUTTON_CORNER_RADIUS, GLW_BORDER_COLOR_2);
+}
+
+glwSize glwMeasureSystemText(glwWin *win, char *text) {
+ glwSystemFontTexture *systemFontTexture = glwGetSystemFontTexture(win);
+ glwSize size = {0, systemFontTexture->originSize.height};
+ for (; *text; text++) {
+ int idx = (*text) - GLW_SYSTEM_FONT_BEGIN_CHAR;
+ if (idx < 0 || idx > GLW_SYSTEM_FONT_CHAR_NUM) {
+ continue;
+ }
+ size.width += systemFontTexture->widths[idx];
+ }
+ return size;
+}
+
+static void glwImGUIActiveIdCheck(glwImGui *imGUI, int id, int x, int y,
+ int width, int height) {
+ if (GLW_DOWN == imGUI->mouseState) {
+ if (!imGUI->activeId) {
+ int hit = glwPointTest(imGUI->mouseX, imGUI->mouseY, x, y,
+ width, height, 0);
+ if (hit) {
+ imGUI->activeId = id;
+ }
+ }
+ } else if (GLW_UP == imGUI->mouseState) {
+ if (imGUI->activeId == id) {
+ imGUI->activeId = 0;
+ }
+ }
+}
+
+int glwImButton(glwWin *win, int id, int x, int y, char *text) {
+ glwImGui *imGUI = glwGetImGUI(win);
+ glwSize textSize = glwMeasureSystemText(win, text);
+ int width = textSize.width * (1 + GLW_HOR_AUTO_MARGIN * 2);
+ int height = textSize.height * (1 + GLW_VER_AUTO_MARGIN * 2);
+ glwImGUIActiveIdCheck(imGUI, id, x, y, width, height);
+ glwDrawButtonBackground(x, y, width, height,
+ imGUI->activeId == id ? GLW_CTRL_STATE_PRESS : GLW_CTRL_STATE_NORMAL);
+ glwDrawSystemText(win, x + textSize.width * GLW_HOR_AUTO_MARGIN,
+ y + textSize.height * GLW_VER_AUTO_MARGIN,
+ text);
+ imGUI->nextX = x + width;
+ imGUI->nextY = y;
+ return imGUI->activeId == id;
+}
+
+int glwImDropdownBox(glwWin *win, int id, int x, int y, char *text) {
+ glwImGui *imGUI = glwGetImGUI(win);
+ glwSize textSize = glwMeasureSystemText(win, text);
+ int arrowHeight = textSize.height * 0.3;
+ int arrowWidth = arrowHeight * 2;
+ int width = textSize.width * (1 + GLW_HOR_AUTO_MARGIN * 2) + arrowWidth * 3;
+ int height = textSize.height * (1 + GLW_VER_AUTO_MARGIN * 2);
+ glwImGUIActiveIdCheck(imGUI, id, x, y, width, height);
+ glwDrawButtonBackground(x, y, width, height,
+ imGUI->activeId == id ? GLW_CTRL_STATE_PRESS : GLW_CTRL_STATE_NORMAL);
+ glwDrawSystemText(win, x + textSize.width * (GLW_HOR_AUTO_MARGIN),
+ y + textSize.height * (GLW_VER_AUTO_MARGIN),
+ text);
+ glwDrawDropdownArrow(x + width - textSize.width * GLW_HOR_AUTO_MARGIN -
+ arrowWidth,
+ y + (height - arrowHeight) / 2, arrowWidth, arrowHeight, 0);
+ imGUI->nextX = x + width;
+ imGUI->nextY = y;
+ return imGUI->activeId == id;
+}
+
+int glwImCheck(glwWin *win, int id, int x, int y, char *text, int checked) {
+ glwImGui *imGUI = glwGetImGUI(win);
+ glwSize textSize = glwMeasureSystemText(win, text);
+ int height = textSize.height;
+ int boxWidth = height;
+ int width = boxWidth + textSize.height * (1 + GLW_HOR_AUTO_MARGIN * 2) +
+ textSize.width;
+ int oldActiveId = imGUI->activeId;
+ glwImGUIActiveIdCheck(imGUI, id, x, y, width, height);
+ glwDrawButtonBackground(x, y, boxWidth, height,
+ (imGUI->activeId == id || checked) ?
+ GLW_CTRL_STATE_PRESS : GLW_CTRL_STATE_NORMAL);
+ glwDrawSystemText(win, x + textSize.height * GLW_HOR_AUTO_MARGIN + boxWidth,
+ y, text);
+ if (checked) {
+ glwDrawCheckSymbol(x, y, boxWidth, height, GLW_CHECK_COLOR);
+ }
+ imGUI->nextX = x + width;
+ imGUI->nextY = y;
+ return (imGUI->activeId == id && oldActiveId != id) ? !checked : checked;
+}
+
+static int glwCalcListMaxWidth(glwWin *win, char **list, int *height,
+ int *len) {
+ int i;
+ int itemWidth = 0;
+ int maxItemWidth = 0;
+
+ for (i = 0; list[i]; ++i) {
+ glwSize textSize = glwMeasureSystemText(win, list[i]);
+ itemWidth = textSize.width * (1 + GLW_HOR_AUTO_MARGIN * 2);
+ if (itemWidth > maxItemWidth) {
+ maxItemWidth = itemWidth;
+ }
+ if (height && !(*height)) {
+ *height = textSize.height * (1 + GLW_VER_AUTO_MARGIN * 2);
+ }
+ if (len) {
+ ++(*len);
+ }
+ }
+
+ return maxItemWidth;
+}
+
+int glwImButtonGroup(glwWin *win, int id, int x, int y, int parentWidth,
+ char **list, int sel) {
+ glwImGui *imGUI = glwGetImGUI(win);
+ int width = 0;
+ int height = 0;
+ int left = 0;
+ int i;
+ int listLen = 0;
+ int offset;
+ int maxItemWidth = 0;
+ maxItemWidth = glwCalcListMaxWidth(win, list, &height, &listLen);
+ width = maxItemWidth * listLen;
+ left = listLen > 1 ? x + (parentWidth - width) / 2 :
+ x + maxItemWidth * GLW_HOR_AUTO_MARGIN;
+ glwImGUIActiveIdCheck(imGUI, id, left, y, width, height);
+ glwDrawRoundedRectGradientFill(left, y, width, height,
+ GLW_BUTTON_CORNER_RADIUS,
+ GLW_FILL_GRADIENT_COLOR_1, GLW_FILL_GRADIENT_COLOR_2);
+ for (i = 0, offset = left; list[i]; ++i) {
+ glwSize textSize = glwMeasureSystemText(win, list[i]);
+ if (imGUI->activeId == id) {
+ int hit = glwPointTest(imGUI->mouseX, imGUI->mouseY, offset, y,
+ maxItemWidth, height, 0);
+ if (hit) {
+ sel = i;
+ }
+ }
+ if (sel == i) {
+ if (1 == listLen) {
+ glwDrawRoundedRectGradientFill(left, y, width, height,
+ GLW_BUTTON_CORNER_RADIUS,
+ GLW_FILL_GRADIENT_COLOR_1_H, GLW_FILL_GRADIENT_COLOR_2_H);
+ } else {
+ if (0 == i) {
+ glwDrawLeftRoundedRectGradientFill(offset, y,
+ maxItemWidth, height,
+ GLW_BUTTON_CORNER_RADIUS,
+ GLW_FILL_GRADIENT_COLOR_1_H, GLW_FILL_GRADIENT_COLOR_2_H);
+ } else if (listLen - 1 == i) {
+ glwDrawRightRoundedRectGradientFill(offset, y,
+ maxItemWidth, height,
+ GLW_BUTTON_CORNER_RADIUS,
+ GLW_FILL_GRADIENT_COLOR_1_H, GLW_FILL_GRADIENT_COLOR_2_H);
+ } else {
+ glwDrawRectGradientFill(offset, y,
+ maxItemWidth, height,
+ GLW_FILL_GRADIENT_COLOR_1_H, GLW_FILL_GRADIENT_COLOR_2_H);
+ }
+ }
+ }
+ if (0 != i) {
+ glwDrawVLine(offset, y, 1, height, GLW_BORDER_COLOR_2);
+ }
+ glwDrawSystemText(win, offset + (maxItemWidth - textSize.width) / 2,
+ y + height * 0.1, list[i]);
+ offset += maxItemWidth;
+ }
+ imGUI->nextX = offset;
+ imGUI->nextY = y;
+ glwDrawRoundedRectBorder(left, y, width, height,
+ GLW_BUTTON_CORNER_RADIUS, GLW_BORDER_COLOR_2);
+ return sel;
+}
+
+int glwImTabBox(glwWin *win, int id, int x, int y, int width, int height,
+ char **list, int sel) {
+ glwImGui *imGUI = glwGetImGUI(win);
+ int tabWidth = 0;
+ int tabHeight = 0;
+ int left = 0;
+ int i;
+ int listLen = 0;
+ int offset;
+ int maxItemWidth = 0;
+ maxItemWidth = glwCalcListMaxWidth(win, list, &tabHeight, &listLen);
+ tabWidth = maxItemWidth * listLen;
+ left = x + maxItemWidth * GLW_HOR_AUTO_MARGIN / 2;
+ imGUI->nextX = x;
+ imGUI->nextY = y + tabHeight;
+ glwImGUIActiveIdCheck(imGUI, id, left, y, tabWidth, tabHeight);
+ for (i = 0, offset = left; list[i]; ++i) {
+ glwSize textSize = glwMeasureSystemText(win, list[i]);
+ if (imGUI->activeId == id) {
+ int hit = glwPointTest(imGUI->mouseX, imGUI->mouseY, offset, y,
+ maxItemWidth, tabHeight, 0);
+ if (hit) {
+ sel = i;
+ }
+ }
+ if (sel == i) {
+ glwDrawTopRoundedRectGradientFill(offset, y,
+ maxItemWidth, tabHeight,
+ GLW_BUTTON_CORNER_RADIUS,
+ GLW_TAB_FILL_GRADIENT_COLOR_1, GLW_TAB_FILL_GRADIENT_COLOR_2);
+ glwDrawTopRoundedRectBorder(offset, y,
+ maxItemWidth, tabHeight,
+ GLW_BUTTON_CORNER_RADIUS, GLW_BORDER_COLOR_1);
+ }
+ glwDrawSystemText(win, offset + (maxItemWidth - textSize.width) / 2,
+ y + tabHeight * GLW_VER_AUTO_MARGIN, list[i]);
+ offset += maxItemWidth;
+ }
+ glwDrawRectGradientFill(x + 1, y + tabHeight,
+ width - 2, height - tabHeight - 2,
+ GLW_BACKGROUND_COLOR, GLW_BACKGROUND_COLOR);
+ glwDrawHLine(x, y + tabHeight - 1, width, 1, GLW_BORDER_COLOR_1);
+ glwDrawHLine(x, y + height - 1, width, 1, GLW_BORDER_COLOR_1);
+ glwDrawVLine(x, y + tabHeight, 1, height - tabHeight,
+ GLW_BORDER_COLOR_1);
+ glwDrawVLine(x + width - 1, y + tabHeight, 1, height - tabHeight,
+ GLW_BORDER_COLOR_1);
+ return sel;
+}
+
+int glwImPanel(glwWin *win, int id, int x, int y, int width, int height) {
+ glwDrawRectGradientFill(x, y, width, height,
+ GLW_PANEL_FILL_COLOR, GLW_PANEL_FILL_COLOR);
+ glwDrawRoundedRectBorder(x, y, width, height,
+ GLW_BUTTON_CORNER_RADIUS, GLW_BORDER_COLOR_1);
+ return 0;
+}
+
+int glwImToolBar(glwWin *win, int id, int x, int y, int width, int height) {
+ glwImGui *imGUI = glwGetImGUI(win);
+ glwDrawRectGradientFill(x + 1, y + 1, width - 2, height - 2,
+ GLW_TOOLBAR_BACKGROUND_COLOR, GLW_TOOLBAR_BACKGROUND_COLOR);
+ glwDrawHLine(x, y + height - 1, width, 1, GLW_BORDER_COLOR_1);
+ imGUI->nextX = x;
+ imGUI->nextY = y + height;
+ return 0;
+}
+
+int glwImBottomBar(glwWin *win, int id, int x, int y, int width, int height) {
+ glwImGui *imGUI = glwGetImGUI(win);
+ glwDrawRectGradientFill(x + 1, y + 1, width - 2, height - 2,
+ GLW_TOOLBAR_BACKGROUND_COLOR, GLW_TOOLBAR_BACKGROUND_COLOR);
+ glwDrawHLine(x, y, width, 1, GLW_BORDER_COLOR_1);
+ imGUI->nextX = x;
+ imGUI->nextY = y - height;
+ return 0;
+}
+
+int glwImNextX(glwWin *win) {
+ glwImGui *imGUI = glwGetImGUI(win);
+ return imGUI->nextX;
+}
+
+int glwImNextY(glwWin *win) {
+ glwImGui *imGUI = glwGetImGUI(win);
+ return imGUI->nextY;
+}
+
+int glwImLineHeight(glwWin *win) {
+ glwSystemFontTexture *systemFontTexture = glwGetSystemFontTexture(win);
+ return systemFontTexture->originSize.height * (1 + GLW_VER_AUTO_MARGIN * 2);
+}
diff --git a/src/glw.h b/src/glw.h
new file mode 100644
index 00000000..e4106261
--- /dev/null
+++ b/src/glw.h
@@ -0,0 +1,70 @@
+#ifndef GLW_H
+#define GLW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct glwSize {
+ int width;
+ int height;
+} glwSize;
+
+typedef struct glwVec2 {
+ float x;
+ float y;
+} glwVec2;
+
+typedef struct glwWin glwWin;
+typedef struct glwFont glwFont;
+
+#define GLW_LEFT_BUTTON 1
+#define GLW_MIDDLE_BUTTON 2
+#define GLW_RIGHT_BUTTON 3
+
+#define GLW_DOWN 1
+#define GLW_UP 2
+
+void glwInit(void);
+void glwMainLoop(void);
+glwWin *glwCreateWindow(int x, int y, int width, int height);
+glwWin *glwCreateSubWindow(glwWin *parent, int x, int y, int width, int height);
+void glwSetUserData(glwWin *win, void *userData);
+void *glwGetUserData(glwWin *win);
+void glwDestroyWindow(glwWin *win);
+void glwSetWindowTitle(glwWin *win, char *name);
+void glwPositionWindow(glwWin *win, int x, int y);
+void glwReshapeWindow(glwWin *win, int width, int height);
+void glwDisplayFunc(glwWin *win, void (*func)(glwWin *win));
+void glwReshapeFunc(glwWin *win, void (*func)(glwWin *win, int width,
+ int height));
+void glwKeyboardFunc(glwWin *win, void (*func)(glwWin *win, unsigned char key,
+ int x, int y));
+void glwMouseFunc(glwWin *win, void (*func)(glwWin *win, int button, int state,
+ int x, int y));
+void glwMotionFunc(glwWin *win, void (*func)(glwWin *win, int x, int y));
+void glwPassiveMotionFunc(glwWin *win, void (*func)(glwWin *win, int x, int y));
+#define glwR(rgb) ((float)(((rgb) >> 16) & 0xff) / 255)
+#define glwG(rgb) ((float)(((rgb) >> 8) & 0xff) / 255)
+#define glwB(rgb) ((float)(((rgb)) & 0xff) / 255)
+int glwImButton(glwWin *win, int id, int x, int y, char *text);
+int glwImCheck(glwWin *win, int id, int x, int y, char *text, int checked);
+int glwImDropdownBox(glwWin *win, int id, int x, int y, char *text);
+int glwImButtonGroup(glwWin *win, int id, int x, int y, int parentWidth,
+ char **list, int sel);
+int glwImPanel(glwWin *win, int id, int x, int y, int width, int height);
+int glwImTabBox(glwWin *win, int id, int x, int y, int width, int height,
+ char **list, int sel);
+int glwImToolBar(glwWin *win, int id, int x, int y, int width, int height);
+int glwImBottomBar(glwWin *win, int id, int x, int y, int width, int height);
+int glwImNextX(glwWin *win);
+int glwImNextY(glwWin *win);
+int glwImLineHeight(glwWin *win);
+int glwPointTest(int x, int y, int left, int top, int width, int height,
+ int allowOffset);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/glw_internal.h b/src/glw_internal.h
new file mode 100644
index 00000000..746467f9
--- /dev/null
+++ b/src/glw_internal.h
@@ -0,0 +1,54 @@
+#ifndef GLW_INTERNAL_H
+#define GLW_INTERNAL_H
+#include "glw.h"
+#include "glw_style.h"
+
+#define GLW_SYSTEM_FONT_BEGIN_CHAR ' '
+#define GLW_SYSTEM_FONT_END_CHAR '~'
+#define GLW_SYSTEM_FONT_CHAR_NUM (GLW_SYSTEM_FONT_END_CHAR - GLW_SYSTEM_FONT_BEGIN_CHAR + 1)
+
+#define GLW_TEXT_ALIGN_LEFT 0
+#define GLW_TEXT_ALIGN_CENTER 1
+#define GLW_TEXT_ALIGN_RIGHT 2
+
+typedef enum glwCtrlState {
+ GLW_CTRL_STATE_NORMAL,
+ GLW_CTRL_STATE_PRESS,
+} glwCtrlState;
+
+typedef struct glwSystemFontTexture {
+ int texId;
+ glwSize size;
+ glwSize originSize;
+ float lefts[GLW_SYSTEM_FONT_CHAR_NUM];
+ int widths[GLW_SYSTEM_FONT_CHAR_NUM];
+} glwSystemFontTexture;
+
+typedef struct glwImGui {
+ int mouseButton;
+ int mouseState;
+ int mouseX;
+ int mouseY;
+ int activeId;
+ int nextX;
+ int nextY;
+} glwImGui;
+
+glwSize glwMeasureText(char *text, glwFont *font);
+unsigned char *glwRenderTextToRGBA(char *text, glwFont *font, glwSize size,
+ int *pixelsWide, int *pixelsHigh);
+void glwDrawText(int x, int y, char *text, glwFont *font);
+void glwDrawSystemText(glwWin *win, int x, int y, char *text);
+glwSize glwMeasureSystemText(glwWin *win, char *text);
+void glwInitSystemFontTexture(glwWin *win);
+void glwInitPrimitives(void);
+glwSystemFontTexture *glwGetSystemFontTexture(glwWin *win);
+void glwDestroyFont(glwFont *font);
+glwFont *glwCreateFont(char *name, int weight, int size, int bold);
+void glwDestroyFont(glwFont *font);
+void glwDrawButtonBackground(float x, float y, float width, float height,
+ glwCtrlState state);
+void glwMouseEvent(glwWin *win, int button, int state, int x, int y);
+glwImGui *glwGetImGUI(glwWin *win);
+
+#endif
diff --git a/src/glw_osx.m b/src/glw_osx.m
new file mode 100644
index 00000000..2c8107bf
--- /dev/null
+++ b/src/glw_osx.m
@@ -0,0 +1,345 @@
+#import
+#import
+#import
+#include "glw_internal.h"
+
+@interface GLView : NSOpenGLView {
+ CVDisplayLinkRef displayLink;
+@public
+ void (*onReshape)(glwWin *win, int width, int height);
+ void (*onDisplay)(glwWin *win);
+ void (*onMouse)(glwWin *win, int button, int state, int x, int y);
+ void (*onMotion)(glwWin *win, int x, int y);
+ void (*onPassiveMotion)(glwWin *win, int x, int y);
+ void *userData;
+ int pendingReshape;
+ int viewWidth;
+ int viewHeight;
+ float scaleX;
+ float scaleY;
+ glwSystemFontTexture systemFontTexture;
+ glwImGui imGUI;
+}
+
+- (CVReturn)getFrameForTime:(const CVTimeStamp *)outputTime;
+- (void)drawFrame;
+@end
+
+static CVReturn onDisplayLinkCallback(CVDisplayLinkRef displayLink,
+ const CVTimeStamp *now, const CVTimeStamp *outputTime,
+ CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext)
+{
+ CVReturn result = [(GLView *)displayLinkContext getFrameForTime:outputTime];
+ return result;
+}
+
+glwSystemFontTexture *glwGetSystemFontTexture(glwWin *win) {
+ GLView *view = ((NSWindow *)win).contentView;
+ return &view->systemFontTexture;
+}
+
+@implementation GLView
+- (id)initWithFrame:(NSRect)frameRect {
+ NSOpenGLPixelFormatAttribute attribs[] = {NSOpenGLPFAMultisample,
+ NSOpenGLPFASampleBuffers, 1,
+ NSOpenGLPFASamples, 0,
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAColorSize, 32,
+ NSOpenGLPFADepthSize, 24,
+ NSOpenGLPFAAlphaSize, 8,
+ NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy,
+ 0};
+ NSOpenGLPixelFormat *windowedPixelFormat = [[NSOpenGLPixelFormat alloc]
+ initWithAttributes:attribs];
+ self = [super initWithFrame:frameRect pixelFormat:windowedPixelFormat];
+ [windowedPixelFormat release];
+
+ [self setWantsBestResolutionOpenGLSurface:YES];
+
+ return self;
+}
+
+- (void) prepareOpenGL {
+ [super prepareOpenGL];
+
+ GLint vblSynch = 1;
+ [[self openGLContext] setValues:&vblSynch
+ forParameter:NSOpenGLCPSwapInterval];
+
+ CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
+ CVDisplayLinkSetOutputCallback(displayLink, onDisplayLinkCallback, self);
+ CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink,
+ [[self openGLContext] CGLContextObj],
+ [[self pixelFormat] CGLPixelFormatObj]);
+
+ CVDisplayLinkStart(displayLink);
+}
+
+- (void)drawFrame {
+ @autoreleasepool {
+ NSOpenGLContext *currentContext = [self openGLContext];
+ [currentContext makeCurrentContext];
+ CGLLockContext([currentContext CGLContextObj]);
+ if (self->pendingReshape) {
+ if (self->onReshape) {
+ self->pendingReshape = 0;
+ if (!self->systemFontTexture.texId) {
+ glwInitSystemFontTexture((glwWin *)self.window);
+ }
+ self->onReshape((glwWin *)self.window, self->viewWidth,
+ self->viewHeight);
+ }
+ }
+ if (self->onDisplay) {
+ self->onDisplay((glwWin *)self.window);
+ }
+ CGLFlushDrawable([[self openGLContext] CGLContextObj]);
+ CGLUnlockContext([currentContext CGLContextObj]);
+ }
+}
+
+- (CVReturn)getFrameForTime:(const CVTimeStamp *)outputTime {
+ [self drawFrame];
+ return kCVReturnSuccess;
+}
+
+- (void)dealloc {
+ CVDisplayLinkRelease(displayLink);
+ [super dealloc];
+}
+
+- (BOOL)acceptsFirstResponder {
+ return YES;
+}
+
+- (void)reshape {
+ NSRect bounds = [self bounds];
+ NSRect backingBounds = [self convertRectToBacking:[self bounds]];
+ viewWidth = (int)backingBounds.size.width;
+ viewHeight = (int)backingBounds.size.height;
+ self->scaleX = (float)viewWidth / bounds.size.width;
+ self->scaleY = (float)viewHeight / bounds.size.height;
+ self->pendingReshape = 1;
+ [self drawFrame];
+}
+
+- (void)resumeDisplayRenderer {
+ NSOpenGLContext *currentContext = [self openGLContext];
+ [currentContext makeCurrentContext];
+ CGLLockContext([currentContext CGLContextObj]);
+ CVDisplayLinkStart(displayLink);
+ CGLUnlockContext([currentContext CGLContextObj]);
+}
+
+- (void)haltDisplayRenderer {
+ NSOpenGLContext *currentContext = [self openGLContext];
+ [currentContext makeCurrentContext];
+ CGLLockContext([currentContext CGLContextObj]);
+ CVDisplayLinkStop(displayLink);
+ CGLUnlockContext([currentContext CGLContextObj]);
+}
+
+- (void)mouseMoved:(NSEvent*)event {
+ NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil];
+ int x = loc.x * self->scaleX;
+ int y = loc.y * self->scaleY;
+ if (GLW_DOWN == self->imGUI.mouseState) {
+ if (self->onMotion) {
+ self->onMotion((glwWin *)self.window, x, y);
+ }
+ } else {
+ if (self->onPassiveMotion) {
+ self->onPassiveMotion((glwWin *)self.window, x, y);
+ }
+ }
+}
+
+- (void)mouseDown:(NSEvent*)event {
+ NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil];
+ int x = loc.x * self->scaleX;
+ int y = loc.y * self->scaleY;
+ glwMouseEvent((glwWin *)self.window, GLW_LEFT_BUTTON, GLW_DOWN, x, y);
+ if (self->onMouse) {
+ self->onMouse((glwWin *)self.window, GLW_LEFT_BUTTON, GLW_DOWN, x, y);
+ }
+}
+
+- (void)mouseDragged:(NSEvent *)event {
+ NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil];
+ int x = loc.x * self->scaleX;
+ int y = loc.y * self->scaleY;
+ if (GLW_DOWN == self->imGUI.mouseState) {
+ if (GLW_DOWN == self->imGUI.mouseState) {
+ if (self->onMotion) {
+ self->onMotion((glwWin *)self.window, x, y);
+ }
+ } else {
+ if (self->onPassiveMotion) {
+ self->onPassiveMotion((glwWin *)self.window, x, y);
+ }
+ }
+ } else {
+ glwMouseEvent((glwWin *)self.window, GLW_LEFT_BUTTON, GLW_DOWN, x, y);
+ if (self->onMouse) {
+ self->onMouse((glwWin *)self.window, GLW_LEFT_BUTTON, GLW_DOWN, x, y);
+ }
+ }
+}
+
+- (BOOL)isFlipped {
+ return YES;
+}
+
+- (void)mouseUp:(NSEvent*)event {
+ NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil];
+ int x = loc.x * self->scaleX;
+ int y = loc.y * self->scaleY;
+ glwMouseEvent((glwWin *)self.window, GLW_LEFT_BUTTON, GLW_UP, x, y);
+ if (self->onMouse) {
+ self->onMouse((glwWin *)self.window, GLW_LEFT_BUTTON, GLW_UP, x, y);
+ }
+}
+@end
+
+glwImGui *glwGetImGUI(glwWin *win) {
+ GLView *view = ((NSWindow *)win).contentView;
+ return &view->imGUI;
+}
+
+glwFont *glwCreateFont(char *name, int weight, int size, int bold) {
+ NSString *fontFamily = [NSString stringWithCString:name
+ encoding:NSMacOSRomanStringEncoding];
+ NSFont *font = [[[NSFontManager sharedFontManager] fontWithFamily:fontFamily
+ traits:(bold ? NSBoldFontMask : NSUnboldFontMask) weight:weight size:size] retain];
+ return (glwFont *)font;
+}
+
+glwSize glwMeasureText(char *text, glwFont *font) {
+ NSString *aString = [NSString stringWithCString:text
+ encoding:NSMacOSRomanStringEncoding];
+ NSSize frameSize = [aString sizeWithAttributes:
+ [NSDictionary dictionaryWithObject:(NSFont *)font forKey:NSFontAttributeName]];
+ glwSize size = {frameSize.width, frameSize.height};
+ return size;
+}
+
+void glwInit(void) {
+ [NSApplication sharedApplication];
+ glwInitPrimitives();
+}
+
+void glwMainLoop(void) {
+ @autoreleasepool {
+ [NSApp run];
+ }
+}
+
+void glwSetUserData(glwWin *win, void *userData) {
+ GLView *view = ((NSWindow *)win).contentView;
+ view->userData = userData;
+}
+
+void *glwGetUserData(glwWin *win) {
+ GLView *view = ((NSWindow *)win).contentView;
+ return view->userData;
+}
+
+glwWin *glwCreateWindow(int x, int y, int width, int height) {
+ NSUInteger windowStyle = NSTitledWindowMask | NSClosableWindowMask |
+ NSResizableWindowMask | NSMiniaturizableWindowMask;
+ NSRect fullRect = [[NSScreen mainScreen] visibleFrame];
+
+ if (0 == width || 0 == height) {
+ width = fullRect.size.width;
+ height = fullRect.size.height;
+ }
+
+ NSRect viewRect = NSMakeRect(0, 0, width, height);
+ NSRect windowRect = NSMakeRect(x, y, width, height);
+
+ NSWindow *window = [[NSWindow alloc] initWithContentRect:windowRect
+ styleMask:windowStyle
+ backing:NSBackingStoreBuffered
+ defer:NO];
+
+ GLView *view = [[GLView alloc] initWithFrame:viewRect];
+ view->onReshape = 0;
+ view->onDisplay = 0;
+ view->onMouse = 0;
+ view->userData = 0;
+ view->pendingReshape = 0;
+ view->viewWidth = width;
+ view->viewHeight = height;
+ view->systemFontTexture.texId = 0;
+ memset(&view->imGUI, 0, sizeof(view->imGUI));
+ view->scaleX = 1;
+ view->scaleY = 1;
+ view->onPassiveMotion = 0;
+ view->onMotion = 0;
+
+ [window setAcceptsMouseMovedEvents:YES];
+ [window setContentView:view];
+ [window setDelegate:view];
+
+ [window orderFrontRegardless];
+
+ return (glwWin *)window;
+}
+
+void glwDisplayFunc(glwWin *win, void (*func)(glwWin *win)) {
+ GLView *view = ((NSWindow *)win).contentView;
+ view->onDisplay = func;
+}
+
+void glwReshapeFunc(glwWin *win, void (*func)(glwWin *win, int width,
+ int height)) {
+ GLView *view = ((NSWindow *)win).contentView;
+ view->onReshape = func;
+}
+
+void glwMouseFunc(glwWin *win, void (*func)(glwWin *win, int button, int state,
+ int x, int y)) {
+ GLView *view = ((NSWindow *)win).contentView;
+ view->onMouse = func;
+}
+
+void glwMotionFunc(glwWin *win,
+ void (*func)(glwWin *win, int x, int y)) {
+ GLView *view = ((NSWindow *)win).contentView;
+ view->onMotion = func;
+}
+
+void glwPassiveMotionFunc(glwWin *win,
+ void (*func)(glwWin *win, int x, int y)) {
+ GLView *view = ((NSWindow *)win).contentView;
+ view->onPassiveMotion = func;
+}
+
+unsigned char *glwRenderTextToRGBA(char *text, glwFont *font, glwSize size,
+ int *pixelsWide, int *pixelsHigh) {
+ NSString *aString = [NSString stringWithCString:text encoding:NSMacOSRomanStringEncoding];
+ NSSize frameSize = NSMakeSize(size.width, size.height);
+ NSImage *image = [[NSImage alloc] initWithSize:frameSize];
+ unsigned char *rgba = 0;
+ int rgbaBytes = 0;
+ [image lockFocus];
+ [aString drawAtPoint:NSMakePoint(0, 0) withAttributes:
+ [NSDictionary dictionaryWithObject:(NSFont *)font forKey:NSFontAttributeName]];
+ [image unlockFocus];
+ NSBitmapImageRep *bitmap = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
+ *pixelsWide = [bitmap pixelsWide];
+ *pixelsHigh = [bitmap pixelsHigh];
+ rgbaBytes = 4 * (*pixelsWide) * (*pixelsHigh);
+ rgba = malloc(rgbaBytes);
+ memcpy(rgba, [bitmap bitmapData], rgbaBytes);
+ [image release];
+ return rgba;
+}
+
+void glwDestroyFont(glwFont *font) {
+ NSFont *nsFont = (NSFont *)font;
+ [nsFont release];
+}
+
+
diff --git a/src/glw_style.h b/src/glw_style.h
new file mode 100644
index 00000000..cd71d4fc
--- /dev/null
+++ b/src/glw_style.h
@@ -0,0 +1,37 @@
+#ifndef GLW_STYLE_H
+#define GLW_STYLE_H
+
+#define GLW_SYSTEM_FONT_NAME "Helvetica"
+#define GLW_SYSTEM_FONT_WEIGHT 5
+#define GLW_SYSTEM_FONT_SIZE 20
+
+#define GLW_SMALL_ROUNDED_CORNER_SLICES 5
+
+#define GLW_BORDER_COLOR_1 0xa2a2a2
+#define GLW_BORDER_COLOR_2 0x616161
+
+#define GLW_FILL_GRADIENT_COLOR_1 0xffffff
+#define GLW_FILL_GRADIENT_COLOR_2 0xc6c4c5
+
+#define GLW_FILL_GRADIENT_COLOR_1_H 0x3795fa
+#define GLW_FILL_GRADIENT_COLOR_2_H 0x333333
+
+#define GLW_BUTTON_CORNER_RADIUS 5
+
+#define GLW_CHECK_COLOR 0x000000
+
+#define GLW_TAB_FILL_GRADIENT_COLOR_1 0xffffff
+#define GLW_TAB_FILL_GRADIENT_COLOR_2 0xc6c4c5
+
+#define GLW_TAB_FILL_GRADIENT_COLOR_1_H 0x3795fa
+#define GLW_TAB_FILL_GRADIENT_COLOR_2_H 0x333333
+
+#define GLW_PANEL_FILL_COLOR 0xe2e2e2
+
+#define GLW_HOR_AUTO_MARGIN 0.4
+#define GLW_VER_AUTO_MARGIN 0.15
+
+#define GLW_BACKGROUND_COLOR 0xfcfcfc
+#define GLW_TOOLBAR_BACKGROUND_COLOR 0xf5f5f5
+
+#endif
diff --git a/src/skinnedmesh.h b/src/skinnedmesh.h
index da73baf0..e3ab88ea 100644
--- a/src/skinnedmesh.h
+++ b/src/skinnedmesh.h
@@ -13,9 +13,14 @@ typedef struct skinnedMeshVertex {
} skinnedMeshVertex;
typedef struct skinnedMeshBone {
- vec3 translation;
+ vec3 position;
vec3 rotation;
matrix toRoot;
} skinnedMeshBone;
+typedef struct skinnedMesh skinnedMesh;
+
+skinnedMesh *skinnedMeshCreate(void);
+void skinnedMeshAddBone();
+
#endif
diff --git a/src/osutil.cpp b/src/util.c
similarity index 86%
rename from src/osutil.cpp
rename to src/util.c
index 744200d4..760aa7a8 100644
--- a/src/osutil.cpp
+++ b/src/util.c
@@ -1,5 +1,6 @@
-#include "osutil.h"
#include
+#include
+#include "osutil.h"
long long osGetMilliseconds(void) {
return (long long)QDateTime::currentMSecsSinceEpoch();
diff --git a/src/osutil.h b/src/util.h
similarity index 57%
rename from src/osutil.h
rename to src/util.h
index 5450cec9..cabe0e9d 100644
--- a/src/osutil.h
+++ b/src/util.h
@@ -5,8 +5,16 @@
extern "C" {
#endif
+#include
+
long long osGetMilliseconds(void);
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define unsued(param) (void)param
+
#ifdef __cplusplus
}
#endif