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

View File

@ -3,7 +3,10 @@ TOPDIR = ..
include $(TOPDIR)/defaults.mk 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 include $(TOPDIR)/rules.mk

View File

@ -1,6 +1,6 @@
/* Default linker script, for normal executables */ /* Default linker script, for normal executables */
OUTPUT_FORMAT(pei-i386) 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 SECTIONS
{ {
/* Make the virtual address and file offset synced if the alignment is /* Make the virtual address and file offset synced if the alignment is
@ -12,6 +12,8 @@ SECTIONS
*(.init) *(.init)
*(.text) *(.text)
*(SORT(.text$*)) *(SORT(.text$*))
*(.text.*)
*(.gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7t)
*(.glue_7) *(.glue_7)
___CTOR_LIST__ = .; __CTOR_LIST__ = . ; ___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
@ -28,7 +30,7 @@ SECTIONS
on fork. This used to be named ".data". The linker used on fork. This used to be named ".data". The linker used
to include this between __data_start__ and __data_end__, but that to include this between __data_start__ and __data_end__, but that
breaks building the cygwin32 dll. Instead, we name the section 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 BLOCK(__section_alignment__) :
{ {
__data_start__ = . ; __data_start__ = . ;
@ -48,12 +50,18 @@ SECTIONS
{ {
*(.rdata) *(.rdata)
*(SORT(.rdata$*)) *(SORT(.rdata$*))
*(.eh_frame) __rt_psrelocs_start = .;
___RUNTIME_PSEUDO_RELOC_LIST__ = .;
__RUNTIME_PSEUDO_RELOC_LIST__ = .;
*(.rdata_runtime_pseudo_reloc) *(.rdata_runtime_pseudo_reloc)
__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_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__) : .pdata BLOCK(__section_alignment__) :
{ {
@ -76,6 +84,8 @@ SECTIONS
*(.debug$T) *(.debug$T)
*(.debug$F) *(.debug$F)
*(.drectve) *(.drectve)
*(.note.GNU-stack)
*(.gnu.lto_*)
} }
.idata BLOCK(__section_alignment__) : .idata BLOCK(__section_alignment__) :
{ {
@ -86,7 +96,9 @@ SECTIONS
/* These zeroes mark the end of the import list. */ /* These zeroes mark the end of the import list. */
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0); LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
SORT(*)(.idata$4) SORT(*)(.idata$4)
__IAT_start__ = .;
SORT(*)(.idata$5) SORT(*)(.idata$5)
__IAT_end__ = .;
SORT(*)(.idata$6) SORT(*)(.idata$6)
SORT(*)(.idata$7) SORT(*)(.idata$7)
} }
@ -153,10 +165,14 @@ SECTIONS
{ {
*(.debug_pubnames) *(.debug_pubnames)
} }
.debug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_pubtypes)
}
/* DWARF 2. */ /* DWARF 2. */
.debug_info BLOCK(__section_alignment__) (NOLOAD) : .debug_info BLOCK(__section_alignment__) (NOLOAD) :
{ {
*(.debug_info) *(.gnu.linkonce.wi.*) *(.debug_info .gnu.linkonce.wi.*)
} }
.debug_abbrev BLOCK(__section_alignment__) (NOLOAD) : .debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
{ {
@ -168,7 +184,7 @@ SECTIONS
} }
.debug_frame BLOCK(__section_alignment__) (NOLOAD) : .debug_frame BLOCK(__section_alignment__) (NOLOAD) :
{ {
*(.debug_frame) *(.debug_frame*)
} }
.debug_str BLOCK(__section_alignment__) (NOLOAD) : .debug_str BLOCK(__section_alignment__) (NOLOAD) :
{ {
@ -199,9 +215,18 @@ SECTIONS
{ {
*(.debug_varnames) *(.debug_varnames)
} }
.debug_macro BLOCK(__section_alignment__) (NOLOAD) :
{
*(.debug_macro)
}
/* DWARF 3. */ /* DWARF 3. */
.debug_ranges BLOCK(__section_alignment__) (NOLOAD) : .debug_ranges BLOCK(__section_alignment__) (NOLOAD) :
{ {
*(.debug_ranges) *(.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> * \defgroup unixsimulator Simulation of the Borg API for UNIX like platforms.
#include <windows.h> */
#include <process.h> /*@{*/
#define pthread_t int
#else /**
* @file main.c
* @brief Simulator for Unix like platforms.
* @author Martin Ongsiek, Peter Fuhrmann, Christian Kroll
*/
#ifdef OSX_ #ifdef OSX_
#include <GLUT/glut.h> #include <GLUT/glut.h>
#else #else
#include <GL/glut.h> #include <GL/glut.h>
#endif #endif
#include <pthread.h> // for threads in linux #include <pthread.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#endif
#include <stdio.h> #include <stdio.h>
#include <setjmp.h> #include <setjmp.h>
#include "../config.h" #include "../config.h"
#include "../display_loop.h" #include "../display_loop.h"
#include "../pixel.h"
#include "trackball.h" #include "trackball.h"
unsigned char fakeport; /** Number of bytes per row. */
volatile unsigned char oldMode, oldOldmode, mode; #define LINEBYTES ((NUM_COLS + 1) / 8)
extern unsigned char waitForFire;
/** 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]; /** Rotation of the x-axis of the scene. */
unsigned char joystick; 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; 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) { void drawLED(int color, float pos_x, float pos_y, float pos_z) {
glPushMatrix(); glPushMatrix();
glTranslatef(pos_x, pos_y, pos_z); glTranslatef(pos_x, pos_y, pos_z);
@ -48,6 +84,10 @@ void drawLED(int color, float pos_x, float pos_y, float pos_z) {
glPopMatrix(); glPopMatrix();
} }
/**
* Draws the LED matrix.
*/
void display(void) { void display(void) {
int x, y, z, level, color; int x, y, z, level, color;
tbReshape(WindWidth, WindHeight); tbReshape(WindWidth, WindHeight);
@ -68,25 +108,28 @@ void display(void){
color = level + 1; color = level + 1;
} }
} }
drawLED(color, (float)y*4.0, drawLED(color, (float) y * 4.0, (float) x * 4.0,
(float)x*4.0,
(float) (NUM_ROWS - 1 - z) * 4.0); (float) (NUM_ROWS - 1 - z) * 4.0);
} }
} }
} }
glPopMatrix(); glPopMatrix();
glutSwapBuffers(); glutSwapBuffers();
#ifdef _WIN32
Sleep(10);
#else
usleep(20000); usleep(20000);
#endif
joystick = 255;
} }
/**
* 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) { void keyboard(unsigned char key, int x, int y) {
switch (key) { switch (key) {
case 'q': printf("Quit\n"); case 'q':
printf("Quit\n");
glutDestroyWindow(win); glutDestroyWindow(win);
exit(0); exit(0);
break; break;
@ -108,6 +151,13 @@ void keyboard(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) { void keyboardup(unsigned char key, int x, int y) {
switch (key) { switch (key) {
case ' ': case ' ':
@ -128,18 +178,34 @@ void keyboardup(unsigned char key, int x, int y){
} }
} }
void mouse(int button, int state, int x, int 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); tbMouse(button, state, x, y);
} }
void motion(int x, int 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); 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);
@ -148,9 +214,8 @@ void reshape(int width, int height)
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
gluPerspective(60.0, (float) WindWidth / (float) WindWidth, 5., 1000.); gluPerspective(60.0, (float) WindWidth / (float) WindWidth, 5., 1000.);
gluLookAt(NUM_ROWS*2., NUM_ROWS*2.+50., NUM_COLS*2., gluLookAt(NUM_ROWS * 2., NUM_ROWS * 2. + 50., NUM_COLS * 2., NUM_ROWS * 2.,
NUM_ROWS*2., NUM_ROWS*2., NUM_COLS*2., NUM_ROWS * 2., NUM_COLS * 2., 0.0, 0.0, 1.0);
0.0, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
@ -158,7 +223,14 @@ void reshape(int width, int height)
WindHeight = height; 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) { static void special(int k, int x, int y) {
switch (k) { switch (k) {
case GLUT_KEY_UP: case GLUT_KEY_UP:
@ -178,17 +250,24 @@ static void special(int k, int x, int y) {
} }
glutPostRedisplay(); 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) { void *display_loop_run(void * unused) {
display_loop(); display_loop();
return 0; return 0;
} }
/**
* 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) { int main(int argc, char **argv) {
WindHeight = 700; WindHeight = 700;
WindWidth = 700; WindWidth = 700;
@ -198,7 +277,6 @@ int main(int argc, char **argv){
win = glutCreateWindow("16x16 Borg Simulator"); win = glutCreateWindow("16x16 Borg Simulator");
// callback // callback
//glutReshapeFunc(reshape);
glutDisplayFunc(display); glutDisplayFunc(display);
glutIdleFunc(display); glutIdleFunc(display);
glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF); glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF);
@ -211,12 +289,11 @@ int main(int argc, char **argv){
// clearcolor & main loop // clearcolor & main loop
glClearColor(0, 0, 0, 1.0); glClearColor(0, 0, 0, 1.0);
gluPerspective(60.0, (float) WindWidth / (float) WindWidth, 5., 1000.); gluPerspective(60.0, (float) WindWidth / (float) WindWidth, 5., 1000.);
gluLookAt(NUM_COLS*2., NUM_COLS*2.+50., NUM_ROWS*2., gluLookAt(NUM_COLS * 2., NUM_COLS * 2. + 50., NUM_ROWS * 2., NUM_COLS * 2.,
NUM_COLS*2., NUM_COLS*2., NUM_ROWS*2., NUM_COLS * 2., NUM_ROWS * 2., 0.0, 0.0, 1.0);
0.0, 0.0, 1.0);
// init Call List for LED // init Call List for LED
quad = gluNewQuadric(); GLUquadric* quad = gluNewQuadric();
glNewList(0, GL_COMPILE); glNewList(0, GL_COMPILE);
glColor4f(0.8, 0.0, 0.0, 1.); glColor4f(0.8, 0.0, 0.0, 1.);
gluSphere(quad, 1.0, 12, 12); gluSphere(quad, 1.0, 12, 12);
@ -237,13 +314,11 @@ int main(int argc, char **argv){
tbInit(GLUT_LEFT_BUTTON); tbInit(GLUT_LEFT_BUTTON);
tbAnimate(GL_FALSE); tbAnimate(GL_FALSE);
// start display_loop thread pthread_t simthread;
#ifdef _WIN32
_beginthread((void (*)(void*))display_loop_run, 0, NULL);
#else
pthread_create(&simthread, NULL, display_loop_run, NULL); pthread_create(&simthread, NULL, display_loop_run, NULL);
#endif
//glutTimerFunc(40, timf, 0); // Set up timer for 40ms, about 25 fps
glutMainLoop(); glutMainLoop();
return 0; return 0;
} }
/*@}*/

