Rewrote API simulator from scratch for Win32 since Cygwin ceased support for Win32's native OpenGL libraries.

This commit is contained in:
Christian Kroll 2012-10-17 08:29:41 +00:00
parent 3e7ee74414
commit 971901e453
10 changed files with 1080 additions and 464 deletions

View File

@ -21,7 +21,7 @@ LIBS = -lm
# flags for the compiler
CFLAGS ?= -Wall -W -Wno-unused-parameter -Wno-sign-compare
CFLAGS += -g -Os -std=gnu99 -fgnu89-inline -D_XOPEN_SOURCE=600 -DNDEBUG
CFLAGS += -g -Os -std=gnu99 -mstrict-X -fgnu89-inline -D_XOPEN_SOURCE=600 -DNDEBUG
# flags for the linker
LDFLAGS += -T ./avr5.x -Wl,-Map,image.map -mmcu=$(MCU)
@ -35,13 +35,13 @@ MACHINE = $(shell uname -m)
#$(info $(OSTYPE))
ifeq ($(OSTYPE),cygwin)
CFLAGS_SIM = -g -Wall -pedantic -std=c99 -O0 -D_WIN32 -mno-cygwin -D_XOPEN_SOURCE=600
LDFLAGS_SIM = -Wl -mno-cygwin -T simulator/i386pe.x
LIBS_SIM = -lglut32 -lglu32 -lopengl32 -lm
CFLAGS_SIM = -g -Wall -pedantic -std=c99 -O0 -D_WIN32 -D_XOPEN_SOURCE=600
LDFLAGS_SIM = -Wl -T simulator/i386pe.x
LIBS_SIM = -lgdi32 -lwinmm -lm
else
CFLAGS_SIM = -g -Wall -pedantic -std=c99 -O0 -D_XOPEN_SOURCE=600
CFLAGS_SIM = -g -g -Wall -pedantic -std=c99 -O0 -D_XOPEN_SOURCE=600
ifeq ($(MACHINE),x86_64)
LDFLAGS_SIM = -Wl -T simulator/elf_x86_64.x
LDFLAGS_SIM = -g -Wl -T simulator/elf_x86_64.x
else
LDFLAGS_SIM = -Wl -T simulator/elf_i386.x
endif

View File

@ -3,7 +3,10 @@ TOPDIR = ..
include $(TOPDIR)/defaults.mk
SRC_SIM = main.c trackball.c util.c eeprom.c
ifeq ($(OSTYPE),cygwin)
SRC_SIM = winmain.c trackball.c eeprom.c
else
SRC_SIM = main.c trackball.c eeprom.c
endif
include $(TOPDIR)/rules.mk

View File

@ -1,6 +1,6 @@
/* Default linker script, for normal executables */
OUTPUT_FORMAT(pei-i386)
SEARCH_DIR("/usr/i686-pc-cygwin/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/lib/w32api");
SEARCH_DIR("/usr/i686-cygwin/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/lib/w32api");
SECTIONS
{
/* Make the virtual address and file offset synced if the alignment is
@ -12,6 +12,8 @@ SECTIONS
*(.init)
*(.text)
*(SORT(.text$*))
*(.text.*)
*(.gnu.linkonce.t.*)
*(.glue_7t)
*(.glue_7)
___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
@ -28,7 +30,7 @@ SECTIONS
on fork. This used to be named ".data". The linker used
to include this between __data_start__ and __data_end__, but that
breaks building the cygwin32 dll. Instead, we name the section
".data_cygwin_nocopy" and explictly include it after __data_end__. */
".data_cygwin_nocopy" and explicitly include it after __data_end__. */
.data BLOCK(__section_alignment__) :
{
__data_start__ = . ;
@ -41,19 +43,25 @@ SECTIONS
__game_descriptors_start__ = . ;
*(.game_descriptors)
__game_descriptors_end__ = . ;
__data_end__ = . ;
__data_end__ = . ;
*(.data_cygwin_nocopy)
}
.rdata BLOCK(__section_alignment__) :
{
*(.rdata)
*(SORT(.rdata$*))
*(.eh_frame)
___RUNTIME_PSEUDO_RELOC_LIST__ = .;
__RUNTIME_PSEUDO_RELOC_LIST__ = .;
__rt_psrelocs_start = .;
*(.rdata_runtime_pseudo_reloc)
___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
__RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
__rt_psrelocs_end = .;
}
__rt_psrelocs_size = __rt_psrelocs_end - __rt_psrelocs_start;
___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
__RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
___RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;
__RUNTIME_PSEUDO_RELOC_LIST__ = . - __rt_psrelocs_size;
.eh_frame BLOCK(__section_alignment__) :
{
*(.eh_frame*)
}
.pdata BLOCK(__section_alignment__) :
{
@ -76,6 +84,8 @@ SECTIONS
*(.debug$T)
*(.debug$F)
*(.drectve)
*(.note.GNU-stack)
*(.gnu.lto_*)
}
.idata BLOCK(__section_alignment__) :
{
@ -86,7 +96,9 @@ SECTIONS
/* These zeroes mark the end of the import list. */
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
SORT(*)(.idata$4)
__IAT_start__ = .;
SORT(*)(.idata$5)
__IAT_end__ = .;
SORT(*)(.idata$6)
SORT(*)(.idata$7)
}
@ -153,10 +165,14 @@ SECTIONS
{
*(.debug_pubnames)
}
.debug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_pubtypes)
}
/* DWARF 2. */
.debug_info BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_info) *(.gnu.linkonce.wi.*)
*(.debug_info .gnu.linkonce.wi.*)
}
.debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
{
@ -168,7 +184,7 @@ SECTIONS
}
.debug_frame BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_frame)
*(.debug_frame*)
}
.debug_str BLOCK(__section_alignment__) (NOLOAD) :
{
@ -199,9 +215,18 @@ SECTIONS
{
*(.debug_varnames)
}
.debug_macro BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_macro)
}
/* DWARF 3. */
.debug_ranges BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_ranges)
}
/* DWARF 4. */
.debug_types BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_types .gnu.linkonce.wt.*)
}
}

