ci.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. //
  2. // TIGR massage test, runs through most API functions
  3. // and performs basic sanity checks.
  4. //
  5. // Epilepsy warning: the tests will open windows quickly,
  6. // causing multicolored intense flashing!
  7. //
  8. #include "tigr.h"
  9. #include <stdio.h>
  10. #include <assert.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #ifdef _WIN32
  14. #include <winsock2.h>
  15. #include <GL/gl.h>
  16. #elif defined __linux__
  17. #include <GL/gl.h>
  18. #else
  19. #define GL_SILENCE_DEPRECATION
  20. #include <OpenGL/gl3.h>
  21. #endif
  22. void windowWithFlags(int flags) {
  23. Tigr* win = tigrWindow(100, 100, "CI", flags);
  24. tigrFill(win, 0, 0, win->w, win->h, tigrRGB(flags >> 1, 64, flags >> 1));
  25. tigrUpdate(win);
  26. assert(!tigrClosed(win));
  27. tigrFree(win);
  28. }
  29. void windowBasics() {
  30. windowWithFlags(0);
  31. }
  32. void windowFlags() {
  33. int flagsMax = TIGR_FULLSCREEN * 2 - 1;
  34. for (int flags = 0; flags < flagsMax; flags++) {
  35. windowWithFlags(flags);
  36. }
  37. }
  38. void offscreen() {
  39. Tigr* bmp = tigrBitmap(100, 100);
  40. assert(bmp != 0);
  41. assert(bmp->w == 100);
  42. assert(bmp->h == 100);
  43. bmp->pix[100 * 100 - 1] = tigrRGBA(1, 2, 3, 4);
  44. tigrFree(bmp);
  45. }
  46. static TPixel colors[5] = {
  47. { 0xff, 0x0, 0x0, 0xff }, { 0xff, 0xff, 0, 0xff }, { 0xff, 0x0, 0xff, 0xff },
  48. { 0x0, 0xff, 0xff, 0xff }, { 0x0, 0x0, 0x0, 0xff },
  49. };
  50. void drawFauxSierpinski(Tigr* bmp) {
  51. int scale = 255 / bmp->w + 1;
  52. for (int x = 0; x < bmp->w; x++) {
  53. for (int y = 0; y < bmp->h; y++) {
  54. int c = (((x & y) + (x ^ y)) * scale) & 0xff;
  55. tigrPlot(bmp, x, y, tigrRGBA(c, c, c, 220));
  56. }
  57. }
  58. }
  59. void drawTestPattern(Tigr* bmp) {
  60. int midW = bmp->w / 2;
  61. int midH = bmp->h / 2;
  62. const char* msg = "TIGR test Xy";
  63. int textHeight = tigrTextHeight(tfont, msg);
  64. int textWidth = tigrTextWidth(tfont, msg);
  65. tigrFill(bmp, 0, 0, bmp->w, bmp->h, colors[0]);
  66. tigrLine(bmp, 0, 0, midW, midH, colors[1]);
  67. tigrFill(bmp, midW, midH, midW, midH, colors[3]);
  68. tigrRect(bmp, midW, midH, midW, midH, colors[2]);
  69. tigrLine(bmp, 0, 10 + textHeight, bmp->w - 1, 10 + textHeight, colors[2]);
  70. tigrLine(bmp, 10 + textWidth, 0, 10 + textWidth, bmp->h - 1, colors[2]);
  71. tigrPrint(bmp, tfont, 10, 10, colors[1], "%s v%d", msg, 76);
  72. tigrPrint(bmp, tfont, 12, 12 + textHeight, colors[2], "%s v%d", msg, 76);
  73. tigrPrint(bmp, tfont, 14, 14 + 2 * textHeight, colors[3], "%s v%d", msg, 76);
  74. Tigr* fontImage = tigrLoadImage("5x7.png");
  75. assert(fontImage != 0);
  76. TigrFont* font = tigrLoadFont(fontImage, TCP_ASCII);
  77. assert(font != 0);
  78. tigrPrint(bmp, font, 10, midH - 10, colors[1], "*** TEENY TINY FONT ***");
  79. tigrFreeFont(font);
  80. fontImage = tigrLoadImage("ch.png");
  81. assert(fontImage != 0);
  82. font = tigrLoadFont(fontImage, TCP_UTF32);
  83. assert(font != 0);
  84. tigrPrint(bmp, font, 10, midH - 40, colors[4], "你好,世界!");
  85. tigrFreeFont(font);
  86. Tigr* img = tigrLoadImage("../tigr.png");
  87. tigrBlit(bmp, img, midW + 1, midH + 1, 42, 125, 70, 42);
  88. tigrBlitTint(bmp, img, midW + 11, midH + 16, 42, 125, 70, 42, colors[2]);
  89. tigrBlitAlpha(bmp, img, midW + 21, midH + 31, 42, 125, 70, 42, 0.5);
  90. Tigr* sierp = tigrBitmap(50, 50);
  91. drawFauxSierpinski(sierp);
  92. tigrBlitAlpha(bmp, sierp, 0, midH, 0, 0, sierp->w, sierp->h, 1);
  93. tigrBlitMode(bmp, TIGR_KEEP_ALPHA);
  94. tigrBlitAlpha(bmp, sierp, sierp->w, midH + sierp->h, 0, 0, sierp->w, sierp->h, 1);
  95. }
  96. void assertPixelsEqual(TPixel c1, TPixel c2) {
  97. assert(c1.r == c2.r);
  98. assert(c1.g == c2.g);
  99. assert(c1.b == c2.b);
  100. assert(c1.a == c2.a);
  101. }
  102. void assertBitmapsEqual(Tigr* a, Tigr* b) {
  103. assert(a->w == b->w);
  104. assert(a->h == b->h);
  105. for (int x = 0; x < a->w; x++) {
  106. for (int y = 0; y < a->h; y++) {
  107. TPixel c1 = tigrGet(a, x, y);
  108. TPixel c2 = tigrGet(b, x, y);
  109. assertPixelsEqual(c1, c2);
  110. }
  111. }
  112. }
  113. void verifyLineContract() {
  114. TPixel bg = tigrRGB(0, 0, 255);
  115. TPixel fg = tigrRGB(255, 0, 0);
  116. Tigr* bmp = tigrBitmap(10, 10);
  117. {
  118. // Single pixel line
  119. tigrClear(bmp, bg);
  120. tigrLine(bmp, 0, 0, 0, 1, fg);
  121. TPixel firstPixel = tigrGet(bmp, 0, 0);
  122. assertPixelsEqual(firstPixel, fg);
  123. TPixel lastPixel = tigrGet(bmp, 0, 1);
  124. assertPixelsEqual(lastPixel, bg);
  125. }
  126. {
  127. // Diagonal line, first pixel inclusive, last pixel exclusive
  128. tigrClear(bmp, bg);
  129. tigrLine(bmp, 0, 0, 9, 9, fg);
  130. TPixel firstPixel = tigrGet(bmp, 0, 0);
  131. assertPixelsEqual(firstPixel, fg);
  132. TPixel lastPixel = tigrGet(bmp, 9, 9);
  133. assertPixelsEqual(lastPixel, bg);
  134. TPixel nextToLastPixel = tigrGet(bmp, 8, 8);
  135. assertPixelsEqual(nextToLastPixel, fg);
  136. }
  137. tigrFree(bmp);
  138. }
  139. void verifyRectContract() {
  140. TPixel bg = tigrRGB(0, 0, 255);
  141. TPixel fg = tigrRGBA(255, 0, 0, 100);
  142. Tigr* ref = tigrBitmap(10, 10);
  143. tigrClear(ref, bg);
  144. Tigr* bmp = tigrBitmap(10, 10);
  145. {
  146. // Zero size rect
  147. tigrClear(bmp, bg);
  148. tigrRect(bmp, 0, 0, 0, 0, fg);
  149. assertBitmapsEqual(bmp, ref);
  150. }
  151. {
  152. // Zero width rect
  153. tigrClear(bmp, bg);
  154. tigrRect(bmp, 0, 0, 0, 5, fg);
  155. assertBitmapsEqual(bmp, ref);
  156. }
  157. {
  158. // Zero height rect
  159. tigrClear(bmp, bg);
  160. tigrRect(bmp, 0, 0, 5, 0, fg);
  161. assertBitmapsEqual(bmp, ref);
  162. }
  163. {
  164. // 2 pixel rect
  165. tigrClear(ref, bg);
  166. tigrPlot(ref, 0, 0, fg);
  167. tigrPlot(ref, 0, 1, fg);
  168. tigrPlot(ref, 1, 0, fg);
  169. tigrPlot(ref, 1, 1, fg);
  170. tigrClear(bmp, bg);
  171. tigrRect(bmp, 0, 0, 2, 2, fg);
  172. assertBitmapsEqual(bmp, ref);
  173. }
  174. {
  175. // 2x1 pixel rect
  176. tigrClear(ref, bg);
  177. tigrPlot(ref, 0, 0, fg);
  178. tigrPlot(ref, 1, 0, fg);
  179. tigrClear(bmp, bg);
  180. tigrRect(bmp, 0, 0, 2, 1, fg);
  181. assertBitmapsEqual(bmp, ref);
  182. }
  183. {
  184. // 1x2 pixel rect
  185. tigrClear(ref, bg);
  186. tigrPlot(ref, 0, 0, fg);
  187. tigrPlot(ref, 0, 1, fg);
  188. tigrClear(bmp, bg);
  189. tigrRect(bmp, 0, 0, 1, 2, fg);
  190. assertBitmapsEqual(bmp, ref);
  191. }
  192. {
  193. // 1 pixel rect
  194. tigrClear(ref, bg);
  195. tigrPlot(ref, 1, 1, fg);
  196. tigrClear(bmp, bg);
  197. tigrRect(bmp, 1, 1, 1, 1, fg);
  198. assertBitmapsEqual(bmp, ref);
  199. }
  200. tigrFree(bmp);
  201. tigrFree(ref);
  202. }
  203. void verifyDrawing() {
  204. verifyLineContract();
  205. verifyRectContract();
  206. Tigr* bmp = tigrBitmap(200, 200);
  207. drawTestPattern(bmp);
  208. #ifdef WRITE_REFERENCE
  209. tigrSaveImage("reference.png", bmp);
  210. #endif
  211. Tigr* loaded = tigrLoadImage("reference.png");
  212. assertBitmapsEqual(bmp, loaded);
  213. }
  214. void directOpenGL() {
  215. Tigr* win = tigrWindow(100, 100, "CI", 0);
  216. assert(tigrBeginOpenGL(win));
  217. glClearColor(1, 1, 0, 1);
  218. glClear(GL_COLOR_BUFFER_BIT);
  219. tigrUpdate(win);
  220. tigrFree(win);
  221. }
  222. void customShader() {
  223. Tigr* win = tigrWindow(100, 100, "CI", 0);
  224. const char shader[] =
  225. "void fxShader(out vec4 color, in vec2 uv) {"
  226. " vec2 tex_size = vec2(textureSize(image, 0));"
  227. " vec4 c = texture(image, (floor(uv * tex_size) + 0.5 * sin(parameters.x)) / tex_size);"
  228. " color = c;"
  229. "}\n";
  230. tigrSetPostShader(win, shader, sizeof(shader) - 1);
  231. tigrSetPostFX(win, 3.14 / 2, 0, 0, 0);
  232. tigrUpdate(win);
  233. tigrFree(win);
  234. }
  235. void timing() {
  236. float elapsed = tigrTime();
  237. assert(elapsed == 0);
  238. Tigr* win = tigrWindow(100, 100, "CI", 0);
  239. tigrUpdate(win);
  240. elapsed = tigrTime();
  241. assert(elapsed > 0 && elapsed < 1);
  242. }
  243. void input() {
  244. Tigr* win = tigrWindow(100, 100, "CI", 0);
  245. tigrUpdate(win);
  246. assert(tigrKeyHeld(win, TK_CONTROL) == tigrKeyDown(win, TK_CONTROL));
  247. assert(tigrReadChar(win) == 0);
  248. int nothing = 100000;
  249. int x = nothing;
  250. int y = nothing;
  251. int buttons = nothing;
  252. tigrMouse(win, &x, &y, &buttons);
  253. assert(buttons != nothing);
  254. assert(x != nothing);
  255. assert(y != nothing);
  256. TigrTouchPoint point;
  257. int touches = tigrTouch(win, &point, 1);
  258. assert(touches <= 1);
  259. }
  260. void unicode() {
  261. const int codePoints[] = { 0x00C4, 0x1F308, 'a' };
  262. const char utf8String[] = "Ä🌈a";
  263. int decoded = 0;
  264. const int* codePoint = codePoints;
  265. const char* utf8Char = utf8String;
  266. const char* lastChar = utf8Char;
  267. while (*utf8Char != 0 && (utf8Char = tigrDecodeUTF8(utf8Char, &decoded)) != 0) {
  268. assert(*codePoint == decoded);
  269. char buf[32];
  270. int len = tigrEncodeUTF8(buf, decoded) - buf;
  271. assert(strncmp(buf, lastChar, len) == 0);
  272. codePoint++;
  273. lastChar = utf8Char;
  274. }
  275. }
  276. typedef struct Test {
  277. const char* title;
  278. void (*test)(void);
  279. int level;
  280. } Test;
  281. int main(int argc, char* argv[]) {
  282. int limit = 1000;
  283. if (argc > 1) {
  284. limit = atoi(argv[1]);
  285. }
  286. Test tests[] = { { "Create offscreen", offscreen, 0 },
  287. { "Drawing API", verifyDrawing, 0 },
  288. { "Window basics", windowBasics, 1 },
  289. { "Unicode", unicode, 0 },
  290. { "Timing", timing, 1 },
  291. { "Custom fx shader", customShader, 2 },
  292. { "Direct OpenGL calls", directOpenGL, 2 },
  293. { "Input processing", input, 1 },
  294. { 0 } };
  295. for (Test* test = tests; test->title != 0; test++) {
  296. printf("%s...", test->title);
  297. if (test->level > limit) {
  298. printf("skipped\n");
  299. } else {
  300. test->test();
  301. printf("OK\n");
  302. }
  303. }
  304. if (argc == 2 && strcmp(argv[1], "full") == 0) {
  305. printf("Full window flag test...");
  306. windowFlags();
  307. printf("OK\n");
  308. }
  309. printf("*** All tests pass OK\n");
  310. return 0;
  311. }