View File

@ -1,4 +1,9 @@
/* /**
* \addtogroup unixsimulator
*/
/*@{*/
/**
* Simple trackball-like motion adapted (ripped off) from projtex.c * Simple trackball-like motion adapted (ripped off) from projtex.c
* (written by David Yu and David Blythe). See the SIGGRAPH '96 * (written by David Yu and David Blythe). See the SIGGRAPH '96
* Advanced OpenGL course notes. * Advanced OpenGL course notes.
@ -20,67 +25,68 @@
* Typical setup: * Typical setup:
* *
* *
void * void
init(void) * init(void)
{ * {
tbInit(GLUT_MIDDLE_BUTTON); * tbInit(GLUT_MIDDLE_BUTTON);
tbAnimate(GL_TRUE); * 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
* 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 */ /* includes */
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.h>
#ifdef OSX_ #ifdef OSX_
# include <GLUT/glut.h> # include <GLUT/glut.h>
#elif _WIN32
# include <GL/glut.h>
#else #else
# include <GL/glut.h> # include <GL/glut.h>
#endif #endif
@ -104,11 +110,19 @@ static GLboolean tb_animate = GL_TRUE;
/* functions */ /* functions */
static void _tbPointToVector(int x, int y, int width, int height, float v[3])
{ /**
* 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; float d, a;
/* project x, y onto a hemi-sphere centered within width, height. */ /* project x, y onto a hemisphere centered within width, height. */
v[0] = (2.0 * x - width) / width; v[0] = (2.0 * x - width) / width;
v[1] = (height - 2.0 * y) / height; v[1] = (height - 2.0 * y) / height;
d = sqrt(v[0] * v[0] + v[1] * v[1]); d = sqrt(v[0] * v[0] + v[1] * v[1]);
@ -119,13 +133,23 @@ static void _tbPointToVector(int x, int y, int width, int height, float v[3])
v[2] *= a; v[2] *= a;
} }
static void _tbAnimate(void)
{ /**
* Redisplay current window contents.
*/
static void _tbAnimate(void) {
glutPostRedisplay(); glutPostRedisplay();
} }
void _tbStartMotion(int x, int y, int button, int time)
{ /**
* 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); assert(tb_button != -1);
tb_tracking = GL_TRUE; tb_tracking = GL_TRUE;
@ -133,8 +157,13 @@ void _tbStartMotion(int x, int y, int button, int time)
_tbPointToVector(x, y, tb_width, tb_height, tb_lastposition); _tbPointToVector(x, y, tb_width, tb_height, tb_lastposition);
} }
void _tbStopMotion(int button, unsigned time)
{ /**
* Stops trackball movement.
* @param button Not used
* @param time Not used.
*/
void _tbStopMotion(int button, unsigned time) {
assert(tb_button != -1); assert(tb_button != -1);
tb_tracking = GL_FALSE; tb_tracking = GL_FALSE;
@ -143,18 +172,28 @@ void _tbStopMotion(int button, unsigned time)
glutIdleFunc(_tbAnimate); glutIdleFunc(_tbAnimate);
} else { } else {
tb_angle = 0.0; tb_angle = 0.0;
if (tb_animate) if (tb_animate) {
glutIdleFunc(0); glutIdleFunc(0);
} }
} }
}
void tbAnimate(GLboolean 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; tb_animate = animate;
} }
void tbInit(GLuint button)
{ /**
* Has to be called before any other tb call.
* @param button Mouse button state.
*/
void tbInit(GLuint button) {
tb_button = button; tb_button = button;
tb_angle = 0.0; tb_angle = 0.0;
@ -165,8 +204,11 @@ void tbInit(GLuint button)
glPopMatrix(); glPopMatrix();
} }
void tbMatrix()
{ /**
* Gets the tb matrix rotation.
*/
void tbMatrix() {
assert(tb_button != -1); assert(tb_button != -1);
glPushMatrix(); glPushMatrix();
@ -179,16 +221,28 @@ void tbMatrix()
glMultMatrixf((GLfloat *) tb_transform); glMultMatrixf((GLfloat *) tb_transform);
} }
void tbReshape(int width, int height)
{ /**
* 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); assert(tb_button != -1);
tb_width = width; tb_width = width;
tb_height = height; tb_height = height;
} }
void tbMouse(int button, int state, int x, int y)
{ /**
* 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); assert(tb_button != -1);
if (state == GLUT_DOWN && button == tb_button) if (state == GLUT_DOWN && button == tb_button)
@ -197,8 +251,13 @@ void tbMouse(int button, int state, int x, int y)
_tbStopMotion(button, glutGet(GLUT_ELAPSED_TIME)); _tbStopMotion(button, glutGet(GLUT_ELAPSED_TIME));
} }
void tbMotion(int x, int y)
{ /**
* 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; GLfloat current_position[3], dx, dy, dz;
assert(tb_button != -1); assert(tb_button != -1);
@ -216,12 +275,12 @@ void tbMotion(int x, int y)
tb_angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz); tb_angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz);
/* calculate the axis of rotation (cross product) */ /* calculate the axis of rotation (cross product) */
tb_axis[0] = tb_lastposition[1] * current_position[2] - tb_axis[0] = tb_lastposition[1] * current_position[2]
tb_lastposition[2] * current_position[1]; - tb_lastposition[2] * current_position[1];
tb_axis[1] = tb_lastposition[2] * current_position[0] - tb_axis[1] = tb_lastposition[2] * current_position[0]
tb_lastposition[0] * current_position[2]; - tb_lastposition[0] * current_position[2];
tb_axis[2] = tb_lastposition[0] * current_position[1] - tb_axis[2] = tb_lastposition[0] * current_position[1]
tb_lastposition[1] * current_position[0]; - tb_lastposition[1] * current_position[0];
/* reset for next time */ /* reset for next time */
tb_lasttime = glutGet(GLUT_ELAPSED_TIME); tb_lasttime = glutGet(GLUT_ELAPSED_TIME);
@ -232,3 +291,5 @@ void tbMotion(int x, int y)
/* remember to draw new position */ /* remember to draw new position */
glutPostRedisplay(); glutPostRedisplay();
} }
/*@}*/

View File

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