- added animation in the test program to test timers
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 27 May 2020 06:57:27 +0000 (09:57 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 27 May 2020 06:57:27 +0000 (09:57 +0300)
- added cross-compile rules in the makefile
- clarified and expanded the README
- added the option to avoid linking with winmm on windows
- removed the GCC builtins as they were pulling math library symbols

.gitignore
Makefile
README.md
miniglut.c
miniglut.h
test.c

index 0932ecf..59a73c7 100644 (file)
@@ -2,3 +2,8 @@
 *.d
 *.swp
 test
+test.exe
+Debug/
+Release/
+*.obj
+*.suo
index 655a7d3..accf05a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,11 +3,31 @@ obj = $(src:.c=.o)
 bin = test
 
 CFLAGS = -pedantic -Wall -g
-LDFLAGS = -lX11 -lGL -lm
+
+sys ?= $(shell uname -s | sed 's/MINGW.*/mingw/')
+ifeq ($(sys), mingw)
+       obj = $(src:.c=.w32.o)
+       bin = test.exe
+
+       LDFLAGS = -mconsole -lopengl32 -lgdi32 -lwinmm
+else
+       LDFLAGS = -lX11 -lGL
+endif
 
 $(bin): $(obj)
        $(CC) -o $@ $(obj) $(LDFLAGS)
 
+%.w32.o: %.c
+       $(CC) -o $@ $(CFLAGS) -c $<
+
 .PHONY: clean
 clean:
        rm -f $(obj) $(bin)
+
+.PHONY: cross
+cross:
+       $(MAKE) CC=i686-w64-mingw32-gcc sys=mingw
+
+.PHONY: cross-clean
+cross-clean:
+       $(MAKE) CC=i686-w64-mingw32-gcc sys=mingw clean
index 5fa2bec..ed78af6 100644 (file)
--- a/README.md
+++ b/README.md
@@ -8,28 +8,62 @@ You can use MiniGLUT by simply dropping two files: `miniglut.h` and `miniglut.c`
 into your project source tree, or by building MiniGLUT as a static library and
 linking with it.
 
-MiniGLUT does not intend to replace a proper GLUT library like FreeGLUT for
-hacking OpenGL experiments and small programs. The purpose of MiniGLUT is to
-replace a proper GLUT library when it's time for release, in order to minimize
-runtime dependencies of the resulting binary.
+MiniGLUT does not intend to replace a full GLUT library, like FreeGLUT, for
+hacking small to medium OpenGL programs. The purpose of MiniGLUT is to
+potentially replace a full GLUT library when it's time for release, in order to
+minimize runtime dependencies of the resulting binary.
 
-A second reason is for porting UNIX OpenGL programs to Windows, especially when
-using the microsoft compiler, where setting up and linking with a proper
-3rd-party library like FreeGLUT is an ordeal in itself. Even more so if you
-decide to statically link, at which point you need to deal with the whole "MSVC
-runtime" chaos. Since MiniGLUT does not call any C library functions, even if
-you decide to link it as a static library, it will not affect your choice of
-MSVC runtime library.
+A second reason to use MiniGLUT is to ease porting of UNIX OpenGL programs to
+Windows, especially when using the microsoft compiler, where setting up and
+linking with a proper 3rd-party library is an ordeal in itself.  Even more so if
+you decide to statically link, at which point you need to deal with the whole
+"MSVC runtime" chaos. Even if you decide to link MiniGLUT as a static library,
+instead of dropping it in your code, it still won't present any MSVC runtime
+compatibility issues, since it doesn't call any C library functions whatsoever.
 
-Missing features
-----------------
+Build
+-----
+Under X11 MiniGLUT depends only on Xlib and OpenGL. Therefore to build a program
+using MiniGLUT you'll need to link with `-lX11 -lGL`.
+
+Under Windows MiniGLUT depends only on OpenGL, GDI and winmm. Therefore to build
+a program using MiniGLUT you'll need to link with `-lopengl32 -lgdi32 -lwinmm`.
+When building with MSVC, linking with the correct libraries is taken care by
+pragmas in the header file. If you wish to avoid the winmm dependency, define
+`MINIGLUT_NO_WINMM`.
+
+To avoid calling C library functions, MiniGLUT uses inline assembly code for
+system calls and trigonometric operations. This makes the default build
+incompatible with non-x86 systems, and with MSVC x64 builds. If you don't mind
+linking with the C library, you can define `MINIGLUT_USE_LIBC` to lift these
+limitations.
+
+License
+-------
+Copyright (C) 2020 John Tsiombikas <nuclear@member.fsf.org>
+
+MiniGLUT is free software. Feel free to use, modify and/or redistribute it,
+under the terms of the GNU General Public License v3, or at your option any
+newer version published by the Free Software Foundation. See COPYING for
+details.
+
+The intention is not to dictate a specific free software license (GPL) but to
+shut the door to proprietary programs. If you want to use MiniGLUT in a free
+software project with an incompatible license, contact me and we will figure out
+a way to enable that.
+
+To learn more about GPL-incompatible free software licenses where this might
+be an issue, see:
+https://www.gnu.org/licenses/license-list.en.html#GPLIncompatibleLicenses
+
+Known Issues
+------------
 MiniGLUT being a subset of GLUT, is missing a number of features. Some of them
 on purpose to keep it minimal, and some of them because I didn't happen to use
 them in a program I wanted to link with MiniGLUT yet.
 
 Missing GLUT features:
- - Only supported systems are UNIX with X11 (GLX) and Windows (WGL).
- - Indexed color contexts.
+ - The only supported systems are: UNIX with X11 (GLX), and Windows (WGL).
  - Multiple windows.
  - Subwindows.
  - Overlays.
@@ -52,25 +86,7 @@ Missing FreeGLUT features:
  - More missing primitives.
 
 If wish to let me know how much you need one of the missing features, or even
-better if you are volunteering to implement it yourself, contact me through
-through email at: nuclear@member.fsf.org
+better if you are volunteering to implement it yourself, send me an email at:
+nuclear@member.fsf.org
 
 Only plain-text emails, hard-wrapped at 72 columns will be accepted.
-
-License
--------
-Copyright (C) 2020 John Tsiombikas <nuclear@member.fsf.org>
-
-MiniGLUT is free software. Feel free to use, modify and/or redistribute it,
-under the terms of the GNU General Public License v3, or at your option any
-newer version published by the Free Software Foundation. See COPYING for
-details.
-
-The intention is not to dictate a specific free software license (GPL) but to
-shut the door to proprietary programs. If you want to use MiniGLUT in a free
-software project with an incompatible free software license, contact me, and we
-will figure out a way to enable that. Usually only other copyleft licenses are
-incompatible with the GPL. There's no issue with combining GPL code with code
-using other non-copyleft free software licenses like MIT/X11, 3-clause BSD, and
-so on.
-See: https://www.gnu.org/licenses/license-list.en.html#GPLIncompatibleLicenses
index 0038799..c9cc1f0 100644 (file)
@@ -15,24 +15,15 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
-/*#define MINIGLUT_GCC_NO_BUILTIN*/
-
 #ifdef MINIGLUT_USE_LIBC
 #define _GNU_SOURCE
 #include <stdlib.h>
 #include <math.h>
 #else
-
-#if defined(__GNUC__) && !defined(MINIGLUT_GCC_NO_BUILTIN)
-#define mglut_sincosf(a, s, c) __builtin_sincosf(a, s, c)
-#define mglut_atan(x)                  __builtin_atan(x)
-#else
 static void mglut_sincosf(float angle, float *sptr, float *cptr);
 static float mglut_atan(float x);
 #endif
 
-#endif
-
 #define PI     3.1415926536f
 
 #if defined(__unix__)
@@ -116,7 +107,7 @@ static glut_cb_sbbutton cb_sball_button;
 static int win_width, win_height;
 static int mapped;
 static int quit;
-static int upd_pending, reshape_pending;
+static int upd_pending;
 static int modstate;
 
 
@@ -809,16 +800,23 @@ void glutSetCursor(int cidx)
 static XVisualInfo *choose_visual(unsigned int mode)
 {
        XVisualInfo *vi;
-       int attr[32] = {
-               GLX_RGBA,
-               GLX_DOUBLEBUFFER,
-               GLX_RED_SIZE, 4,
-               GLX_GREEN_SIZE, 4,
-               GLX_BLUE_SIZE, 4
-       };
-       int *aptr = attr + 8;
+       int attr[32];
+       int *aptr = attr;
        int *samples = 0;
 
+       if(mode & GLUT_DOUBLE) {
+               *aptr++ = GLX_DOUBLEBUFFER;
+       }
+
+       if(mode & GLUT_INDEX) {
+               *aptr++ = GLX_BUFFER_SIZE;
+               *aptr++ = 1;
+       } else {
+               *aptr++ = GLX_RGBA;
+               *aptr++ = GLX_RED_SIZE; *aptr++ = 4;
+               *aptr++ = GLX_GREEN_SIZE; *aptr++ = 4;
+               *aptr++ = GLX_BLUE_SIZE; *aptr++ = 4;
+       }
        if(mode & GLUT_ALPHA) {
                *aptr++ = GLX_ALPHA_SIZE;
                *aptr++ = 4;
@@ -942,6 +940,8 @@ static void get_screen_size(int *scrw, int *scrh)
 
 /* --------------- windows implementation ----------------- */
 #ifdef BUILD_WIN32
+static int reshape_pending;
+
 static void update_modkeys(void);
 static int translate_vkey(int vkey);
 static void handle_mbutton(int bn, int st, WPARAM wparam, LPARAM lparam);
@@ -949,7 +949,7 @@ static void handle_mbutton(int bn, int st, WPARAM wparam, LPARAM lparam);
 void glutMainLoopEvent(void)
 {
        MSG msg;
-       
+
        if(!cb_display) {
                panic("display callback not set");
        }
@@ -1251,12 +1251,18 @@ static void get_screen_size(int *scrw, int *scrh)
 #if defined(__unix__) || defined(__APPLE__)
 #include <sys/time.h>
 
+#ifdef MINIGLUT_USE_LIBC
+#define sys_gettimeofday(tv, tz)       gettimeofday(tv, tz)
+#else
+static int sys_gettimeofday(struct timeval *tv, struct timezone *tz);
+#endif
+
 static long get_msec(void)
 {
        static struct timeval tv0;
        struct timeval tv;
 
-       gettimeofday(&tv, 0);
+       sys_gettimeofday(&tv, 0);
        if(tv0.tv_sec == 0 && tv0.tv_usec == 0) {
                tv0 = tv;
                return 0;
@@ -1268,12 +1274,18 @@ static long get_msec(void)
 static long get_msec(void)
 {
        static long t0;
+       long tm;
 
+#ifdef MINIGLUT_NO_WINMM
+       tm = GetTickCount();
+#else
+       tm = timeGetTime();
+#endif
        if(!t0) {
-               t0 = timeGetTime();
+               t0 = tm;
                return 0;
        }
-       return timeGetTime() - t0;
+       return tm - t0;
 }
 #endif
 
@@ -1297,9 +1309,14 @@ static int sys_write(int fd, const void *buf, int count)
        return write(fd, buf, count);
 }
 
+static int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+       return gettimeofday(tv, tz);
+}
+
 #else  /* !MINIGLUT_USE_LIBC */
 
-#if defined(__GNUC__) && defined(MINIGLUT_GCC_NO_BUILTIN)
+#ifdef __GNUC__
 static void mglut_sincosf(float angle, float *sptr, float *cptr)
 {
        asm volatile(
@@ -1377,8 +1394,7 @@ static void sys_exit(int status)
 {
        asm volatile(
                "syscall\n\t"
-               :: "a"(60), "D"(status)
-       );
+               :: "a"(60), "D"(status));
 }
 static int sys_write(int fd, const void *buf, int count)
 {
@@ -1386,8 +1402,16 @@ static int sys_write(int fd, const void *buf, int count)
        asm volatile(
                "syscall\n\t"
                : "=a"(res)
-               : "a"(1), "D"(fd), "S"(buf), "d"(count)
-       );
+               : "a"(1), "D"(fd), "S"(buf), "d"(count));
+       return res;
+}
+static int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+       int res;
+       asm volatile(
+               "syscall\n\t"
+               : "=a"(res)
+               : "a"(96), "D"(tv), "S"(tz));
        return res;
 }
 #endif
@@ -1395,19 +1419,25 @@ static int sys_write(int fd, const void *buf, int count)
 static void sys_exit(int status)
 {
        asm volatile(
-               "mov $1, %%eax\n\t"
                "int $0x80\n\t"
-               :: "b"(status)
-               : "eax"
-       );
+               :: "a"(1), "b"(status));
 }
 static int sys_write(int fd, const void *buf, int count)
 {
        int res;
        asm volatile(
-               "mov $4, %%eax\n\t"
                "int $0x80\n\t"
-               :: "b"(fd), "c"(buf), "d"(count));
+               : "=a"(res)
+               : "a"(4), "b"(fd), "c"(buf), "d"(count));
+       return res;
+}
+static int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+       int res;
+       asm volatile(
+               "int $0x80\n\t"
+               : "=a"(res)
+               : "a"(78), "b"(tv), "c"(tz));
        return res;
 }
 #endif
