1#include "sl.h"
2
3#include "internal/shaders.h"
4#include "internal/triangle.h"
5#include "internal/rectangle.h"
6#include "internal/circle.h"
7#include "internal/semicircle.h"
8#include "internal/point.h"
9#include "internal/line.h"
10#include "internal/sprite.h"
11#include "internal/text.h"
12#include "internal/sound.h"
13#include "internal/window.h"
14
15#include "util/transform.h"
16#include "util/images.h"
17
18#include "config.h"
19
20#ifdef __MINGW32__
21 #include "util/gldebugging.h"
22#endif
23
24#ifdef USE_GLES
25 #include <GLES2/gl2.h>
26 #include <GLES2/gl2ext.h>
27#else
28 #include <GL/glew.h>
29#endif
30
31#include <stdlib.h>
32#include <stdio.h>
33#include <stdint.h>
34
35#define SL_MATRIX_STACK_SIZE 32
36
37#define IDEAL_FRAME_TIME 0.01666667
38
39// private vars
40
41static int slMousePosX;
42static int slMousePosY;
43static uint8_t slMousePosStale = 1;
44
45static Mat4 slMatrixStack[SL_MATRIX_STACK_SIZE];
46static Mat4 *slCurrentMatrix = &slMatrixStack[0];
47static int slStackSize = 0;
48
49static Mat4 slProjectionMatrix;
50
51static Vec4 slForeColor;// = {.x = 1.0, .y = 1.0, .z = 1.0, .w = 1.0};
52
53static double slSpriteScrollX = 0.0;
54static double slSpriteScrollY = 0.0;
55static double slSpriteTilingX = 1.0;
56static double slSpriteTilingY = 1.0;
57
58static int slTextAlign = SL_ALIGN_LEFT;
59
60static double slDeltaTime = IDEAL_FRAME_TIME;
61static double slOldFrameTime = 0.0;
62static double slNewFrameTime = IDEAL_FRAME_TIME;
63
64// private function prototypes
65
66static void sliInitResources();
67static void sliKillResources();
68
69// window commands
70
71void slWindow(int width, int height, const char *title, int fullScreen)
72{
73 // error tracking for any window-creation issues we run into
74 #ifndef USE_GLES
75 GLenum error;
76 #endif
77
78 if(!sliIsWindowOpen())
79 {
80 // use either GLFW or PIGU to set up our window
81 sliOpenWindow(width, height, title, fullScreen);
82
83 // configure our viewing area
84 glViewport(0, 0, width, height);
85
86 // enable our extensions handler
87 #ifndef USE_GLES
88 glewExperimental = 1;
89 error = glewInit();
90 if(error != GLEW_OK)
91 {
92 fprintf(stderr, "slWindow() could not initialize GLEW: %s\n", glewGetErrorString(error));
93 exit(1);
94 }
95 #endif
96
97 // start with a clean error slate
98 glGetError();
99
100 // turn on OpenGL debugging
101 #ifdef DEBUG
102 initGLDebugger();
103 #endif
104
105 // turn on blending and turn depth testing off
106 glEnable(GL_BLEND);
107 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
108 glDisable(GL_DEPTH_TEST);
109
110 // camera view settings
111 slProjectionMatrix = ortho(0.0f, (double)width, 0.0f, (double)height);
112
113 // default colors
114 slSetBackColor(0.0, 0.0, 0.0);
115 slSetForeColor(1.0, 1.0, 1.0, 1.0);
116
117 // initialize any rendering resources
118 sliInitResources();
119
120 // initialize our first transformation matrix
121 *slCurrentMatrix = identity();
122 }
123 else
124 {
125 fprintf(stderr, "slWindow() cannot be called when a window already exists\n");
126 exit(1);
127 }
128}
129
130void slShowCursor(int showCursor)
131{
132 sliShowCursor(showCursor);
133}
134
135void slClose()
136{
137 if(sliIsWindowOpen())
138 {
139 sliKillResources();
140 sliCloseWindow();
141 }
142 else
143 {
144 fprintf(stderr, "slClose() cannot be called when no window exists\n");
145 exit(1);
146 }
147}
148
149int slShouldClose()
150{
151 if(!sliIsWindowOpen())
152 {
153 fprintf(stderr, "slShouldClose() cannot be called because no window exists\n");
154 exit(1);
155 }
156
157 return sliShouldClose();
158}
159
160// simple input
161
162int slGetKey(int key)
163{
164 return sliGetKey(key);
165}
166
167int slGetMouseButton(int button)
168{
169 return sliGetMouseButton(button);
170}
171
172int slGetMouseX()
173{
174 // make sure a render step has not occurred since we last read the mouse position
175 if(slMousePosStale)
176 {
177 sliGetMousePos(&slMousePosX, &slMousePosY);
178 slMousePosStale = 0;
179 }
180
181 return slMousePosX;
182}
183
184int slGetMouseY()
185{
186 // make sure a render step has not occurred since we last read the mouse position
187 if(slMousePosStale)
188 {
189 sliGetMousePos(&slMousePosX, &slMousePosY);
190 slMousePosStale = 0;
191 }
192
193 return slMousePosY;
194}
195
196// simple frame timing
197
198double slGetDeltaTime()
199{
200 return slDeltaTime;
201}
202
203double slGetTime()
204{
205 return sliGetTime();
206}
207
208// rendering/clearing commands
209
210void slRender()
211{
212 // value close enough to zero for delta time management
213 const double SL_MIN_DELTA_TIME = 0.00001; // tiny fraction of a second
214 const double SL_MAX_DELTA_TIME = 0.5; // half a second dt max
215
216 // render any leftover points or lines
217 sliPointsFlush();
218 sliLinesFlush();
219 sliTextFlush(slCurrentMatrix, &slForeColor);
220
221 // read any input events, show the back buffer, and clear the (previous) front buffer
222 sliPollAndSwap();
223 glClear(GL_COLOR_BUFFER_BIT);
224
225 // gather time values
226 slOldFrameTime = slNewFrameTime;
227 slNewFrameTime = sliGetTime();
228
229 // compute delta time value; ensure we don't have any long pauses or tiny time quantums
230 slDeltaTime = (slNewFrameTime - slOldFrameTime);
231 if(slDeltaTime < SL_MIN_DELTA_TIME)
232 slDeltaTime = SL_MIN_DELTA_TIME;
233 if(slDeltaTime > SL_MAX_DELTA_TIME)
234 slDeltaTime = SL_MAX_DELTA_TIME;
235
236 // set our mouse position as needing refreshing
237 slMousePosStale = 1;
238}
239
240// colour control
241
242void slSetBackColor(double red, double green, double blue)
243{
244 glClearColor((GLclampf)red, (GLclampf)green, (GLclampf)blue, 1.0);
245}
246
247void slSetForeColor(double red, double green, double blue, double alpha)
248{
249 slForeColor.x = (float)red;
250 slForeColor.y = (float)green;
251 slForeColor.z = (float)blue;
252 slForeColor.w = (float)alpha;
253}
254
255// blending control
256
257void slSetAdditiveBlend(int additiveBlend)
258{
259 sliPointsFlush();
260 sliLinesFlush();
261
262 glBlendFunc(GL_SRC_ALPHA, additiveBlend ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA);
263}
264
265// transformations
266
267void slPush()
268{
269 if(slStackSize < SL_MATRIX_STACK_SIZE - 1)
270 {
271 slStackSize ++;
272 slCurrentMatrix ++;
273 *slCurrentMatrix = *(slCurrentMatrix - 1);
274 }
275 else
276 {
277 fprintf(stderr, "slPush() exceeded maximum transform stack size of %d\n", SL_MATRIX_STACK_SIZE);
278 exit(1);
279 }
280}
281
282void slPop()
283{
284 if(slStackSize > 0)
285 {
286 slStackSize --;
287 slCurrentMatrix --;
288 }
289 else
290 {
291 fprintf(stderr, "slPop() cannot pop an empty transform stack\n");
292 exit(1);
293 }
294}
295
296void slTranslate(double x, double y)
297{
298 *slCurrentMatrix = translate(slCurrentMatrix, x, y);
299}
300
301void slRotate(double degrees)
302{
303 *slCurrentMatrix = rotate(slCurrentMatrix, degrees);
304}
305
306void slScale(double x, double y)
307{
308 *slCurrentMatrix = scale(slCurrentMatrix, x, y);
309}
310
311// texture loading
312
313int slLoadTexture(const char *filename)
314{
315 int result = -1;
316
317 if(sliIsWindowOpen())
318 {
319 result = (int)loadOpenGLTexture(filename);
320 }
321 else
322 {
323 fprintf(stderr, "slLoadTexture() cannot be called before slWindow() is called\n");
324 exit(1);
325 }
326
327 return result;
328}
329
330// sound loading and playing
331
332int slLoadWAV(const char *filename)
333{
334 int result = -1;
335
336 if(sliIsWindowOpen())
337 {
338 result = sliLoadWAV(filename);
339 }
340 else
341 {
342 fprintf(stderr, "slLoadWAV() cannot be called before slWindow() is called\n");
343 exit(1);
344 }
345
346 return result;
347}
348
349int slSoundPlay(int sound)
350{
351 return sliSoundPlay(sound);
352}
353
354int slSoundLoop(int sound)
355{
356 return sliSoundLoop(sound);
357}
358
359void slSoundPause(int sound)
360{
361 sliSoundPause(sound);
362}
363
364void slSoundStop(int sound)
365{
366 sliSoundStop(sound);
367}
368
369void slSoundPauseAll()
370{
371 sliSoundPauseAll();
372}
373
374void slSoundResumeAll()
375{
376 sliSoundResumeAll();
377}
378
379void slSoundStopAll()
380{
381 sliSoundStopAll();
382}
383
384int slSoundPlaying(int sound)
385{
386 return sliSoundPlaying(sound);
387}
388
389int slSoundLooping(int sound)
390{
391 return sliSoundLooping(sound);
392}
393
394// simple shape commands
395
396void slTriangleFill(double x, double y, double width, double height)
397{
398 Mat4 modelview = translate(slCurrentMatrix, x, y);
399 modelview = scale(&modelview, width, height);
400
401 sliPointsFlush();
402 sliLinesFlush();
403 sliTextFlush(slCurrentMatrix, &slForeColor);
404 sliTriangleFill(&modelview, &slForeColor);
405}
406
407void slTriangleOutline(double x, double y, double width, double height)
408{
409 Mat4 modelview = translate(slCurrentMatrix, x, y);
410 modelview = scale(&modelview, width, height);
411
412 sliPointsFlush();
413 sliLinesFlush();
414 sliTextFlush(slCurrentMatrix, &slForeColor);
415 sliTriangleOutline(&modelview, &slForeColor);
416}
417
418void slRectangleFill(double x, double y, double width, double height)
419{
420 Mat4 modelview = translate(slCurrentMatrix, x, y);
421 modelview = scale(&modelview, width, height);
422
423 sliPointsFlush();
424 sliLinesFlush();
425 sliTextFlush(slCurrentMatrix, &slForeColor);
426 sliRectangleFill(&modelview, &slForeColor);
427}
428
429void slRectangleOutline(double x, double y, double width, double height)
430{
431 Mat4 modelview = translate(slCurrentMatrix, x, y);
432 modelview = scale(&modelview, width, height);
433
434 sliPointsFlush();
435 sliLinesFlush();
436 sliTextFlush(slCurrentMatrix, &slForeColor);
437 sliRectangleOutline(&modelview, &slForeColor);
438}
439
440void slCircleFill(double x, double y, double radius, int numVertices)
441{
442 Mat4 modelview = translate(slCurrentMatrix, x, y);
443
444 sliPointsFlush();
445 sliLinesFlush();
446 sliTextFlush(slCurrentMatrix, &slForeColor);
447 sliCircleFill(&modelview, &slForeColor, radius, numVertices);
448}
449
450void slCircleOutline(double x, double y, double radius, int numVertices)
451{
452 Mat4 modelview = translate(slCurrentMatrix, x, y);
453
454 sliPointsFlush();
455 sliLinesFlush();
456 sliTextFlush(slCurrentMatrix, &slForeColor);
457 sliCircleOutline(&modelview, &slForeColor, radius, numVertices);
458}
459
460void slSemiCircleFill(double x, double y, double radius, int numVertices, double degrees)
461{
462 Mat4 modelview = translate(slCurrentMatrix, x, y);
463
464 sliPointsFlush();
465 sliLinesFlush();
466 sliTextFlush(slCurrentMatrix, &slForeColor);
467 sliSemiCircleFill(&modelview, &slForeColor, radius, numVertices, degrees);
468}
469
470void slSemiCircleOutline(double x, double y, double radius, int numVertices, double degrees)
471{
472 Mat4 modelview = translate(slCurrentMatrix, x, y);
473
474 sliPointsFlush();
475 sliLinesFlush();
476 sliTextFlush(slCurrentMatrix, &slForeColor);
477 sliSemiCircleOutline(&modelview, &slForeColor, radius, numVertices, degrees);
478}
479
480void slPoint(double x, double y)
481{
482 Mat4 modelview = translate(slCurrentMatrix, x, y);
483
484 sliLinesFlush();
485 sliTextFlush(slCurrentMatrix, &slForeColor);
486 sliPoint(&modelview, &slForeColor);
487}
488
489void slLine(double x1, double y1, double x2, double y2)
490{
491 Mat4 modelview1 = translate(slCurrentMatrix, x1, y1);
492 Mat4 modelview2 = translate(slCurrentMatrix, x2, y2);
493
494 sliPointsFlush();
495 sliTextFlush(slCurrentMatrix, &slForeColor);
496 sliLine(&slForeColor, modelview1.cols[3].x, modelview1.cols[3].y, modelview2.cols[3].x, modelview2.cols[3].y);
497}
498
499void slSetSpriteTiling(double x, double y)
500{
501 slSpriteTilingX = x;
502 slSpriteTilingY = y;
503}
504
505void slSetSpriteScroll(double x, double y)
506{
507 slSpriteScrollX = x;
508 slSpriteScrollY = y;
509}
510
511void slSprite(int texture, double x, double y, double width, double height)
512{
513 Mat4 modelview;
514
515 // this shorthand causes compiler errors on MSVC...
516 Vec2 tiling;// = {.x = slSpriteTilingX, .y = slSpriteTilingY};
517 Vec2 scroll;// = {.x = slSpriteScrollX, .y = slSpriteScrollY};
518
519 // ...so we do it the hard way instead
520 tiling.x = (float)slSpriteTilingX;
521 tiling.y = (float)slSpriteTilingY;
522 scroll.x = (float)slSpriteScrollX;
523 scroll.y = (float)slSpriteScrollY;
524
525 modelview = translate(slCurrentMatrix, x, y);
526 modelview = scale(&modelview, width, height);
527
528 sliPointsFlush();
529 sliLinesFlush();
530 sliTextFlush(slCurrentMatrix, &slForeColor);
531 sliSprite(&modelview, &slForeColor, (GLuint)texture, &tiling, &scroll);
532}
533
534// text commands
535
536void slSetTextAlign(int fontAlign)
537{
538 if(fontAlign >= 0 && fontAlign <= 2)
539 {
540 slTextAlign = fontAlign;
541 }
542 else
543 {
544 fprintf(stderr, "slSetTextAlign() only accepts SL_ALIGN_CENTER, SL_ALIGN_RIGHT, or SL_ALIGN_LEFT\n");
545 exit(1);
546 }
547}
548
549double slGetTextWidth(const char *text)
550{
551 return sliTextWidth(text);
552}
553
554double slGetTextHeight(const char *text)
555{
556 return sliTextHeight(text);
557}
558
559int slLoadFont(const char *fontFilename)
560{
561 int result = -1;
562
563 if(sliIsWindowOpen())
564 {
565 result = sliLoadFont(fontFilename);
566 }
567 else
568 {
569 fprintf(stderr, "slSetFont() cannot be called before slWindow() is called\n");
570 exit(1);
571 }
572
573 return result;
574}
575
576void slSetFont(int font, int fontSize)
577{
578 if(sliIsWindowOpen())
579 {
580 sliFont(font, fontSize);
581 }
582 else
583 {
584 fprintf(stderr, "slSetFont() cannot be called before slWindow() is called\n");
585 exit(1);
586 }
587}
588
589void slSetFontSize(int fontSize)
590{
591 sliFontSize(fontSize);
592}
593
594void slText(double x, double y, const char *text)
595{
596 Mat4 modelview = translate(slCurrentMatrix, x, y);
597
598 if(slTextAlign == SL_ALIGN_CENTER)
599 {
600 modelview = translate(&modelview, -slGetTextWidth(text) / 2.0, 0.0);
601 }
602 else if(slTextAlign == SL_ALIGN_RIGHT)
603 {
604 modelview = translate(&modelview, -slGetTextWidth(text), 0.0);
605 }
606
607 sliPointsFlush();
608 sliLinesFlush();
609 sliText(&modelview, &slForeColor, text);
610}
611
612// private functions
613
614void sliInitResources()
615{
616 slMousePosStale = 1;
617
618 slCurrentMatrix = &slMatrixStack[0];
619 slStackSize = 0;
620
621 slSpriteScrollX = 0.0;
622 slSpriteScrollY = 0.0;
623 slSpriteTilingX = 1.0;
624
625 slTextAlign = SL_ALIGN_LEFT;
626
627 slDeltaTime = IDEAL_FRAME_TIME;
628 slOldFrameTime = 0.0;
629 slNewFrameTime = IDEAL_FRAME_TIME;
630
631 sliShadersInit(&slProjectionMatrix);
632 sliTriangleInit();
633 sliRectangleInit();
634 sliCircleInit();
635 sliSemiCircleInit();
636 sliPointInit();
637 sliLineInit();
638 sliSpriteInit();
639 sliTextInit();
640 sliSoundInit();
641}
642
643void sliKillResources()
644{
645 sliTextDestroy();
646 sliSpriteDestroy();
647 sliLineDestroy();
648 sliPointDestroy();
649 sliCircleDestroy();
650 sliSemiCircleDestroy();
651 sliRectangleDestroy();
652 sliTriangleDestroy();
653 sliShadersDestroy();
654 sliSoundDestroy();
655}
656