Rewrote API simulator from scratch for Win32 since Cygwin ceased support for Win32's native OpenGL libraries.
This commit is contained in:
parent
3e7ee74414
commit
971901e453
12
defaults.mk
12
defaults.mk
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ = . ;
|
||||
|
@ -36,24 +38,30 @@ SECTIONS
|
|||
*(.data2)
|
||||
*(SORT(.data$*))
|
||||
*(.jcr)
|
||||
__eeprom_start__ = . ;
|
||||
__eeprom_start__ = . ;
|
||||
*(.eeprom)
|
||||
__game_descriptors_start__ = . ;
|
||||
*(.game_descriptors)
|
||||
__game_descriptors_end__ = . ;
|
||||
__data_end__ = . ;
|
||||
__game_descriptors_start__ = . ;
|
||||
*(.game_descriptors)
|
||||
__game_descriptors_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.*)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
#include "joystick.h"
|
||||
|
||||
unsigned char fakeport;
|
||||
|
||||
|
||||
// fake function since our keybord doesn't need any initialisation
|
||||
void joy_init()
|
||||
{
|
||||
}
|
|
@ -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_*/
|
403
simulator/main.c
403
simulator/main.c
|
@ -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;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*@}*/
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*@}*/
|
Loading…
Reference in New Issue