@@ -1421,7 +1451,7 @@ static void sys_exit(int status)
 }
 static int sys_write(int fd, const void *buf, int count)
 {
-       int wrsz;
+       unsigned long wrsz = 0;
 
        HANDLE out = GetStdHandle(fd == 1 ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
        if(!WriteFile(out, buf, count, &wrsz, 0)) {
index 56d7a97..f5b2daf 100644 (file)
@@ -24,7 +24,9 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 #ifdef _MSC_VER
 #pragma comment (lib, "opengl32")
+#ifndef MINIGLUT_NO_WINMM
 #pragma comment (lib, "winmm")
+#endif
 #endif /* MSVC */
 
 #endif
diff --git a/test.c b/test.c
index 45db5d6..780c018 100644 (file)
--- a/test.c
+++ b/test.c
@@ -1,5 +1,6 @@
 #include "miniglut.h"
 
+void idle(void);
 void display(void);
 void reshape(int x, int y);
 void keypress(unsigned char key, int x, int y);
@@ -9,6 +10,7 @@ void motion(int x, int y);
 float cam_theta, cam_phi = 25, cam_dist = 8;
 int mouse_x, mouse_y;
 int bnstate[8];
+int anim;
 
 int main(int argc, char **argv)
 {
@@ -32,10 +34,18 @@ int main(int argc, char **argv)
        return 0;
 }
 
+void idle(void)
+{
+       glutPostRedisplay();
+}
 
 void display(void)
 {
+       long tm;
        float lpos[] = {-1, 2, 3, 0};
+
+       tm = glutGet(GLUT_ELAPSED_TIME);
+
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
        glMatrixMode(GL_MODELVIEW);
@@ -46,7 +56,14 @@ void display(void)
 
        glLightfv(GL_LIGHT0, GL_POSITION, lpos);
 
+       glPushMatrix();
+       if(anim) {
+               glRotatef(tm / 10.0f, 1, 0, 0);
+               glRotatef(tm / 10.0f, 0, 1, 0);
+       }
        glutSolidTorus(0.3, 1, 16, 24);
+       glPopMatrix();
+
        glutSolidSphere(0.4, 16, 8);
 
        glPushMatrix();
@@ -84,8 +101,17 @@ void reshape(int x, int y)
 
 void keypress(unsigned char key, int x, int y)
 {
-       if(key == 27 || key == 'q') {
+       switch(key) {
+       case 27:
+       case 'q':
                glutExit();
+               break;
+
+       case ' ':
+               anim ^= 1;
+               glutIdleFunc(anim ? idle : 0);
+               glutPostRedisplay();
+               break;
        }
 }