You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
6.0KB

  1. //
  2. // Copyright (c) 2013 Mikko Mononen memon@inside.org
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <float.h>
  21. #include <GLFW/glfw3.h>
  22. #define NANOSVG_IMPLEMENTATION
  23. #include "nanosvg.h"
  24. NSVGimage* g_image = NULL;
  25. static unsigned char bgColor[4] = {205,202,200,255};
  26. static unsigned char lineColor[4] = {0,160,192,255};
  27. static float distPtSeg(float x, float y, float px, float py, float qx, float qy)
  28. {
  29. float pqx, pqy, dx, dy, d, t;
  30. pqx = qx-px;
  31. pqy = qy-py;
  32. dx = x-px;
  33. dy = y-py;
  34. d = pqx*pqx + pqy*pqy;
  35. t = pqx*dx + pqy*dy;
  36. if (d > 0) t /= d;
  37. if (t < 0) t = 0;
  38. else if (t > 1) t = 1;
  39. dx = px + t*pqx - x;
  40. dy = py + t*pqy - y;
  41. return dx*dx + dy*dy;
  42. }
  43. static void cubicBez(float x1, float y1, float x2, float y2,
  44. float x3, float y3, float x4, float y4,
  45. float tol, int level)
  46. {
  47. float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
  48. float d;
  49. if (level > 12) return;
  50. x12 = (x1+x2)*0.5f;
  51. y12 = (y1+y2)*0.5f;
  52. x23 = (x2+x3)*0.5f;
  53. y23 = (y2+y3)*0.5f;
  54. x34 = (x3+x4)*0.5f;
  55. y34 = (y3+y4)*0.5f;
  56. x123 = (x12+x23)*0.5f;
  57. y123 = (y12+y23)*0.5f;
  58. x234 = (x23+x34)*0.5f;
  59. y234 = (y23+y34)*0.5f;
  60. x1234 = (x123+x234)*0.5f;
  61. y1234 = (y123+y234)*0.5f;
  62. d = distPtSeg(x1234, y1234, x1,y1, x4,y4);
  63. if (d > tol*tol) {
  64. cubicBez(x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1);
  65. cubicBez(x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1);
  66. } else {
  67. glVertex2f(x4, y4);
  68. }
  69. }
  70. void drawPath(float* pts, int npts, char closed, float tol)
  71. {
  72. int i;
  73. glBegin(GL_LINE_STRIP);
  74. glColor4ubv(lineColor);
  75. glVertex2f(pts[0], pts[1]);
  76. for (i = 0; i < npts-1; i += 3) {
  77. float* p = &pts[i*2];
  78. cubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], tol, 0);
  79. }
  80. if (closed) {
  81. glVertex2f(pts[0], pts[1]);
  82. }
  83. glEnd();
  84. }
  85. void drawControlPts(float* pts, int npts)
  86. {
  87. int i;
  88. // Control lines
  89. glColor4ubv(lineColor);
  90. glBegin(GL_LINES);
  91. for (i = 0; i < npts-1; i += 3) {
  92. float* p = &pts[i*2];
  93. glVertex2f(p[0],p[1]);
  94. glVertex2f(p[2],p[3]);
  95. glVertex2f(p[4],p[5]);
  96. glVertex2f(p[6],p[7]);
  97. }
  98. glEnd();
  99. // Points
  100. glPointSize(6.0f);
  101. glColor4ubv(lineColor);
  102. glBegin(GL_POINTS);
  103. glVertex2f(pts[0],pts[1]);
  104. for (i = 0; i < npts-1; i += 3) {
  105. float* p = &pts[i*2];
  106. glVertex2f(p[6],p[7]);
  107. }
  108. glEnd();
  109. // Points
  110. glPointSize(3.0f);
  111. glBegin(GL_POINTS);
  112. glColor4ubv(bgColor);
  113. glVertex2f(pts[0],pts[1]);
  114. for (i = 0; i < npts-1; i += 3) {
  115. float* p = &pts[i*2];
  116. glColor4ubv(lineColor);
  117. glVertex2f(p[2],p[3]);
  118. glVertex2f(p[4],p[5]);
  119. glColor4ubv(bgColor);
  120. glVertex2f(p[6],p[7]);
  121. }
  122. glEnd();
  123. }
  124. void drawframe(GLFWwindow* window)
  125. {
  126. int width = 0, height = 0;
  127. float view[4], cx, cy, hw, hh, aspect, px;
  128. NSVGshape* shape;
  129. NSVGpath* path;
  130. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
  131. glfwGetFramebufferSize(window, &width, &height);
  132. glViewport(0, 0, width, height);
  133. glClearColor(220.0f/255.0f, 220.0f/255.0f, 220.0f/255.0f, 1.0f);
  134. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  135. glEnable(GL_BLEND);
  136. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  137. glDisable(GL_TEXTURE_2D);
  138. glMatrixMode(GL_PROJECTION);
  139. glLoadIdentity();
  140. // Fit view to bounds
  141. cx = g_image->width*0.5f;
  142. cy = g_image->height*0.5f;
  143. hw = g_image->width*0.5f;
  144. hh = g_image->height*0.5f;
  145. if (width/hw < height/hh) {
  146. aspect = (float)height / (float)width;
  147. view[0] = cx - hw * 1.2f;
  148. view[2] = cx + hw * 1.2f;
  149. view[1] = cy - hw * 1.2f * aspect;
  150. view[3] = cy + hw * 1.2f * aspect;
  151. } else {
  152. aspect = (float)width / (float)height;
  153. view[0] = cx - hh * 1.2f * aspect;
  154. view[2] = cx + hh * 1.2f * aspect;
  155. view[1] = cy - hh * 1.2f;
  156. view[3] = cy + hh * 1.2f;
  157. }
  158. // Size of one pixel.
  159. px = (view[2] - view[1]) / (float)width;
  160. glOrtho(view[0], view[2], view[3], view[1], -1, 1);
  161. glMatrixMode(GL_MODELVIEW);
  162. glLoadIdentity();
  163. glDisable(GL_DEPTH_TEST);
  164. glColor4ub(255,255,255,255);
  165. glEnable(GL_BLEND);
  166. glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
  167. // Draw bounds
  168. glColor4ub(0,0,0,64);
  169. glBegin(GL_LINE_LOOP);
  170. glVertex2f(0, 0);
  171. glVertex2f(g_image->width, 0);
  172. glVertex2f(g_image->width, g_image->height);
  173. glVertex2f(0, g_image->height);
  174. glEnd();
  175. for (shape = g_image->shapes; shape != NULL; shape = shape->next) {
  176. for (path = shape->paths; path != NULL; path = path->next) {
  177. drawPath(path->pts, path->npts, path->closed, px * 1.5f);
  178. drawControlPts(path->pts, path->npts);
  179. }
  180. }
  181. glfwSwapBuffers(window);
  182. }
  183. void resizecb(GLFWwindow* window, int width, int height)
  184. {
  185. // Update and render
  186. NSVG_NOTUSED(width);
  187. NSVG_NOTUSED(height);
  188. drawframe(window);
  189. }
  190. int main()
  191. {
  192. GLFWwindow* window;
  193. const GLFWvidmode* mode;
  194. if (!glfwInit())
  195. return -1;
  196. mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
  197. window = glfwCreateWindow(mode->width - 40, mode->height - 80, "Nano SVG", NULL, NULL);
  198. if (!window)
  199. {
  200. printf("Could not open window\n");
  201. glfwTerminate();
  202. return -1;
  203. }
  204. glfwSetFramebufferSizeCallback(window, resizecb);
  205. glfwMakeContextCurrent(window);
  206. glEnable(GL_POINT_SMOOTH);
  207. glEnable(GL_LINE_SMOOTH);
  208. g_image = nsvgParseFromFile("../example/nano.svg", "px", 96.0f);
  209. if (g_image == NULL) {
  210. printf("Could not open SVG image.\n");
  211. glfwTerminate();
  212. return -1;
  213. }
  214. while (!glfwWindowShouldClose(window))
  215. {
  216. drawframe(window);
  217. glfwPollEvents();
  218. }
  219. nsvgDelete(g_image);
  220. glfwTerminate();
  221. return 0;
  222. }