View File

@ -1,9 +0,0 @@
#include "joystick.h"
unsigned char fakeport;
// fake function since our keybord doesn't need any initialisation
void joy_init()
{
}

View File

@ -1,15 +0,0 @@
#ifndef JOYSTICK_H_
#define JOYSTICK_H_
extern unsigned char fakeport;
#define JOYISFIRE (0x01 & fakeport)
#define JOYISLEFT (0x02 & fakeport)
#define JOYISRIGHT (0x04 & fakeport)
#define JOYISDOWN (0x08 & fakeport)
#define JOYISUP (0x10 & fakeport)
unsigned char waitForFire;
#endif /*JOYSTICK_H_*/

View File

@ -1,46 +1,82 @@
#ifdef _WIN32
#include <GL/glut.h>
#include <windows.h>
#include <process.h>
#define pthread_t int
/**
* \defgroup unixsimulator Simulation of the Borg API for UNIX like platforms.
*/
/*@{*/
/**
* @file main.c
* @brief Simulator for Unix like platforms.
* @author Martin Ongsiek, Peter Fuhrmann, Christian Kroll
*/
#ifdef OSX_
#include <GLUT/glut.h>
#else
#ifdef OSX_
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <pthread.h> // for threads in linux
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <GL/glut.h>
#endif
#include <pthread.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <setjmp.h>
#include "../config.h"
#include "../display_loop.h"
#include "../pixel.h"
#include "trackball.h"
unsigned char fakeport;
volatile unsigned char oldMode, oldOldmode, mode;
extern unsigned char waitForFire;
/** Number of bytes per row. */
#define LINEBYTES ((NUM_COLS + 1) / 8)
/** Fake port for simulating joystick input. */
volatile unsigned char fakeport;
/** Flag which indicates if wait should jump to the menu if fire is pressed. */
volatile unsigned char waitForFire;
/** The simulated frame buffer of the borg. */
volatile unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES];
/** Jump buffer which leads directly the menu. */
extern jmp_buf newmode_jmpbuf;
int WindWidth, WindHeight;
/** Width of the window. */
int WindWidth;
/** Height of the window. */
int WindHeight;
unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES];
unsigned char joystick;
/** Rotation of the x-axis of the scene. */
float view_rotx = 0;
/** Rotation of the y-axis of the scene. */
float view_roty = 0;
/** Rotation of the z-axis of the scene. */
float view_rotz = 0;
float view_rotx = 0, view_roty = 0, view_rotz = 0;
/** GLUT window handle. */
int win;
pthread_t simthread;
GLUquadric* quad;
/**
* Simple wait function.
* @param ms The requested delay in milliseconds.
*/
void wait(unsigned int ms) {
if (waitForFire) {
if (fakeport & 0x01) {
longjmp(newmode_jmpbuf, 43);
}
}
usleep(ms * 1000);
}
/**
* Draw a LED in the given color (which is a list).
* @param color List which contains a sphere.
* @param pos_x x-coordinate
* @param pos_y y-coordinate
* @param pos_z z-coordinate
*/
void drawLED(int color, float pos_x, float pos_y, float pos_z) {
glPushMatrix();
glTranslatef(pos_x, pos_y, pos_z);
@ -48,175 +84,216 @@ void drawLED(int color, float pos_x, float pos_y, float pos_z) {
glPopMatrix();
}
void display(void){
int x, y, z, level, color;
tbReshape(WindWidth, WindHeight);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glTranslatef(NUM_COLS*2., 0., NUM_ROWS*2.);
/**
* Draws the LED matrix.
*/
void display(void) {
int x, y, z, level, color;
tbReshape(WindWidth, WindHeight);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glTranslatef(NUM_COLS * 2., 0., NUM_ROWS * 2.);
tbMatrix();
glRotatef(view_rotx, 1.0, 0.0, 0.0);
glRotatef(view_roty, 0.0, 1.0, 0.0);
glRotatef(view_rotx, 1.0, 0.0, 0.0);
glRotatef(view_roty, 0.0, 1.0, 0.0);
glRotatef(view_rotz, 0.0, 0.0, 1.0);
glTranslatef(-NUM_COLS*2, 0., -NUM_ROWS*2.);
for (x = 0; x < 1; x++) {
glTranslatef(-NUM_COLS * 2, 0., -NUM_ROWS * 2.);
for (x = 0; x < 1; x++) {
for (y = 0; y < NUM_COLS; y++) {
for (z = 0; z < NUM_ROWS; z++) {
color = 0;
for (level = 0; level < NUMPLANE; level++) {
if (pixmap[level][z%NUM_ROWS][y/8] & (1 << y % 8)) {
color = level+1;
if (pixmap[level][z % NUM_ROWS][y / 8] & (1 << y % 8)) {
color = level + 1;
}
}
drawLED(color, (float)y*4.0,
(float)x*4.0,
(float)(NUM_ROWS-1-z)*4.0);
drawLED(color, (float) y * 4.0, (float) x * 4.0,
(float) (NUM_ROWS - 1 - z) * 4.0);
}
}
}
}
glPopMatrix();
glutSwapBuffers();
#ifdef _WIN32
Sleep(10);
#else
usleep(20000);
#endif
joystick = 255;
}
void keyboard(unsigned char key, int x, int y){
/**
* Handler for processing key presses.
* @param key The pressed key encoded in ASCII.
* @param x X-position of the mouse pointer.
* @param y Y-position of the mouse pointer.
*/
void keyboard(unsigned char key, int x, int y) {
switch (key) {
case 'q': printf("Quit\n");
glutDestroyWindow(win);
exit(0);
break;
case ' ':
fakeport |= 0x01;
break;
case 'a':
fakeport |= 0x02;
break;
case 'd':
fakeport |= 0x04;
break;
case 's':
fakeport |= 0x08;
break;
case 'w':
fakeport |= 0x10;
break;
case 'q':
printf("Quit\n");
glutDestroyWindow(win);
exit(0);
break;
case ' ':
fakeport |= 0x01;
break;
case 'a':
fakeport |= 0x02;
break;
case 'd':
fakeport |= 0x04;
break;
case 's':
fakeport |= 0x08;
break;
case 'w':
fakeport |= 0x10;
break;
}
}
void keyboardup(unsigned char key, int x, int y){
/**
* Handler for processing key releases.
* @param key The released key encoded in ASCII.
* @param x X-position of the mouse pointer.
* @param y Y-position of the mouse pointer.
*/
void keyboardup(unsigned char key, int x, int y) {
switch (key) {
case ' ':
fakeport &= ~0x01;
break;
case 'a':
fakeport &= ~0x02;
break;
case 'd':
fakeport &= ~0x04;
break;
case 's':
fakeport &= ~0x08;
break;
case 'w':
fakeport &= ~0x10;
break;
case ' ':
fakeport &= ~0x01;
break;
case 'a':
fakeport &= ~0x02;
break;
case 'd':
fakeport &= ~0x04;
break;
case 's':
fakeport &= ~0x08;
break;
case 'w':
fakeport &= ~0x10;
break;
}
}
void mouse(int button, int state, int x, int y)
{
tbMouse(button, state, x, y);
/**
* Relays mouse position and button state to the trackball implementation.
* @param button Currently monitored button.
* @param state State of that button.
* @param x X-position of the mouse pointer.
* @param y Y-position of the mouse pointer.
*/
void mouse(int button, int state, int x, int y) {
tbMouse(button, state, x, y);
}
void motion(int x, int y)
{
tbMotion(x, y);
/**
* Relays motion request to the trackball implementation.
* @param x X-position for the motion direction.
* @param y Y-position for the motion direction.
*/
void motion(int x, int y) {
tbMotion(x, y);
}
void reshape(int width, int height)
{
/**
* Updating the window size.
* @param width Width of the window.
* @param height Height of the window.
*/
void reshape(int width, int height) {
tbReshape(width, height);
tbReshape(width, height);
glViewport(0, 0, width, height);
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (float)WindWidth/(float)WindWidth, 5., 1000.);
gluLookAt(NUM_ROWS*2., NUM_ROWS*2.+50., NUM_COLS*2.,
NUM_ROWS*2., NUM_ROWS*2., NUM_COLS*2.,
0.0, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (float) WindWidth / (float) WindWidth, 5., 1000.);
gluLookAt(NUM_ROWS * 2., NUM_ROWS * 2. + 50., NUM_COLS * 2., NUM_ROWS * 2.,
NUM_ROWS * 2., NUM_COLS * 2., 0.0, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
WindWidth = width;
WindHeight = height;
WindWidth = width;
WindHeight = height;
}
/* change view angle */
/**
* Handler for special keys (the arrow keys in particular) for adjusting the
* view angle of the scene.
* @param k The pressed special key using GLUT's nomenclature.
* @param x X-position of the mouse pointer.
* @param y Y-position of the mouse pointer.
*/
static void special(int k, int x, int y) {
switch (k) {
case GLUT_KEY_UP:
view_rotx += 5.0;
break;
case GLUT_KEY_DOWN:
view_rotx -= 5.0;
break;
case GLUT_KEY_LEFT:
view_rotz += 5.0;
break;
case GLUT_KEY_RIGHT:
view_rotz -= 5.0;
break;
default:
return;
}
glutPostRedisplay();
switch (k) {
case GLUT_KEY_UP:
view_rotx += 5.0;
break;
case GLUT_KEY_DOWN:
view_rotx -= 5.0;
break;
case GLUT_KEY_LEFT:
view_rotz += 5.0;
break;
case GLUT_KEY_RIGHT:
view_rotz -= 5.0;
break;
default:
return;
}
glutPostRedisplay();
}
/*
void timf(int value) {
glutPostRedisplay();
glutTimerFunc(1, timf, 0);
}*/
/**
* Entry point for starting the display loop thread.
* @param unused Not used. Only here to satisfy signature constraints.
*/
void *display_loop_run(void * unused) {
display_loop();
return 0;
}
int main(int argc, char **argv){
WindHeight = 700;
WindWidth = 700;
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(WindHeight, WindWidth);
win = glutCreateWindow("16x16 Borg Simulator");
// callback
//glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutIdleFunc(display);
glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF);
glutKeyboardFunc(keyboard);
glutKeyboardUpFunc(keyboardup);
glutSpecialFunc(special);
glutMouseFunc(mouse);
glutMotionFunc(motion);
/**
* Main function for the simulator.
* @param argc The argument count.
* @param argv Command line arguments.
* @return Exit codem, always zero.
*/
int main(int argc, char **argv) {
WindHeight = 700;
WindWidth = 700;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(WindHeight, WindWidth);
win = glutCreateWindow("16x16 Borg Simulator");
// clearcolor & main loop
glClearColor(0,0,0,1.0);
gluPerspective(60.0, (float)WindWidth/(float)WindWidth, 5., 1000.);
gluLookAt(NUM_COLS*2., NUM_COLS*2.+50., NUM_ROWS*2.,
NUM_COLS*2., NUM_COLS*2., NUM_ROWS*2.,
0.0, 0.0, 1.0);
// callback
glutDisplayFunc(display);
glutIdleFunc(display);
glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF);
glutKeyboardFunc(keyboard);
glutKeyboardUpFunc(keyboardup);
glutSpecialFunc(special);
glutMouseFunc(mouse);
glutMotionFunc(motion);
// clearcolor & main loop
glClearColor(0, 0, 0, 1.0);
gluPerspective(60.0, (float) WindWidth / (float) WindWidth, 5., 1000.);
gluLookAt(NUM_COLS * 2., NUM_COLS * 2. + 50., NUM_ROWS * 2., NUM_COLS * 2.,
NUM_COLS * 2., NUM_ROWS * 2., 0.0, 0.0, 1.0);
// init Call List for LED
quad = gluNewQuadric();
GLUquadric* quad = gluNewQuadric();
glNewList(0, GL_COMPILE);
glColor4f(0.8, 0.0, 0.0, 1.);
gluSphere(quad, 1.0, 12, 12);
@ -224,26 +301,24 @@ int main(int argc, char **argv){
glNewList(1, GL_COMPILE);
glColor4f(0.5, 0.0, 0.0, 1.);
gluSphere(quad, 1.4, 12, 12);
glEndList();
glEndList();
glNewList(2, GL_COMPILE);
glColor4f(0.7, 0.0, 0.0, 1.);
gluSphere(quad, 1.55, 12, 12);
glEndList();
glEndList();
glNewList(3, GL_COMPILE);
glColor4f(1.00, 0.0, 0.0, 1.);
gluSphere(quad, 1.7, 12, 12);
glEndList();
gluSphere(quad, 1.7, 12, 12);
glEndList();
tbInit(GLUT_LEFT_BUTTON);
tbAnimate(GL_FALSE);
tbInit(GLUT_LEFT_BUTTON);
tbAnimate(GL_FALSE);
// start display_loop thread
#ifdef _WIN32
_beginthread((void (*)(void*))display_loop_run, 0, NULL);
#else
pthread_create(&simthread, NULL, display_loop_run, NULL);
#endif
//glutTimerFunc(40, timf, 0); // Set up timer for 40ms, about 25 fps
glutMainLoop();
return 0;
pthread_t simthread;
pthread_create(&simthread, NULL, display_loop_run, NULL);
glutMainLoop();
return 0;
}
/*@}*/

View File

@ -1,4 +1,9 @@
/*
/**
* \addtogroup unixsimulator
*/
/*@{*/
/**
* Simple trackball-like motion adapted (ripped off) from projtex.c
* (written by David Yu and David Blythe). See the SIGGRAPH '96
* Advanced OpenGL course notes.
@ -20,67 +25,68 @@
* Typical setup:
*
*
void
init(void)
{
tbInit(GLUT_MIDDLE_BUTTON);
tbAnimate(GL_TRUE);
. . .
}
void
reshape(int width, int height)
{
tbReshape(width, height);
. . .
}
void
display(void)
{
glPushMatrix();
tbMatrix();
. . . draw the scene . . .
glPopMatrix();
}
void
mouse(int button, int state, int x, int y)
{
tbMouse(button, state, x, y);
. . .
}
void
motion(int x, int y)
{
tbMotion(x, y);
. . .
}
int
main(int argc, char** argv)
{
. . .
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
. . .
}
* void
* init(void)
* {
* tbInit(GLUT_MIDDLE_BUTTON);
* tbAnimate(GL_TRUE);
* . . .
* }
*
* */
* void
* reshape(int width, int height)
* {
* tbReshape(width, height);
* . . .
* }
*
* void
* display(void)
* {
* glPushMatrix();
*
* tbMatrix();
* . . . draw the scene . . .
*
* glPopMatrix();
* }
*
* void
* mouse(int button, int state, int x, int y)
* {
* tbMouse(button, state, x, y);
* . . .
* }
*
* void
* motion(int x, int y)
* {
* tbMotion(x, y);
* . . .
* }
*
* int
* main(int argc, char** argv)
* {
* . . .
* init();
* glutReshapeFunc(reshape);
* glutDisplayFunc(display);
* glutMouseFunc(mouse);
* glutMotionFunc(motion);
* . . .
* }
*
* @file trackball.c
* @brief Helper functions for the UNIX platform Borg simulator.
* @author Martin Ongsiek, David Yu, David Blythe
*/
/* includes */
#include <math.h>
#include <assert.h>
#ifdef OSX_
# include <GLUT/glut.h>
#elif _WIN32
# include <GL/glut.h>
#else
# include <GL/glut.h>
#endif
@ -104,131 +110,186 @@ static GLboolean tb_animate = GL_TRUE;
/* functions */
static void _tbPointToVector(int x, int y, int width, int height, float v[3])
{
float d, a;
/* project x, y onto a hemi-sphere centered within width, height. */
v[0] = (2.0 * x - width) / width;
v[1] = (height - 2.0 * y) / height;
d = sqrt(v[0] * v[0] + v[1] * v[1]);
v[2] = cos((3.14159265 / 2.0) * ((d < 1.0) ? d : 1.0));
a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] *= a;
v[1] *= a;
v[2] *= a;
/**
* Project x and y onto a hemisphere centered within given width and height.
* @param x X-coordinate
* @param y Y-coordinate
* @param width Width of the hemisphere.
* @param height Width of the hemisphere.
* @param v Vector where the projection is performed on.
*/
static void _tbPointToVector(int x, int y, int width, int height, float v[3]) {
float d, a;
/* project x, y onto a hemisphere centered within width, height. */
v[0] = (2.0 * x - width) / width;
v[1] = (height - 2.0 * y) / height;
d = sqrt(v[0] * v[0] + v[1] * v[1]);
v[2] = cos((3.14159265 / 2.0) * ((d < 1.0) ? d : 1.0));
a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] *= a;
v[1] *= a;
v[2] *= a;
}
static void _tbAnimate(void)
{
glutPostRedisplay();
/**
* Redisplay current window contents.
*/
static void _tbAnimate(void) {
glutPostRedisplay();
}
void _tbStartMotion(int x, int y, int button, int time)
{
assert(tb_button != -1);
tb_tracking = GL_TRUE;
tb_lasttime = time;
_tbPointToVector(x, y, tb_width, tb_height, tb_lastposition);
/**
* Starts trackball movement depending on the mouse position.
* @param x X-position of the mouse pointer.
* @param y Y-position of the mouse pointer.
* @param button Not used.
* @param time Elapsed time.
*/
void _tbStartMotion(int x, int y, int button, int time) {
assert(tb_button != -1);
tb_tracking = GL_TRUE;
tb_lasttime = time;
_tbPointToVector(x, y, tb_width, tb_height, tb_lastposition);
}
void _tbStopMotion(int button, unsigned time)
{
assert(tb_button != -1);
tb_tracking = GL_FALSE;
/**
* Stops trackball movement.
* @param button Not used
* @param time Not used.
*/
void _tbStopMotion(int button, unsigned time) {
assert(tb_button != -1);
if (time == tb_lasttime && tb_animate) {
glutIdleFunc(_tbAnimate);
} else {
tb_angle = 0.0;
if (tb_animate)
glutIdleFunc(0);
}
tb_tracking = GL_FALSE;
if (time == tb_lasttime && tb_animate) {
glutIdleFunc(_tbAnimate);
} else {
tb_angle = 0.0;
if (tb_animate) {
glutIdleFunc(0);
}
}
}
void tbAnimate(GLboolean animate)
{
tb_animate = animate;
/**
* Starts or stops the spinning movement of the trackball.
* @param animate GL_TRUE for starting and GL_FALSE for stopping the animation.
*/
void tbAnimate(GLboolean animate) {
tb_animate = animate;
}
void tbInit(GLuint button)
{
tb_button = button;
tb_angle = 0.0;
/* put the identity in the trackball transform */
glPushMatrix();
glLoadIdentity();
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)tb_transform);
glPopMatrix();
/**
* Has to be called before any other tb call.
* @param button Mouse button state.
*/
void tbInit(GLuint button) {
tb_button = button;
tb_angle = 0.0;
/* put the identity in the trackball transform */
glPushMatrix();
glLoadIdentity();
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) tb_transform);
glPopMatrix();
}
void tbMatrix()
{
assert(tb_button != -1);
glPushMatrix();
glLoadIdentity();
glRotatef(tb_angle, -tb_axis[0], tb_axis[2], tb_axis[1]);
glMultMatrixf((GLfloat *)tb_transform);
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)tb_transform);
glPopMatrix();
/**
* Gets the tb matrix rotation.
*/
void tbMatrix() {
assert(tb_button != -1);
glMultMatrixf((GLfloat *)tb_transform);
}
glPushMatrix();
glLoadIdentity();
glRotatef(tb_angle, -tb_axis[0], tb_axis[2], tb_axis[1]);
glMultMatrixf((GLfloat *) tb_transform);
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) tb_transform);
glPopMatrix();
void tbReshape(int width, int height)
{
assert(tb_button != -1);
tb_width = width;
tb_height = height;
glMultMatrixf((GLfloat *) tb_transform);
}
void tbMouse(int button, int state, int x, int y)
{
assert(tb_button != -1);
if (state == GLUT_DOWN && button == tb_button)
_tbStartMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME));
else if (state == GLUT_UP && button == tb_button)
_tbStopMotion(button, glutGet(GLUT_ELAPSED_TIME));
/**
* Reshape callback function for determining the window size.
* @param width Width of the trackball.
* @param height Height of the trackball.
*/
void tbReshape(int width, int height) {
assert(tb_button != -1);
tb_width = width;
tb_height = height;
}
void tbMotion(int x, int y)
{
GLfloat current_position[3], dx, dy, dz;
assert(tb_button != -1);
/**
* Starts motion depending on mouse position and button state.
* @param button The button whose state has changed.
* @param state The state of that button.
* @param x X-position of the mouse pointer.
* @param y Y-position of the mouse pointer.
*/
void tbMouse(int button, int state, int x, int y) {
assert(tb_button != -1);
if (tb_tracking == GL_FALSE)
return;
_tbPointToVector(x, y, tb_width, tb_height, current_position);
/* calculate the angle to rotate by (directly proportional to the
length of the mouse movement */
dx = current_position[0] - tb_lastposition[0];
dy = current_position[1] - tb_lastposition[1];
dz = current_position[2] - tb_lastposition[2];
tb_angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz);
/* calculate the axis of rotation (cross product) */
tb_axis[0] = tb_lastposition[1] * current_position[2] -
tb_lastposition[2] * current_position[1];
tb_axis[1] = tb_lastposition[2] * current_position[0] -
tb_lastposition[0] * current_position[2];
tb_axis[2] = tb_lastposition[0] * current_position[1] -
tb_lastposition[1] * current_position[0];
/* reset for next time */
tb_lasttime = glutGet(GLUT_ELAPSED_TIME);
tb_lastposition[0] = current_position[0];
tb_lastposition[1] = current_position[1];
tb_lastposition[2] = current_position[2];
/* remember to draw new position */
glutPostRedisplay();
if (state == GLUT_DOWN && button == tb_button)
_tbStartMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME));
else if (state == GLUT_UP && button == tb_button)
_tbStopMotion(button, glutGet(GLUT_ELAPSED_TIME));
}
/**
* Starts a rotating scene motion to the given coordinates.
* @param x The x-coordinate.
* @param y The y-coordinate.
*/
void tbMotion(int x, int y) {
GLfloat current_position[3], dx, dy, dz;
assert(tb_button != -1);
if (tb_tracking == GL_FALSE)
return;
_tbPointToVector(x, y, tb_width, tb_height, current_position);
/* calculate the angle to rotate by (directly proportional to the
length of the mouse movement */
dx = current_position[0] - tb_lastposition[0];
dy = current_position[1] - tb_lastposition[1];
dz = current_position[2] - tb_lastposition[2];
tb_angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz);
/* calculate the axis of rotation (cross product) */
tb_axis[0] = tb_lastposition[1] * current_position[2]
- tb_lastposition[2] * current_position[1];
tb_axis[1] = tb_lastposition[2] * current_position[0]
- tb_lastposition[0] * current_position[2];
tb_axis[2] = tb_lastposition[0] * current_position[1]
- tb_lastposition[1] * current_position[0];
/* reset for next time */
tb_lasttime = glutGet(GLUT_ELAPSED_TIME);
tb_lastposition[0] = current_position[0];
tb_lastposition[1] = current_position[1];
tb_lastposition[2] = current_position[2];
/* remember to draw new position */
glutPostRedisplay();
}
/*@}*/

View File

@ -1,77 +1,86 @@
/*
* Simple trackball-like motion adapted (ripped off) from projtex.c
* (written by David Yu and David Blythe). See the SIGGRAPH '96
* Advanced OpenGL course notes.
*
*
* Usage:
*
* o call gltbInit() in before any other gltb call
* o call gltbReshape() from the reshape callback
* o call gltbMatrix() to get the trackball matrix rotation
* o call gltbStartMotion() to begin trackball movememt
* o call gltbStopMotion() to stop trackball movememt
* o call gltbMotion() from the motion callback
* o call gltbAnimate(GL_TRUE) if you want the trackball to continue
* spinning after the mouse button has been released
* o call gltbAnimate(GL_FALSE) if you want the trackball to stop
* spinning after the mouse button has been released
*
* Typical setup:
*
*
void
init(void)
{
gltbInit(GLUT_MIDDLE_BUTTON);
gltbAnimate(GL_TRUE);
. . .
}
/**
* \addtogroup unixsimulator
*/
/*@{*/
void
reshape(int width, int height)
{
gltbReshape(width, height);
. . .
}
void
display(void)
{
glPushMatrix();
gltbMatrix();
. . . draw the scene . . .
glPopMatrix();
}
void
mouse(int button, int state, int x, int y)
{
gltbMouse(button, state, x, y);
. . .
}
void
motion(int x, int y)
{
gltbMotion(x, y);
. . .
}
int
main(int argc, char** argv)
{
. . .
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
. . .
}
***/
/**
* Simple trackball-like motion adapted (ripped off) from projtex.c
* (written by David Yu and David Blythe). See the SIGGRAPH '96
* Advanced OpenGL course notes.
*
*
* Usage:
*
* o call tbInit() in before any other tb call
* o call tbReshape() from the reshape callback
* o call tbMatrix() to get the trackball matrix rotation
* o call tbStartMotion() to begin trackball movememt
* o call tbStopMotion() to stop trackball movememt
* o call tbMotion() from the motion callback
* o call tbAnimate(GL_TRUE) if you want the trackball to continue
* spinning after the mouse button has been released
* o call tbAnimate(GL_FALSE) if you want the trackball to stop
* spinning after the mouse button has been released
*
* Typical setup:
*
*
* void
* init(void)
* {
* tbInit(GLUT_MIDDLE_BUTTON);
* tbAnimate(GL_TRUE);
* . . .
* }
*
* void
* reshape(int width, int height)
* {
* tbReshape(width, height);
* . . .
* }
*
* void
* display(void)
* {
* glPushMatrix();
*
* tbMatrix();
* . . . draw the scene . . .
*
* glPopMatrix();
* }
*
* void
* mouse(int button, int state, int x, int y)
* {
* tbMouse(button, state, x, y);
* . . .
* }
*
* void
* motion(int x, int y)
* {
* tbMotion(x, y);
* . . .
* }
*
* int
* main(int argc, char** argv)
* {
* . . .
* init();
* glutReshapeFunc(reshape);
* glutDisplayFunc(display);
* glutMouseFunc(mouse);
* glutMotionFunc(motion);
* . . .
* }
*
* @file trackball.h
* @brief Header file for helper functions for the UNIX platform Borg simulator.
* @author Martin Ongsiek, David Yu, David Blythe
*/
/* functions */
@ -87,3 +96,4 @@
void tbAnimate(GLboolean animate);
/*@}*/

View File

@ -1,26 +0,0 @@
#ifdef _WIN32
#include <windows.h>
#endif
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <setjmp.h>
#include "joystick.h"
extern jmp_buf newmode_jmpbuf;
void wait(unsigned int ms) {
if (waitForFire) {
if (JOYISFIRE) {
longjmp(newmode_jmpbuf, 43);
}
}
#ifdef _WIN32
Sleep(ms);
#else
usleep(ms*1000);
#endif
}

492
simulator/winmain.c Normal file
View File

@ -0,0 +1,492 @@
/**
* \defgroup winsimulator Simulation of the Borg API for the Win32 platform.
*/
/*@{*/
/**
* This is a native Win32 port of the Borgware-2D API simulator. Although the
* OpenGL based simulator is in fact platform independent, there are some
* obstacles regarding Cygwin's OpenGL support.
*
* Earlier versions of Cygwin used to ship bindings to Win32's native OpenGL
* libraries. Unfortunately some of those native components (GLUT in particular)
* weren't maintained for years so it was decided to cease support for them.
*
* The reasons are explained in more detail at
* http://cygwin.com/ml/cygwin/2012-05/msg00276.html
*
* The OpenGL bindings which are now shipped with Cygwin require a running
* X-Server which I consider clumsy to use on a Windows platform (especially for
* a small application like this simulator). So I decided to write a native
* Win32 application to free Windows developers from the hassles of rolling out
* a complete X11 setup.
*
* The native simulator feels like the OpenGL based one, with the exception that
* you can't rotate the matrix (I'm using the plain GDI32 API for the graphics).
*
* @file winmain.c
* @brief Simulator for the Win32 platform.
* @author Christian Kroll
*/
#include <windows.h>
#include <setjmp.h>
#include "../config.h"
#include "../display_loop.h"
/** Number of bytes per row. */
#define LINEBYTES ((NUM_COLS + 1) / 8)
/** The width (in pixels) of the margin around a LED. */
#define LED_MARGIN 1
/** The diameter (in pixels) of a LED. */
#define LED_DIAMETER 14
/** The extend of the whole LED including its margin. */
#define LED_EXTENT (2 * LED_MARGIN + LED_DIAMETER)
/** Width of the canvas. */
#define WND_X_EXTENTS (NUM_COLS * LED_EXTENT)
/** Height of the canvas. */
#define WND_Y_EXTENTS (NUM_ROWS * LED_EXTENT)
/* string constants */
LPCSTR g_strWindowClass = "BorgSimulatorWindowClass";
LPCSTR g_strWindowTitle = "Borg Simulator";
LPCSTR g_strError = "Error";
LPCSTR g_strErrorRegisterWindow = "Error: Could not register window class.";
LPCSTR g_strErrorCreateWindow = "Error: Could not create window.";
/** Event object for the multimedia timer (wait() function). */
HANDLE g_hWaitEvent;
/** Fake port for simulating joystick input. */
volatile unsigned char fakeport;
/** Flag which indicates if wait should jump to the menu if fire is pressed. */
volatile unsigned char waitForFire;
/** The simulated frame buffer of the borg. */
volatile unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES];
/** Jump buffer which leads directly the menu. */
extern jmp_buf newmode_jmpbuf;
/* forward declarations */
LRESULT CALLBACK simWndProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam);
/**
* Registers a window class (necessary for creating a window).
* @param lpwc Pointer to WNDCLASS struct.
* @param hInstance Handle of the instance where this window class belongs to.
* @return TRUE if successful, otherwise FALSE.
*/
BOOL simRegisterWindowClass(WNDCLASSA *const lpwc,
HINSTANCE hInstance)
{
lpwc->style = 0;
lpwc->lpfnWndProc = simWndProc;
lpwc->cbClsExtra = 0;
lpwc->cbWndExtra = 0;
lpwc->hInstance = hInstance;
lpwc->hIcon = LoadIcon(NULL, IDI_WINLOGO);
lpwc->hCursor = LoadCursor(NULL, IDC_ARROW);
lpwc->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
lpwc->lpszMenuName = NULL;
lpwc->lpszClassName = g_strWindowClass;
return (RegisterClassA(lpwc) != 0);
}
/**
* Creates a new window and makes it visible.
* @param lphWnd Pointer to window handle.
* @param hInstance Handle of the instance where this window belongs to.
* @param nCmdShow Flag for showing the window minimized, maximized etc.
* @return TRUE if successful, otherwise FALSE.
*/
BOOL simCreateWindow(HWND *lphWnd,
HINSTANCE hInstance,
int nCmdShow)
{
/* create window and retrieve its handle */
*lphWnd = CreateWindow(g_strWindowClass, g_strWindowTitle,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
WND_X_EXTENTS * 2, WND_Y_EXTENTS * 2, HWND_DESKTOP,
NULL, hInstance, NULL);
/* mske it visible */
if (*lphWnd != NULL)
{
ShowWindow(*lphWnd, nCmdShow);
UpdateWindow(*lphWnd);
return TRUE;
}
return FALSE;
}
/**
* Draws the LED matrix on the given device context.
* @param hdc The device context where the LED matrix should be drawn on.
*/
void simDrawMatrix(HDC hdc)
{
COLORREF colorLed;
HBRUSH hBrushLed;
HGDIOBJ hGdiOld;
unsigned int c, p, x, y, absX;
int left, right, top, bottom;
static unsigned char const shl_map[8] =
{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
/* clear background */
FloodFill(hdc, 0, 0, RGB(0, 0, 0));
/* go through every plane */
for (p = 0; p < NUMPLANE; ++p)
{
/* create and select red brush into device context */
colorLed = RGB((255.0 / NUMPLANE) * (p + 1), 0, 0);
hBrushLed = CreateSolidBrush(colorLed);
hGdiOld = SelectObject(hdc, hBrushLed);
/* translate pixmap into LEDs */
for (y = 0; y < NUM_ROWS; ++y)
{
for (c = 0; c < LINEBYTES; ++c)
{
for (x = 0; x < 8; ++x)
{
if (pixmap[p][y][c] & shl_map[x])
{
// eventually draw a LED, mirroring its coordinates
absX = (c * 8 + x) * LED_EXTENT + LED_MARGIN;
left = WND_X_EXTENTS - absX;
right = WND_X_EXTENTS - absX - LED_DIAMETER + 1;
top = y * LED_EXTENT + LED_MARGIN;
bottom = top + LED_DIAMETER - 1;
Ellipse(hdc, left, top, right, bottom);
}
}
}
}
/* dispose that brush */
DeleteObject(SelectObject(hdc, hGdiOld));
}
}
/**
* Retrieves device context from given window, creates a compatible memory
* device context for double buffering and hands that thing over to
* simDrawMatrix().
* @param hWnd The window where the LED-Matrix should be displayed.
*/
void simDisplay(HWND hWnd)
{
RECT rect;
HDC hdc;
HDC hMemDc;
HBITMAP hBmp;
HBITMAP hOldBmp;
/* retrieve window dimensions */
if (GetClientRect(hWnd, &rect))
{
int const cx = rect.right - rect.left;
int const cy = rect.bottom - rect.top;
/* retrieve device context */
if ((hdc = GetDC(hWnd)) != NULL)
{
/* make window contents scalable */
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, WND_X_EXTENTS, WND_Y_EXTENTS, NULL);
SetViewportExtEx(hdc, cx, cy, NULL);
/* create memory device context for double buffering */
hMemDc = CreateCompatibleDC(hdc);
if (hMemDc != NULL)
{
/* contents of the memory DC should be scaled as well */
SetMapMode(hMemDc, MM_ANISOTROPIC);
SetWindowExtEx(hMemDc, WND_X_EXTENTS, WND_Y_EXTENTS, NULL);
SetViewportExtEx(hMemDc, cx, cy, NULL);
/* create a bitmap to be associated with the memory DC... */
hBmp = CreateCompatibleBitmap(hdc, cx, cy);
if (hBmp != NULL)
{
/* ...and selct that into that DC */
hOldBmp = (HBITMAP)SelectObject(hMemDc, hBmp);
/* finally *sigh* draw the LED matrix */
simDrawMatrix(hMemDc);
/* and blit that into the window DC */
BitBlt(hdc, 0, 0, cx, cy, hMemDc, 0, 0, SRCCOPY);
/* clean up */
DeleteObject(SelectObject(hMemDc, hOldBmp));
}
DeleteDC(hMemDc);
}
ReleaseDC(hWnd, hdc);
}
InvalidateRect(hWnd, &rect, FALSE);
}
}
/**
* Message handler for the main window.
* @param hWnd The window whose messages should be processed.
* @param msg The message fired from the operating system.
* @param wParam First message parameter.
* @param lParam Second message parameter.
*/
LRESULT CALLBACK simWndProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
LPMINMAXINFO lpminmax;
switch (msg)
{
/* enforce minimum window size */
case WM_GETMINMAXINFO:
lpminmax = (LPMINMAXINFO)lParam;
lpminmax->ptMinTrackSize.x = WND_X_EXTENTS * 2;
lpminmax->ptMinTrackSize.y = WND_Y_EXTENTS * 2;
break;
/* paint window contents */
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
if (hdc != NULL)
{
simDisplay(hWnd);
EndPaint(hWnd, &ps);
}
break;
/* map key presses to fake joystick movements */
case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
case 'Q':
PostQuitMessage(0);
break;
case VK_SPACE:
fakeport |= 0x01;
break;
case 'A':
fakeport |= 0x02;
break;
case 'D':
fakeport |= 0x04;
break;
case 'S':
fakeport |= 0x08;
break;
case 'W':
fakeport |= 0x10;
break;
default:
return DefWindowProcA(hWnd, msg, wParam, lParam);
break;
}
break;
/* map key releases to fake joystick movements */
case WM_KEYUP:
switch(wParam)
{
case VK_SPACE:
fakeport &= ~0x01;
break;
case 'A':
fakeport &= ~0x02;
break;
case 'D':
fakeport &= ~0x04;
break;
case 'S':
fakeport &= ~0x08;
break;
case 'W':
fakeport &= ~0x10;
break;
default:
return DefWindowProcA(hWnd, msg, wParam, lParam);
break;
}
break;
/* refresh the LED matrix every 40 ms */
case WM_TIMER:
simDisplay(hWnd);
break;
/* quit application */
case WM_DESTROY:
PostQuitMessage(0);
break;
/* Windows' default handler */
default:
return DefWindowProcA(hWnd, msg, wParam, lParam);
break;
}
return 0;
}
/**
* Entry point for starting the the display loop in a thread.
* @param lpParam Free style arguments for the thread function (not used here).
* @return Always zero.
*/
DWORD WINAPI simLoop(LPVOID lpParam)
{
display_loop();
return 0;
}
/**
* Wait function which utilizes multimedia timers and thread synchronization
* objects. Although this is much more complicated than calling the Sleep()
* function, it is also much more precise.
* @param ms The requested delay in milliseconds.
*/
void wait(int ms)
{
TIMECAPS tc;
MMRESULT mmresult;
MMRESULT mmTimerEventId;
UINT uResolution;
/* check if fire button is pressed (and if it is, jump to the menu) */
if (waitForFire) {
if (fakeport & 0x01) {
longjmp(newmode_jmpbuf, 43);
}
}
/* retrieve timer resolution capabilities of the current system */
mmresult = timeGetDevCaps(&tc, sizeof(tc));
if (mmresult == TIMERR_NOERROR)
{
/* retrieve best resolution and configure timer services accordingly */
uResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);
mmresult = timeBeginPeriod(uResolution);
if (mmresult == TIMERR_NOERROR)
{
/* actually retrieve a multimedia timer */
mmTimerEventId = timeSetEvent(ms, uResolution, g_hWaitEvent, NULL,
TIME_ONESHOT | TIME_CALLBACK_EVENT_PULSE);
if (mmTimerEventId != NULL)
{
/* now halt until that timer pulses our wait event object */
WaitForSingleObject(g_hWaitEvent, INFINITE);
/* relieve the timer from its duties */
timeKillEvent(mmTimerEventId);
}
/* relax timer service constraints */
timeEndPeriod (uResolution);
}
}
}
/**
* Main function of the windows simulator.
* @param hInstance Instance handle given by the operating system.
* @param hPrevInstance This parameter has no meaning in Win32.
* @param lpCmdLine Pointer to a null terminated command line string.
* @param nCmdShow Flags for showing the window minimized, maximized and so on.
* @return Exit code, always 0 here.
*/
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wc;
HWND hWnd;
MSG msg;
HANDLE hThread;
/* regster window class (with nice black background!) */
if (simRegisterWindowClass(&wc, hInstance))
{
/* actually create the window and make it visible */
if (simCreateWindow(&hWnd, hInstance, nCmdShow))
{
/* event handle for multimedia timer (for the wait() function) */
g_hWaitEvent = CreateEventA(NULL, FALSE, FALSE, "Local\\WaitEvent");
if (g_hWaitEvent != NULL)
{
/* start the display loop thread */
hThread = CreateThread(NULL, 0, simLoop, NULL, 0, NULL);
if (hThread != NULL)
{
/* ensure that the display loop stays responsive */
SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
/* issue a timer message every 40 ms (roughly 25 fps) */
/* NOTE: this has nothing to do with the multimedia timer */
SetTimer(hWnd, 23, 40, NULL);
/* standard Windows(R) message loop */
/* (runs as long as the window hasn't been closed) */
while (GetMessageA(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
/* stop the display loop */
TerminateThread(hThread, 0);
}
/* relieve wait event object from its duties */
CloseHandle(g_hWaitEvent);
}
return msg.wParam;
}
MessageBoxA(HWND_DESKTOP, g_strErrorCreateWindow, g_strError, MB_OK);
}
MessageBoxA(HWND_DESKTOP, g_strErrorRegisterWindow, g_strError, MB_OK);
return 0;
}
/*@}*/