Compare commits
2 Commits
master
...
wow-commit
Author | SHA1 | Date |
---|---|---|
Peter Nelson | 6dfc0cc5dd | |
Peter Nelson | 86dfa2637d |
4
Makefile
4
Makefile
|
@ -14,8 +14,8 @@ SRCS += worker.c
|
||||||
|
|
||||||
OBJS := $(SRCS:.c=.o)
|
OBJS := $(SRCS:.c=.o)
|
||||||
|
|
||||||
CFLAGS += `pkg-config libglfw ftgl openal --cflags` -g
|
CFLAGS += `pkg-config freetype2 glfw3 ftgl openal opengl --cflags` -g
|
||||||
LDFLAGS += `pkg-config libglfw ftgl openal --libs` -g
|
LDFLAGS += -lm -lpthread -lSOIL `pkg-config freetype2 glfw3 ftgl openal opengl --libs`
|
||||||
|
|
||||||
lfsdash: $(OBJS)
|
lfsdash: $(OBJS)
|
||||||
$(CC) $(LDFLAGS) $(OBJS) -o $@
|
$(CC) $(LDFLAGS) $(OBJS) -o $@
|
||||||
|
|
244
audio.c
244
audio.c
|
@ -1,6 +1,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
//#include <GL/glut.h>
|
// #include <GL/glut.h>
|
||||||
#include <AL/al.h>
|
#include <AL/al.h>
|
||||||
#include <AL/alc.h>
|
#include <AL/alc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -14,187 +14,189 @@
|
||||||
ALCdevice *dev;
|
ALCdevice *dev;
|
||||||
ALCcontext *ctx;
|
ALCcontext *ctx;
|
||||||
|
|
||||||
//There is only one listener, and these arrays define the initial set up of the listener for its position, direction, and velocity. The listener is not moving at the start, but can move around any other sound source.
|
// There is only one listener, and these arrays define the initial set up of the listener for its position, direction, and velocity. The listener is not moving at the start, but can move around any other sound source.
|
||||||
ALfloat listenerPos[]={0.0,0.0,4.0};
|
ALfloat listenerPos[] = {0.0, 0.0, 4.0};
|
||||||
ALfloat listenerVel[]={0.0,0.0,0.0};
|
ALfloat listenerVel[] = {0.0, 0.0, 0.0};
|
||||||
ALfloat listenerOri[]={0.0,0.0,1.0, 0.0,1.0,0.0};
|
ALfloat listenerOri[] = {0.0, 0.0, 1.0, 0.0, 1.0, 0.0};
|
||||||
|
|
||||||
//Each sound source has similar properties that the listener has. The source0Pos and source0Vel arrays show the position and velocity of the sound source.
|
// Each sound source has similar properties that the listener has. The source0Pos and source0Vel arrays show the position and velocity of the sound source.
|
||||||
ALfloat source0Pos[]={ -2.0, 0.0, 0.0};
|
ALfloat source0Pos[] = {-2.0, 0.0, 0.0};
|
||||||
ALfloat source0Vel[]={ 0.0, 0.0, 0.0};
|
ALfloat source0Vel[] = {0.0, 0.0, 0.0};
|
||||||
|
|
||||||
//Sounds need to be stored in an array, similar to textures. Several buffers are needed to contain the sounds and other necessary information. The size, freq, format, and data variables are used when loading the sound files.
|
// Sounds need to be stored in an array, similar to textures. Several buffers are needed to contain the sounds and other necessary information. The size, freq, format, and data variables are used when loading the sound files.
|
||||||
ALuint buffer[NUM_BUFFERS];
|
ALuint buffer[NUM_BUFFERS];
|
||||||
ALuint source[NUM_SOURCES];
|
ALuint source[NUM_SOURCES];
|
||||||
ALuint environment[NUM_ENVIRONMENTS];
|
ALuint environment[NUM_ENVIRONMENTS];
|
||||||
|
|
||||||
int file_read_int32_le(char *buffer, FILE *file)
|
int file_read_int32_le(char *buffer, FILE *file)
|
||||||
{
|
{
|
||||||
int r = fread(buffer, sizeof(char), 4, file);
|
int r = fread(buffer, sizeof(char), 4, file);
|
||||||
uint32_t ret = (uint8_t)buffer[0];
|
uint32_t ret = (uint8_t)buffer[0];
|
||||||
ret |= (uint8_t)buffer[1] << 8;
|
ret |= (uint8_t)buffer[1] << 8;
|
||||||
ret |= (uint8_t)buffer[2] << 16;
|
ret |= (uint8_t)buffer[2] << 16;
|
||||||
ret |= (uint8_t)buffer[3] << 24;
|
ret |= (uint8_t)buffer[3] << 24;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int file_read_int16_le(char *buffer, FILE *file)
|
int file_read_int16_le(char *buffer, FILE *file)
|
||||||
{
|
{
|
||||||
int r = fread(buffer, sizeof(char), 2, file);
|
int r = fread(buffer, sizeof(char), 2, file);
|
||||||
uint16_t ret = (uint8_t)buffer[0];
|
uint16_t ret = (uint8_t)buffer[0];
|
||||||
ret |= (uint8_t)buffer[1] << 8;
|
ret |= (uint8_t)buffer[1] << 8;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_ignore_bytes(FILE *file, int bytes)
|
void file_ignore_bytes(FILE *file, int bytes)
|
||||||
{
|
{
|
||||||
fseek(file, bytes, SEEK_CUR);
|
fseek(file, bytes, SEEK_CUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *file_allocate_and_read_bytes(FILE *file, size_t bytes)
|
void *file_allocate_and_read_bytes(FILE *file, size_t bytes)
|
||||||
{
|
{
|
||||||
void *buffer = malloc(bytes);
|
void *buffer = malloc(bytes);
|
||||||
fread(buffer, 1, bytes, file);
|
fread(buffer, 1, bytes, file);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ALenum GetFormatFromInfo(short channels, short bitsPerSample) {
|
static inline ALenum GetFormatFromInfo(short channels, short bitsPerSample)
|
||||||
if (channels == 1)
|
{
|
||||||
return AL_FORMAT_MONO16;
|
if (channels == 1)
|
||||||
return AL_FORMAT_STEREO16;
|
return AL_FORMAT_MONO16;
|
||||||
|
return AL_FORMAT_STEREO16;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_load(const char *filename, ALuint buffer)
|
void audio_load(const char *filename, ALuint buffer)
|
||||||
{
|
{
|
||||||
FILE* file = fopen(filename, "rb");
|
FILE *file = fopen(filename, "rb");
|
||||||
char xbuffer[5];
|
char xbuffer[5];
|
||||||
memset(xbuffer, 0, sizeof xbuffer);
|
memset(xbuffer, 0, sizeof xbuffer);
|
||||||
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "RIFF") != 0)
|
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "RIFF") != 0)
|
||||||
printf("Not a WAV file: %s\n", xbuffer);
|
printf("Not a WAV file: %s\n", xbuffer);
|
||||||
|
|
||||||
file_read_int32_le(xbuffer, file);
|
file_read_int32_le(xbuffer, file);
|
||||||
|
|
||||||
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "WAVE") != 0)
|
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "WAVE") != 0)
|
||||||
printf("Not a WAV file: %s\n", xbuffer);
|
printf("Not a WAV file: %s\n", xbuffer);
|
||||||
|
|
||||||
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "fmt ") != 0)
|
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "fmt ") != 0)
|
||||||
printf("Invalid WAV file: %s\n", xbuffer);
|
printf("Invalid WAV file: %s\n", xbuffer);
|
||||||
|
|
||||||
int size = file_read_int32_le(xbuffer, file);
|
int size = file_read_int32_le(xbuffer, file);
|
||||||
short audioFormat = file_read_int16_le(xbuffer, file);
|
short audioFormat = file_read_int16_le(xbuffer, file);
|
||||||
short channels = file_read_int16_le(xbuffer, file);
|
short channels = file_read_int16_le(xbuffer, file);
|
||||||
int sampleRate = file_read_int32_le(xbuffer, file);
|
int sampleRate = file_read_int32_le(xbuffer, file);
|
||||||
int byteRate = file_read_int32_le(xbuffer, file);
|
int byteRate = file_read_int32_le(xbuffer, file);
|
||||||
file_read_int16_le(xbuffer, file);
|
file_read_int16_le(xbuffer, file);
|
||||||
short bitsPerSample = file_read_int16_le(xbuffer, file);
|
short bitsPerSample = file_read_int16_le(xbuffer, file);
|
||||||
|
|
||||||
size -= 16;
|
size -= 16;
|
||||||
|
|
||||||
file_ignore_bytes(file, size);
|
file_ignore_bytes(file, size);
|
||||||
|
|
||||||
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "data") != 0)
|
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "data") != 0)
|
||||||
printf("Invalid WAV file: %s\n", xbuffer);
|
printf("Invalid WAV file: %s\n", xbuffer);
|
||||||
|
|
||||||
int dataChunkSize = file_read_int32_le(xbuffer, file);
|
int dataChunkSize = file_read_int32_le(xbuffer, file);
|
||||||
unsigned char* bufferData = file_allocate_and_read_bytes(file, (size_t) dataChunkSize);
|
unsigned char *bufferData = file_allocate_and_read_bytes(file, (size_t)dataChunkSize);
|
||||||
|
|
||||||
float duration = (float)(dataChunkSize) / byteRate;
|
float duration = (float)(dataChunkSize) / byteRate;
|
||||||
alBufferData(buffer, GetFormatFromInfo(channels, bitsPerSample), bufferData, dataChunkSize, sampleRate);
|
alBufferData(buffer, GetFormatFromInfo(channels, bitsPerSample), bufferData, dataChunkSize, sampleRate);
|
||||||
free(bufferData);
|
free(bufferData);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_init(void)
|
void audio_init(void)
|
||||||
{
|
{
|
||||||
dev = alcOpenDevice(NULL);
|
dev = alcOpenDevice(NULL);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Oops\n");
|
fprintf(stderr, "Oops\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = alcCreateContext(dev, NULL);
|
ctx = alcCreateContext(dev, NULL);
|
||||||
alcMakeContextCurrent(ctx);
|
alcMakeContextCurrent(ctx);
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Oops2\n");
|
fprintf(stderr, "Oops2\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
alListenerfv(AL_POSITION,listenerPos);
|
alListenerfv(AL_POSITION, listenerPos);
|
||||||
alListenerfv(AL_VELOCITY,listenerVel);
|
alListenerfv(AL_VELOCITY, listenerVel);
|
||||||
alListenerfv(AL_ORIENTATION,listenerOri);
|
alListenerfv(AL_ORIENTATION, listenerOri);
|
||||||
|
|
||||||
alGetError(); // clear any error messages
|
alGetError(); // clear any error messages
|
||||||
|
|
||||||
// Generate buffers, or else no sound will happen!
|
// Generate buffers, or else no sound will happen!
|
||||||
alGenBuffers(NUM_BUFFERS, buffer);
|
alGenBuffers(NUM_BUFFERS, buffer);
|
||||||
|
|
||||||
if (alGetError() != AL_NO_ERROR) {
|
if (alGetError() != AL_NO_ERROR)
|
||||||
printf("- Error creating buffers !!\n");
|
{
|
||||||
exit(1);
|
printf("- Error creating buffers !!\n");
|
||||||
}
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
audio_load("off.wav", buffer[FX_OFF]);
|
audio_load("off.wav", buffer[FX_OFF]);
|
||||||
audio_load("on.wav", buffer[FX_ON]);
|
audio_load("on.wav", buffer[FX_ON]);
|
||||||
audio_load("bing.wav", buffer[FX_BING]);
|
audio_load("bing.wav", buffer[FX_BING]);
|
||||||
audio_load("bip.wav", buffer[FX_BIP]);
|
audio_load("bip.wav", buffer[FX_BIP]);
|
||||||
audio_load("bop.wav", buffer[FX_BOP]);
|
audio_load("bop.wav", buffer[FX_BOP]);
|
||||||
|
|
||||||
alGetError(); /* clear error */
|
alGetError(); /* clear error */
|
||||||
alGenSources(NUM_SOURCES, source);
|
alGenSources(NUM_SOURCES, source);
|
||||||
|
|
||||||
if (alGetError() != AL_NO_ERROR)
|
if (alGetError() != AL_NO_ERROR)
|
||||||
{
|
{
|
||||||
printf("- Error creating sources !!\n");
|
printf("- Error creating sources !!\n");
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ii;
|
int ii;
|
||||||
for (ii = 0; ii < NUM_SOURCES; ii++)
|
for (ii = 0; ii < NUM_SOURCES; ii++)
|
||||||
{
|
{
|
||||||
alSourcef(source[ii], AL_PITCH, 1.0f);
|
alSourcef(source[ii], AL_PITCH, 1.0f);
|
||||||
alSourcef(source[ii], AL_GAIN, 1.0f);
|
alSourcef(source[ii], AL_GAIN, 1.0f);
|
||||||
alSourcefv(source[ii], AL_POSITION, source0Pos);
|
alSourcefv(source[ii], AL_POSITION, source0Pos);
|
||||||
alSourcefv(source[ii], AL_VELOCITY, source0Vel);
|
alSourcefv(source[ii], AL_VELOCITY, source0Vel);
|
||||||
//alSourcei(source[0], AL_BUFFER, buffer[0]);
|
// alSourcei(source[0], AL_BUFFER, buffer[0]);
|
||||||
alSourcei(source[ii], AL_LOOPING, AL_FALSE);
|
alSourcei(source[ii], AL_LOOPING, AL_FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_deinit(void)
|
void audio_deinit(void)
|
||||||
{
|
{
|
||||||
int ii;
|
int ii;
|
||||||
for (ii = 0; ii < NUM_SOURCES; ii++)
|
for (ii = 0; ii < NUM_SOURCES; ii++)
|
||||||
{
|
{
|
||||||
alSourceStop(source[ii]);
|
alSourceStop(source[ii]);
|
||||||
}
|
}
|
||||||
|
|
||||||
alDeleteSources(NUM_SOURCES, source);
|
alDeleteSources(NUM_SOURCES, source);
|
||||||
alDeleteBuffers(NUM_BUFFERS, buffer);
|
alDeleteBuffers(NUM_BUFFERS, buffer);
|
||||||
|
|
||||||
alcMakeContextCurrent(NULL);
|
alcMakeContextCurrent(NULL);
|
||||||
alcDestroyContext(ctx);
|
alcDestroyContext(ctx);
|
||||||
alcCloseDevice(dev);
|
alcCloseDevice(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_volume(float f)
|
void audio_volume(float f)
|
||||||
{
|
{
|
||||||
int ii;
|
int ii;
|
||||||
for (ii = 0; ii < NUM_SOURCES; ii++)
|
for (ii = 0; ii < NUM_SOURCES; ii++)
|
||||||
{
|
{
|
||||||
alSourcef(source[ii], AL_GAIN, f);
|
alSourcef(source[ii], AL_GAIN, f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float frand(float mult)
|
float frand(float mult)
|
||||||
{
|
{
|
||||||
return ((float)rand() / (float)RAND_MAX) * mult;
|
return ((float)rand() / (float)RAND_MAX) * mult;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_play(int s, int b)
|
void audio_play(int s, int b)
|
||||||
{
|
{
|
||||||
alSourceStop(source[s]);
|
alSourceStop(source[s]);
|
||||||
alSourcei(source[s], AL_BUFFER, buffer[b]);
|
alSourcei(source[s], AL_BUFFER, buffer[b]);
|
||||||
alSourcePlay(source[s]);
|
alSourcePlay(source[s]);
|
||||||
}
|
}
|
||||||
|
|
13
audio.h
13
audio.h
|
@ -1,12 +1,13 @@
|
||||||
#ifndef AUDIO_H
|
#ifndef AUDIO_H
|
||||||
#define AUDIO_H
|
#define AUDIO_H
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
FX_ON,
|
{
|
||||||
FX_OFF,
|
FX_ON,
|
||||||
FX_BING,
|
FX_OFF,
|
||||||
FX_BIP,
|
FX_BING,
|
||||||
FX_BOP,
|
FX_BIP,
|
||||||
|
FX_BOP,
|
||||||
};
|
};
|
||||||
|
|
||||||
void audio_init(void);
|
void audio_init(void);
|
||||||
|
|
161
cars.c
161
cars.c
|
@ -10,110 +10,115 @@ struct car s_cars[MAX_CARS];
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
char* strsep(char** stringp, const char* delim)
|
char *strsep(char **stringp, const char *delim)
|
||||||
{
|
{
|
||||||
char* start = *stringp;
|
char *start = *stringp;
|
||||||
char* p;
|
char *p;
|
||||||
|
|
||||||
p = (start != NULL) ? strpbrk(start, delim) : NULL;
|
p = (start != NULL) ? strpbrk(start, delim) : NULL;
|
||||||
|
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
{
|
{
|
||||||
*stringp = NULL;
|
*stringp = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
*stringp = p + 1;
|
*stringp = p + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void init_cars(void)
|
void init_cars(void)
|
||||||
{
|
{
|
||||||
memset(s_cars, 0, sizeof s_cars);
|
memset(s_cars, 0, sizeof s_cars);
|
||||||
|
|
||||||
FILE *f = fopen("cars.txt", "r");
|
FILE *f = fopen("cars.txt", "r");
|
||||||
if (!f) return;
|
if (!f)
|
||||||
|
return;
|
||||||
|
|
||||||
struct car *car = s_cars;
|
struct car *car = s_cars;
|
||||||
|
|
||||||
while (!feof(f))
|
while (!feof(f))
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
if (fgets(buf, sizeof buf, f) <= 0) break;
|
if (fgets(buf, sizeof buf, f) <= 0)
|
||||||
if (*buf == '#') continue;
|
break;
|
||||||
|
if (*buf == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
char *bufp = buf, *p;
|
char *bufp = buf, *p;
|
||||||
p = strsep(&bufp, ",");
|
p = strsep(&bufp, ",");
|
||||||
strncpy(car->tag, p, sizeof car->tag);
|
strncpy(car->tag, p, sizeof car->tag);
|
||||||
p = strsep(&bufp, ",");
|
p = strsep(&bufp, ",");
|
||||||
strncpy(car->base, p, sizeof car->base);
|
strncpy(car->base, p, sizeof car->base);
|
||||||
p = strsep(&bufp, ",");
|
p = strsep(&bufp, ",");
|
||||||
strncpy(car->cls, p, sizeof car->cls);
|
strncpy(car->cls, p, sizeof car->cls);
|
||||||
p = strsep(&bufp, ",");
|
p = strsep(&bufp, ",");
|
||||||
car->intake = strtol(p, NULL, 10);
|
car->intake = strtol(p, NULL, 10);
|
||||||
p = strsep(&bufp, ",");
|
p = strsep(&bufp, ",");
|
||||||
car->weight = strtol(p, NULL, 10);
|
car->weight = strtol(p, NULL, 10);
|
||||||
p = strsep(&bufp, ",");
|
p = strsep(&bufp, ",");
|
||||||
strncpy(car->name, p, sizeof car->name);
|
strncpy(car->name, p, sizeof car->name);
|
||||||
p = strsep(&bufp, ",");
|
p = strsep(&bufp, ",");
|
||||||
car->maxrpm = strtof(p, NULL);
|
car->maxrpm = strtof(p, NULL);
|
||||||
p = strsep(&bufp, ",");
|
p = strsep(&bufp, ",");
|
||||||
car->maxfuel = strtof(p, NULL);
|
car->maxfuel = strtof(p, NULL);
|
||||||
p = strsep(&bufp, ",");
|
p = strsep(&bufp, ",");
|
||||||
car->maxboost = strtof(p, NULL);
|
car->maxboost = strtof(p, NULL);
|
||||||
p = strsep(&bufp, ",");
|
p = strsep(&bufp, ",");
|
||||||
car->maxspeed = strtof(p, NULL);
|
car->maxspeed = strtof(p, NULL);
|
||||||
|
|
||||||
car++;
|
car++;
|
||||||
|
|
||||||
if (car - s_cars == MAX_CARS) break;
|
if (car - s_cars == MAX_CARS)
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_car(const char tag[4], struct car *car)
|
int get_car(const char tag[4], struct car *car)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_CARS; i++)
|
for (i = 0; i < MAX_CARS; i++)
|
||||||
{
|
{
|
||||||
if (!strcmp(s_cars[i].tag, tag))
|
if (!strcmp(s_cars[i].tag, tag))
|
||||||
{
|
{
|
||||||
if (car != NULL) memcpy(car, &s_cars[i], sizeof *car);
|
if (car != NULL)
|
||||||
return i;
|
memcpy(car, &s_cars[i], sizeof *car);
|
||||||
}
|
return i;
|
||||||
}
|
}
|
||||||
return -1;
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *find_car(const char tag[4], int intake, int weight)
|
const char *find_car(const char tag[4], int intake, int weight)
|
||||||
{
|
{
|
||||||
const struct car *best = NULL;
|
const struct car *best = NULL;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_CARS; i++)
|
for (i = 0; i < MAX_CARS; i++)
|
||||||
{
|
{
|
||||||
const struct car *car = s_cars + i;
|
const struct car *car = s_cars + i;
|
||||||
if (!strcmp(car->base, tag))
|
if (!strcmp(car->base, tag))
|
||||||
{
|
{
|
||||||
if (car->intake <= intake && car->weight <= weight)
|
if (car->intake <= intake && car->weight <= weight)
|
||||||
{
|
{
|
||||||
if (best == NULL || (car->intake >= best->intake && car->weight >= best->weight))
|
if (best == NULL || (car->intake >= best->intake && car->weight >= best->weight))
|
||||||
{
|
{
|
||||||
best = s_cars + i;
|
best = s_cars + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return best->tag;
|
return best->tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_car(int carnum, float dist, float time, float cons)
|
void update_car(int carnum, float dist, float time, float cons)
|
||||||
{
|
{
|
||||||
s_cars[carnum].dist += dist;
|
s_cars[carnum].dist += dist;
|
||||||
s_cars[carnum].time += time;
|
s_cars[carnum].time += time;
|
||||||
s_cars[carnum].cons += cons;
|
s_cars[carnum].cons += cons;
|
||||||
}
|
}
|
||||||
|
|
26
cars.h
26
cars.h
|
@ -5,20 +5,20 @@
|
||||||
|
|
||||||
struct car
|
struct car
|
||||||
{
|
{
|
||||||
char tag[4];
|
char tag[4];
|
||||||
char base[4];
|
char base[4];
|
||||||
char cls[20];
|
char cls[20];
|
||||||
char name[20];
|
char name[20];
|
||||||
float maxrpm;
|
float maxrpm;
|
||||||
float maxfuel;
|
float maxfuel;
|
||||||
float maxboost;
|
float maxboost;
|
||||||
float maxspeed;
|
float maxspeed;
|
||||||
int intake;
|
int intake;
|
||||||
int weight;
|
int weight;
|
||||||
|
|
||||||
float dist;
|
float dist;
|
||||||
float time;
|
float time;
|
||||||
float cons;
|
float cons;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct car s_cars[MAX_CARS];
|
extern struct car s_cars[MAX_CARS];
|
||||||
|
|
203
config.c
203
config.c
|
@ -7,164 +7,173 @@
|
||||||
|
|
||||||
struct configitem
|
struct configitem
|
||||||
{
|
{
|
||||||
char setting[MAXCONFIGLEN];
|
char setting[MAXCONFIGLEN];
|
||||||
char value[MAXCONFIGLEN];
|
char value[MAXCONFIGLEN];
|
||||||
struct configitem *next;
|
struct configitem *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
const char *filename;
|
const char *filename;
|
||||||
struct configitem *head;
|
struct configitem *head;
|
||||||
} s_config;
|
} s_config;
|
||||||
|
|
||||||
static void config_free(void)
|
static void config_free(void)
|
||||||
{
|
{
|
||||||
struct configitem *prev;
|
struct configitem *prev;
|
||||||
struct configitem *curr = s_config.head;
|
struct configitem *curr = s_config.head;
|
||||||
|
|
||||||
s_config.head = NULL;
|
s_config.head = NULL;
|
||||||
|
|
||||||
while (curr != NULL)
|
while (curr != NULL)
|
||||||
{
|
{
|
||||||
prev = curr;
|
prev = curr;
|
||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
free(prev);
|
free(prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_set_string(const char *key, const char *value)
|
void config_set_string(const char *key, const char *value)
|
||||||
{
|
{
|
||||||
struct configitem *item;
|
struct configitem *item;
|
||||||
struct configitem **itemp = &s_config.head;
|
struct configitem **itemp = &s_config.head;
|
||||||
|
|
||||||
while (*itemp != NULL)
|
while (*itemp != NULL)
|
||||||
{
|
{
|
||||||
if (strcasecmp((*itemp)->setting, key) == 0)
|
if (strcasecmp((*itemp)->setting, key) == 0)
|
||||||
{
|
{
|
||||||
item = *itemp;
|
item = *itemp;
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
{
|
{
|
||||||
*itemp = item->next;
|
*itemp = item->next;
|
||||||
free(item);
|
free(item);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strncpy(item->value, value, sizeof item->value);
|
strncpy(item->value, value, sizeof item->value);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
itemp = &(*itemp)->next;
|
itemp = &(*itemp)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value == NULL) return;
|
if (value == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
*itemp = malloc(sizeof *item);
|
*itemp = malloc(sizeof *item);
|
||||||
item = *itemp;
|
item = *itemp;
|
||||||
|
|
||||||
strncpy(item->setting, key, sizeof item->setting);
|
strncpy(item->setting, key, sizeof item->setting);
|
||||||
strncpy(item->value, value, sizeof item->value);
|
strncpy(item->value, value, sizeof item->value);
|
||||||
item->next = NULL;
|
item->next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void config_rehash(void)
|
static void config_rehash(void)
|
||||||
{
|
{
|
||||||
FILE *f = fopen(s_config.filename, "r");
|
FILE *f = fopen(s_config.filename, "r");
|
||||||
if (f == NULL) return;
|
if (f == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
config_free();
|
config_free();
|
||||||
|
|
||||||
while (!feof(f))
|
while (!feof(f))
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
if (fgets(buf, sizeof buf, f) <= 0) break;
|
if (fgets(buf, sizeof buf, f) <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
/* Ignore comments */
|
/* Ignore comments */
|
||||||
if (*buf == '#') continue;
|
if (*buf == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
char *n = strchr(buf, '=');
|
char *n = strchr(buf, '=');
|
||||||
if (n == NULL) continue;
|
if (n == NULL)
|
||||||
*n++ = '\0';
|
continue;
|
||||||
|
*n++ = '\0';
|
||||||
|
|
||||||
char *eol = strchr(n, '\n');
|
char *eol = strchr(n, '\n');
|
||||||
if (eol != NULL) *eol = '\0';
|
if (eol != NULL)
|
||||||
|
*eol = '\0';
|
||||||
|
|
||||||
config_set_string(buf, n);
|
config_set_string(buf, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void config_write(void)
|
static void config_write(void)
|
||||||
{
|
{
|
||||||
FILE *f = fopen(s_config.filename, "w");
|
FILE *f = fopen(s_config.filename, "w");
|
||||||
if (f == NULL) return;
|
if (f == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
struct configitem *curr;
|
struct configitem *curr;
|
||||||
for (curr = s_config.head; curr != NULL; curr = curr->next)
|
for (curr = s_config.head; curr != NULL; curr = curr->next)
|
||||||
{
|
{
|
||||||
fprintf(f, "%s=%s\n", curr->setting, curr->value);
|
fprintf(f, "%s=%s\n", curr->setting, curr->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_init(const char *filename)
|
void config_init(const char *filename)
|
||||||
{
|
{
|
||||||
s_config.filename = filename;
|
s_config.filename = filename;
|
||||||
s_config.head = NULL;
|
s_config.head = NULL;
|
||||||
|
|
||||||
config_rehash();
|
config_rehash();
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_deinit(void)
|
void config_deinit(void)
|
||||||
{
|
{
|
||||||
config_write();
|
config_write();
|
||||||
config_free();
|
config_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_set_int(const char *setting, int value)
|
void config_set_int(const char *setting, int value)
|
||||||
{
|
{
|
||||||
char c[MAXCONFIGLEN];
|
char c[MAXCONFIGLEN];
|
||||||
snprintf(c, sizeof c, "%d", value);
|
snprintf(c, sizeof c, "%d", value);
|
||||||
config_set_string(setting, c);
|
config_set_string(setting, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_set_float(const char *setting, float value)
|
void config_set_float(const char *setting, float value)
|
||||||
{
|
{
|
||||||
char c[MAXCONFIGLEN];
|
char c[MAXCONFIGLEN];
|
||||||
snprintf(c, sizeof c, "%f", value);
|
snprintf(c, sizeof c, "%f", value);
|
||||||
config_set_string(setting, c);
|
config_set_string(setting, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_get_string(const char *setting, char **value)
|
int config_get_string(const char *setting, char **value)
|
||||||
{
|
{
|
||||||
struct configitem *curr;
|
struct configitem *curr;
|
||||||
for (curr = s_config.head; curr != NULL; curr = curr->next)
|
for (curr = s_config.head; curr != NULL; curr = curr->next)
|
||||||
{
|
{
|
||||||
if (strcasecmp(curr->setting, setting) == 0)
|
if (strcasecmp(curr->setting, setting) == 0)
|
||||||
{
|
{
|
||||||
*value = curr->value;
|
*value = curr->value;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*value = NULL;
|
*value = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_get_int(const char *setting, int *value)
|
int config_get_int(const char *setting, int *value)
|
||||||
{
|
{
|
||||||
char *c, *endptr;
|
char *c, *endptr;
|
||||||
int v;
|
int v;
|
||||||
|
|
||||||
if (!config_get_string(setting, &c)) return 0;
|
if (!config_get_string(setting, &c))
|
||||||
|
return 0;
|
||||||
|
|
||||||
v = strtol(c, &endptr, 10);
|
v = strtol(c, &endptr, 10);
|
||||||
if (*endptr != '\0') return 0;
|
if (*endptr != '\0')
|
||||||
|
return 0;
|
||||||
|
|
||||||
*value = v;
|
*value = v;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_get_float(const char *setting, float *value)
|
int config_get_float(const char *setting, float *value)
|
||||||
|
@ -172,10 +181,12 @@ int config_get_float(const char *setting, float *value)
|
||||||
char *c, *endptr;
|
char *c, *endptr;
|
||||||
float v;
|
float v;
|
||||||
|
|
||||||
if (!config_get_string(setting, &c)) return 0;
|
if (!config_get_string(setting, &c))
|
||||||
|
return 0;
|
||||||
|
|
||||||
v = strtof(c, &endptr);
|
v = strtof(c, &endptr);
|
||||||
if (*endptr != '\0') return 0;
|
if (*endptr != '\0')
|
||||||
|
return 0;
|
||||||
|
|
||||||
*value = v;
|
*value = v;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
371
gauge.c
371
gauge.c
|
@ -1,4 +1,4 @@
|
||||||
#include <GL/glfw.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <FTGL/ftgl.h>
|
#include <FTGL/ftgl.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -11,227 +11,238 @@ void init_gauges(void)
|
||||||
|
|
||||||
void DrawArc(float inner, float outer, float start_angle, float arc_angle, int num_segments)
|
void DrawArc(float inner, float outer, float start_angle, float arc_angle, int num_segments)
|
||||||
{
|
{
|
||||||
num_segments = 72;
|
num_segments = 72;
|
||||||
float theta = arc_angle / (float)(num_segments - 1);//theta is now calculated from the arc angle instead, the - 1 bit comes from the fact that the arc is open
|
float theta = arc_angle / (float)(num_segments - 1); // theta is now calculated from the arc angle instead, the - 1 bit comes from the fact that the arc is open
|
||||||
|
|
||||||
float tangetial_factor = tanf(theta);
|
float tangetial_factor = tanf(theta);
|
||||||
|
|
||||||
float radial_factor = cosf(theta);
|
float radial_factor = cosf(theta);
|
||||||
|
|
||||||
float xi = inner * sinf(start_angle); //we now start at the start angle
|
float xi = inner * sinf(start_angle); // we now start at the start angle
|
||||||
float yi = inner * cosf(start_angle);
|
float yi = inner * cosf(start_angle);
|
||||||
float xo = outer * sinf(start_angle); //we now start at the start angle
|
float xo = outer * sinf(start_angle); // we now start at the start angle
|
||||||
float yo = outer * cosf(start_angle);
|
float yo = outer * cosf(start_angle);
|
||||||
|
|
||||||
|
glBegin(GL_TRIANGLE_STRIP); // since the arc is not a closed curve, this is a strip now
|
||||||
|
int ii;
|
||||||
|
for (ii = 0; ii < num_segments; ii++)
|
||||||
|
{
|
||||||
|
glVertex3f(xi, yi, 0);
|
||||||
|
glVertex3f(xo, yo, 0);
|
||||||
|
|
||||||
glBegin(GL_TRIANGLE_STRIP);//since the arc is not a closed curve, this is a strip now
|
float txi = -yi;
|
||||||
int ii;
|
float tyi = xi;
|
||||||
for(ii = 0; ii < num_segments; ii++)
|
|
||||||
{
|
|
||||||
glVertex3f(xi, yi, 0);
|
|
||||||
glVertex3f(xo, yo, 0);
|
|
||||||
|
|
||||||
float txi = -yi;
|
xi += txi * tangetial_factor;
|
||||||
float tyi = xi;
|
yi += tyi * tangetial_factor;
|
||||||
|
|
||||||
xi += txi * tangetial_factor;
|
xi *= radial_factor;
|
||||||
yi += tyi * tangetial_factor;
|
yi *= radial_factor;
|
||||||
|
|
||||||
xi *= radial_factor;
|
float txo = -yo;
|
||||||
yi *= radial_factor;
|
float tyo = xo;
|
||||||
|
|
||||||
float txo = -yo;
|
xo += txo * tangetial_factor;
|
||||||
float tyo = xo;
|
yo += tyo * tangetial_factor;
|
||||||
|
|
||||||
xo += txo * tangetial_factor;
|
xo *= radial_factor;
|
||||||
yo += tyo * tangetial_factor;
|
yo *= radial_factor;
|
||||||
|
}
|
||||||
xo *= radial_factor;
|
glEnd();
|
||||||
yo *= radial_factor;
|
|
||||||
}
|
|
||||||
glEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
float theta = 2 * 3.1415926 / (float)num_segments;
|
float theta = 2 * 3.1415926 / (float)num_segments;
|
||||||
float c = cosf(theta);//precalculate the sine and cosine
|
float c = cosf(theta);//precalculate the sine and cosine
|
||||||
float s = sinf(theta);
|
float s = sinf(theta);
|
||||||
float t;
|
float t;
|
||||||
|
|
||||||
float x = r;//we start at angle = 0
|
float x = r;//we start at angle = 0
|
||||||
float y = 0;
|
float y = 0;
|
||||||
|
|
||||||
glBegin(GL_LINE_LOOP);
|
glBegin(GL_LINE_LOOP);
|
||||||
int ii;
|
int ii;
|
||||||
for(ii = 0; ii < num_segments; ii++)
|
for(ii = 0; ii < num_segments; ii++)
|
||||||
{
|
{
|
||||||
glVertex3f(x + cx, y + cy, 0);//output vertex
|
glVertex3f(x + cx, y + cy, 0);//output vertex
|
||||||
|
|
||||||
//apply the rotation matrix
|
//apply the rotation matrix
|
||||||
t = x;
|
t = x;
|
||||||
x = c * x - s * y;
|
x = c * x - s * y;
|
||||||
y = s * t + c * y;
|
y = s * t + c * y;
|
||||||
}
|
}
|
||||||
glEnd();
|
glEnd();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
void drawDial(const struct gauge *gauge, float value, int style)
|
void drawDial(const struct gauge *gauge, float value, int style)
|
||||||
{
|
{
|
||||||
float range = gauge->rangemax - gauge->rangemin;
|
float range = gauge->rangemax - gauge->rangemin;
|
||||||
float angle = gauge->anglemax - gauge->anglemin;
|
float angle = gauge->anglemax - gauge->anglemin;
|
||||||
float cura = (value - gauge->rangemin) / range * angle + gauge->anglemin;
|
float cura = (value - gauge->rangemin) / range * angle + gauge->anglemin;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
switch (style)
|
switch (style)
|
||||||
{
|
{
|
||||||
case GT_NONE:
|
case GT_NONE:
|
||||||
break;
|
break;
|
||||||
case GT_BAR:
|
case GT_BAR:
|
||||||
glColor4f(gauge->dial.r, gauge->dial.g, gauge->dial.b, gauge->dial.a);
|
glColor4f(gauge->dial.r, gauge->dial.g, gauge->dial.b, gauge->dial.a);
|
||||||
DrawArc(gauge->majorstart, gauge->majorend, cura, cura - gauge->anglemin, 10);
|
DrawArc(gauge->majorstart, gauge->majorend, cura, cura - gauge->anglemin, 10);
|
||||||
break;
|
break;
|
||||||
case GT_LINE2:
|
case GT_LINE2:
|
||||||
glColor4f(gauge->dial.r, gauge->dial.g, gauge->dial.b, gauge->dial.a);
|
glColor4f(gauge->dial.r, gauge->dial.g, gauge->dial.b, gauge->dial.a);
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
glVertex3f(0, 0, 0);
|
glVertex3f(0, 0, 0);
|
||||||
glVertex3f(sin(cura), cos(cura), 0);
|
glVertex3f(sin(cura), cos(cura), 0);
|
||||||
glEnd();
|
glEnd();
|
||||||
break;
|
break;
|
||||||
case GT_LINE:
|
case GT_LINE:
|
||||||
glColor4f(1.0, 0.0, 0.0, 1.0);
|
glColor4f(1.0, 0.0, 0.0, 1.0);
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
glVertex3f(sin(cura) * 0.8, cos(cura) * 0.8, 0);
|
glVertex3f(sin(cura) * 0.8, cos(cura) * 0.8, 0);
|
||||||
glVertex3f(sin(cura), cos(cura), 0);
|
glVertex3f(sin(cura), cos(cura), 0);
|
||||||
glEnd();
|
glEnd();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case GT_NEEDLE:
|
case GT_NEEDLE:
|
||||||
glColor4f(gauge->dial.r, gauge->dial.g, gauge->dial.b, gauge->dial.a);
|
glColor4f(gauge->dial.r, gauge->dial.g, gauge->dial.b, gauge->dial.a);
|
||||||
glRotatef(cura * -180.0 / M_PI, 0.0, 0.0, 1.0);
|
glRotatef(cura * -180.0 / M_PI, 0.0, 0.0, 1.0);
|
||||||
glBegin(GL_TRIANGLE_STRIP);
|
glBegin(GL_TRIANGLE_STRIP);
|
||||||
//glVertex3f(-0.01, -0.04, 0.0);
|
// glVertex3f(-0.01, -0.04, 0.0);
|
||||||
//glVertex3f(0.01, -0.04, 0.0);
|
// glVertex3f(0.01, -0.04, 0.0);
|
||||||
//glVertex3f(-0.02, 0, 0.0);
|
// glVertex3f(-0.02, 0, 0.0);
|
||||||
//glVertex3f(0.02, 0.0, 0.0);
|
// glVertex3f(0.02, 0.0, 0.0);
|
||||||
//glVertex3f(-0.005, 1.0, 0.0);
|
// glVertex3f(-0.005, 1.0, 0.0);
|
||||||
//glVertex3f(0.005, 1.0, 0.0);
|
// glVertex3f(0.005, 1.0, 0.0);
|
||||||
glVertex3f(-0.02, 0.2, 0.0);
|
glVertex3f(-0.02, 0.2, 0.0);
|
||||||
glVertex3f(0.02, 0.2, 0.0);
|
glVertex3f(0.02, 0.2, 0.0);
|
||||||
glVertex3f(-0.005, 1.0, 0.0);
|
glVertex3f(-0.005, 1.0, 0.0);
|
||||||
glVertex3f(0.005, 1.0, 0.0);
|
glVertex3f(0.005, 1.0, 0.0);
|
||||||
//glVertex3f(0.0, 1.0, 0.0);
|
// glVertex3f(0.0, 1.0, 0.0);
|
||||||
glEnd();
|
glEnd();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void draw_gauge(const struct gauge *gauge, float value, float red, FTGLfont *font, int gaugetype)
|
void draw_gauge(const struct gauge *gauge, float value, float red, FTGLfont *font, int gaugetype)
|
||||||
{
|
{
|
||||||
float range = gauge->rangemax - gauge->rangemin;
|
float range = gauge->rangemax - gauge->rangemin;
|
||||||
float angle = gauge->anglemax - gauge->anglemin;
|
float angle = gauge->anglemax - gauge->anglemin;
|
||||||
float major;// = angle / (range / gauge->majorstep + 0.0);
|
float major; // = angle / (range / gauge->majorstep + 0.0);
|
||||||
float minor;// = angle / (range / gauge->minorstep + 0.0);
|
float minor; // = angle / (range / gauge->minorstep + 0.0);
|
||||||
float cura;
|
float cura;
|
||||||
float x1, y1, x2, y2;
|
float x1, y1, x2, y2;
|
||||||
int ii;
|
int ii;
|
||||||
|
|
||||||
float majorstep = gauge->majorstep;
|
float majorstep = gauge->majorstep;
|
||||||
float minorstep = gauge->minorstep;
|
float minorstep = gauge->minorstep;
|
||||||
|
|
||||||
while (1) {
|
while (1)
|
||||||
major = angle / (range / majorstep + 0.0);
|
{
|
||||||
minor = angle / (range / minorstep + 0.0);
|
major = angle / (range / majorstep + 0.0);
|
||||||
if (fabsf(major) < 12 * M_PI / 180.0) {
|
minor = angle / (range / minorstep + 0.0);
|
||||||
majorstep *= 2;
|
if (fabsf(major) < 12 * M_PI / 180.0)
|
||||||
minorstep = majorstep / 2;
|
{
|
||||||
} else {
|
majorstep *= 2;
|
||||||
break;
|
minorstep = majorstep / 2;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (value < gauge->rangemin) value = gauge->rangemin;
|
if (value < gauge->rangemin)
|
||||||
if (value > gauge->rangemax * 2) value = gauge->rangemax * 2;
|
value = gauge->rangemin;
|
||||||
|
if (value > gauge->rangemax * 2)
|
||||||
|
value = gauge->rangemax * 2;
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glScalef(gauge->radius, gauge->radius, 1.0);
|
glScalef(gauge->radius, gauge->radius, 1.0);
|
||||||
|
|
||||||
if (red > 0) {
|
if (red > 0)
|
||||||
glLineWidth(1.0);
|
{
|
||||||
glColor4f(0.8, 0.0, 0.0, 1.0);
|
glLineWidth(1.0);
|
||||||
|
glColor4f(0.8, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
cura = (red - gauge->rangemin) / range * angle + gauge->anglemin;
|
cura = (red - gauge->rangemin) / range * angle + gauge->anglemin;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
float x1 = sin(cura) * gauge->majorstart;
|
float x1 = sin(cura) * gauge->majorstart;
|
||||||
float y1 = cos(cura) * gauge->majorstart;
|
float y1 = cos(cura) * gauge->majorstart;
|
||||||
float x2 = sin(cura) * gauge->majorend;
|
float x2 = sin(cura) * gauge->majorend;
|
||||||
float y2 = cos(cura) * gauge->majorend;
|
float y2 = cos(cura) * gauge->majorend;
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
glVertex3f(x1, y1, 0);
|
glVertex3f(x1, y1, 0);
|
||||||
glVertex3f(x2, y2, 0);
|
glVertex3f(x2, y2, 0);
|
||||||
glEnd();*/
|
glEnd();*/
|
||||||
|
|
||||||
// printf("%f -> %f\n", cura, gauge->anglemax);
|
// printf("%f -> %f\n", cura, gauge->anglemax);
|
||||||
DrawArc(gauge->majorstart, gauge->majorend, gauge->anglemax, gauge->anglemax - cura, 10);
|
DrawArc(gauge->majorstart, gauge->majorend, gauge->anglemax, gauge->anglemax - cura, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
glLineWidth(gauge->minorwidth);
|
glLineWidth(gauge->minorwidth);
|
||||||
glColor4f(gauge->minor.r, gauge->minor.g, gauge->minor.b, gauge->minor.a);
|
glColor4f(gauge->minor.r, gauge->minor.g, gauge->minor.b, gauge->minor.a);
|
||||||
// for (cura = gauge->anglemin; cura < gauge->anglemax; cura += minor)
|
// for (cura = gauge->anglemin; cura < gauge->anglemax; cura += minor)
|
||||||
for (ii = 0; ii <= range / minorstep; ii++)
|
for (ii = 0; ii <= range / minorstep; ii++)
|
||||||
{
|
{
|
||||||
if (red > 0 && ii * minorstep >= red) {
|
if (red > 0 && ii * minorstep >= red)
|
||||||
glColor4f(1.0, 1.0, 1.0, 1.0);
|
{
|
||||||
}
|
glColor4f(1.0, 1.0, 1.0, 1.0);
|
||||||
float cura = gauge->anglemin + ii * minor;
|
}
|
||||||
x1 = sin(cura) * gauge->minorstart;
|
float cura = gauge->anglemin + ii * minor;
|
||||||
y1 = cos(cura) * gauge->minorstart;
|
x1 = sin(cura) * gauge->minorstart;
|
||||||
x2 = sin(cura) * gauge->minorend;
|
y1 = cos(cura) * gauge->minorstart;
|
||||||
y2 = cos(cura) * gauge->minorend;
|
x2 = sin(cura) * gauge->minorend;
|
||||||
glBegin(GL_LINES);
|
y2 = cos(cura) * gauge->minorend;
|
||||||
glVertex3f(x1, y1, 0);
|
glBegin(GL_LINES);
|
||||||
glVertex3f(x2, y2, 0);
|
glVertex3f(x1, y1, 0);
|
||||||
glEnd();
|
glVertex3f(x2, y2, 0);
|
||||||
}
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
glLineWidth(gauge->majorwidth);
|
glLineWidth(gauge->majorwidth);
|
||||||
glColor4f(gauge->major.r, gauge->major.g, gauge->major.b, gauge->major.a);
|
glColor4f(gauge->major.r, gauge->major.g, gauge->major.b, gauge->major.a);
|
||||||
// for (cura = gauge->anglemin; cura < gauge->anglemax; cura += major)
|
// for (cura = gauge->anglemin; cura < gauge->anglemax; cura += major)
|
||||||
for (ii = 0; ii <= range / majorstep; ii++)
|
for (ii = 0; ii <= range / majorstep; ii++)
|
||||||
{
|
{
|
||||||
if (red > 0 && ii * majorstep > red) {
|
if (red > 0 && ii * majorstep > red)
|
||||||
glColor4f(1.0, 1.0, 1.0, 1.0);
|
{
|
||||||
}
|
glColor4f(1.0, 1.0, 1.0, 1.0);
|
||||||
float cura = gauge->anglemin + ii * major;
|
}
|
||||||
x1 = sin(cura) * gauge->majorstart;
|
float cura = gauge->anglemin + ii * major;
|
||||||
y1 = cos(cura) * gauge->majorstart;
|
x1 = sin(cura) * gauge->majorstart;
|
||||||
x2 = sin(cura) * gauge->majorend;
|
y1 = cos(cura) * gauge->majorstart;
|
||||||
y2 = cos(cura) * gauge->majorend;
|
x2 = sin(cura) * gauge->majorend;
|
||||||
glBegin(GL_LINES);
|
y2 = cos(cura) * gauge->majorend;
|
||||||
glVertex3f(x1, y1, 0);
|
glBegin(GL_LINES);
|
||||||
glVertex3f(x2, y2, 0);
|
glVertex3f(x1, y1, 0);
|
||||||
glEnd();
|
glVertex3f(x2, y2, 0);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
char text[10];
|
char text[10];
|
||||||
if (gauge->majorstep > 100) {
|
if (gauge->majorstep > 100)
|
||||||
snprintf(text, sizeof text, "%d", (int)(ii * majorstep / 1000 + gauge->rangemin));
|
{
|
||||||
} else {
|
snprintf(text, sizeof text, "%d", (int)(ii * majorstep / 1000 + gauge->rangemin));
|
||||||
if (range == 1) {
|
}
|
||||||
snprintf(text, sizeof text, ii == 0 ? "E" : ii == 1 ? "½" : "F");
|
else
|
||||||
} else {
|
{
|
||||||
snprintf(text, sizeof text, "%d", (int)(ii * majorstep + gauge->rangemin));
|
if (range == 1)
|
||||||
}
|
{
|
||||||
}
|
snprintf(text, sizeof text, ii == 0 ? "E" : ii == 1 ? "½"
|
||||||
|
: "F");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(text, sizeof text, "%d", (int)(ii * majorstep + gauge->rangemin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float scale = (gauge->majorend - gauge->majorstart) * 1.5;
|
float scale = (gauge->majorend - gauge->majorstart) * 1.5;
|
||||||
float offs = gauge->majorstart - scale;
|
float offs = gauge->majorstart - scale;
|
||||||
drawText(text, font, sin(cura) * offs, cos(cura) * offs, scale, scale, TA_CENTRE, TA_CENTRE);
|
drawText(text, font, sin(cura) * offs, cos(cura) * offs, scale, scale, TA_CENTRE, TA_CENTRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawDial(gauge, value, gaugetype);
|
drawDial(gauge, value, gaugetype);
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
75
gauge.h
75
gauge.h
|
@ -5,60 +5,61 @@
|
||||||
|
|
||||||
struct colour
|
struct colour
|
||||||
{
|
{
|
||||||
float r, g, b, a;
|
float r, g, b, a;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OG_SHIFT 1 // key
|
#define OG_SHIFT 1 // key
|
||||||
#define OG_CTRL 2 // key
|
#define OG_CTRL 2 // key
|
||||||
|
|
||||||
#define OG_TURBO 8192 // show turbo gauge
|
#define OG_TURBO 8192 // show turbo gauge
|
||||||
#define OG_KM 16384 // if not set - user prefers MILES
|
#define OG_KM 16384 // if not set - user prefers MILES
|
||||||
#define OG_BAR 32768 // if not set - user prefers PSI
|
#define OG_BAR 32768 // if not set - user prefers PSI
|
||||||
|
|
||||||
// DL_x - bits for OutGaugePack DashLights and ShowLights
|
// DL_x - bits for OutGaugePack DashLights and ShowLights
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
DL_SHIFT, // bit 0 - shift light
|
DL_SHIFT, // bit 0 - shift light
|
||||||
DL_FULLBEAM, // bit 1 - full beam
|
DL_FULLBEAM, // bit 1 - full beam
|
||||||
DL_HANDBRAKE, // bit 2 - handbrake
|
DL_HANDBRAKE, // bit 2 - handbrake
|
||||||
DL_PITSPEED, // bit 3 - pit speed limiter
|
DL_PITSPEED, // bit 3 - pit speed limiter
|
||||||
DL_TC, // bit 4 - TC active or switched off
|
DL_TC, // bit 4 - TC active or switched off
|
||||||
DL_SIGNAL_L, // bit 5 - left turn signal
|
DL_SIGNAL_L, // bit 5 - left turn signal
|
||||||
DL_SIGNAL_R, // bit 6 - right turn signal
|
DL_SIGNAL_R, // bit 6 - right turn signal
|
||||||
DL_SIGNAL_ANY, // bit 7 - shared turn signal
|
DL_SIGNAL_ANY, // bit 7 - shared turn signal
|
||||||
DL_OILWARN, // bit 8 - oil pressure warning
|
DL_OILWARN, // bit 8 - oil pressure warning
|
||||||
DL_BATTERY, // bit 9 - battery warning
|
DL_BATTERY, // bit 9 - battery warning
|
||||||
DL_ABS, // bit 10 - ABS active or switched off
|
DL_ABS, // bit 10 - ABS active or switched off
|
||||||
DL_SPARE, // bit 11
|
DL_SPARE, // bit 11
|
||||||
DL_NUM
|
DL_NUM
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gauge
|
struct gauge
|
||||||
{
|
{
|
||||||
char name[16];
|
char name[16];
|
||||||
float radius;
|
float radius;
|
||||||
float anglemin;
|
float anglemin;
|
||||||
float anglemax;
|
float anglemax;
|
||||||
float rangemin;
|
float rangemin;
|
||||||
float rangemax;
|
float rangemax;
|
||||||
|
|
||||||
float majorstep;
|
float majorstep;
|
||||||
float majorwidth;
|
float majorwidth;
|
||||||
float majorstart;
|
float majorstart;
|
||||||
float majorend;
|
float majorend;
|
||||||
struct colour major;
|
struct colour major;
|
||||||
|
|
||||||
float minorstep;
|
float minorstep;
|
||||||
float minorwidth;
|
float minorwidth;
|
||||||
float minorstart;
|
float minorstart;
|
||||||
float minorend;
|
float minorend;
|
||||||
struct colour minor;
|
struct colour minor;
|
||||||
|
|
||||||
struct colour dial;
|
struct colour dial;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
GT_NONE,
|
GT_NONE,
|
||||||
GT_NEEDLE,
|
GT_NEEDLE,
|
||||||
GT_LINE,
|
GT_LINE,
|
||||||
|
|
37
gettime.h
37
gettime.h
|
@ -32,29 +32,36 @@ static inline LARGE_INTEGER getFILETIMEoffset()
|
||||||
|
|
||||||
static inline int clock_gettime(int X, struct timespec *ts)
|
static inline int clock_gettime(int X, struct timespec *ts)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER t;
|
LARGE_INTEGER t;
|
||||||
FILETIME f;
|
FILETIME f;
|
||||||
double microseconds;
|
double microseconds;
|
||||||
static LARGE_INTEGER offset;
|
static LARGE_INTEGER offset;
|
||||||
static double frequencyToMicroseconds;
|
static double frequencyToMicroseconds;
|
||||||
static int initialized = 0;
|
static int initialized = 0;
|
||||||
static BOOL usePerformanceCounter = 0;
|
static BOOL usePerformanceCounter = 0;
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized)
|
||||||
|
{
|
||||||
LARGE_INTEGER performanceFrequency;
|
LARGE_INTEGER performanceFrequency;
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
|
usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
|
||||||
if (usePerformanceCounter) {
|
if (usePerformanceCounter)
|
||||||
|
{
|
||||||
QueryPerformanceCounter(&offset);
|
QueryPerformanceCounter(&offset);
|
||||||
frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
|
frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
offset = getFILETIMEoffset();
|
offset = getFILETIMEoffset();
|
||||||
frequencyToMicroseconds = 10.;
|
frequencyToMicroseconds = 10.;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (usePerformanceCounter) {
|
if (usePerformanceCounter)
|
||||||
|
{
|
||||||
QueryPerformanceCounter(&t);
|
QueryPerformanceCounter(&t);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
GetSystemTimeAsFileTime(&f);
|
GetSystemTimeAsFileTime(&f);
|
||||||
t.QuadPart = f.dwHighDateTime;
|
t.QuadPart = f.dwHighDateTime;
|
||||||
t.QuadPart <<= 32;
|
t.QuadPart <<= 32;
|
||||||
|
@ -73,9 +80,9 @@ static inline int clock_gettime(int X, struct timespec *ts)
|
||||||
|
|
||||||
static inline unsigned gettime(void)
|
static inline unsigned gettime(void)
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
595
insim.c
595
insim.c
|
@ -1,4 +1,4 @@
|
||||||
//#define USE_IPV6
|
// #define USE_IPV6
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
@ -7,9 +7,9 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#define MSG_NOSIGNAL 0
|
#define MSG_NOSIGNAL 0
|
||||||
#else
|
#else
|
||||||
//#include <sys/types.h>
|
// #include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
//#include <netinet/in.h>
|
// #include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -25,7 +25,8 @@
|
||||||
struct conninfo s_conninfo[256];
|
struct conninfo s_conninfo[256];
|
||||||
struct carinfo s_carinfo[256];
|
struct carinfo s_carinfo[256];
|
||||||
|
|
||||||
struct insim_buffer {
|
struct insim_buffer
|
||||||
|
{
|
||||||
int state;
|
int state;
|
||||||
uint8_t buffer[65536];
|
uint8_t buffer[65536];
|
||||||
int pos;
|
int pos;
|
||||||
|
@ -41,339 +42,353 @@ static uint8_t s_send_pos;
|
||||||
|
|
||||||
void insim_queue(const void *buffer, size_t size)
|
void insim_queue(const void *buffer, size_t size)
|
||||||
{
|
{
|
||||||
uint8_t *packet = malloc(size);
|
uint8_t *packet = malloc(size);
|
||||||
memcpy(packet, buffer, size);
|
memcpy(packet, buffer, size);
|
||||||
queue_produce(s_send_queue, packet);
|
queue_produce(s_send_queue, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
int insim_dequeue(int fd)
|
int insim_dequeue(int fd)
|
||||||
{
|
{
|
||||||
if (s_send_packet == NULL) queue_consume(s_send_queue, (void *)&s_send_packet);
|
if (s_send_packet == NULL)
|
||||||
|
queue_consume(s_send_queue, (void *)&s_send_packet);
|
||||||
|
|
||||||
if (s_send_packet != NULL)
|
if (s_send_packet != NULL)
|
||||||
{
|
{
|
||||||
ssize_t s = send(fd, (char *)s_send_packet + s_send_pos, s_send_packet[0] - s_send_pos, MSG_NOSIGNAL);
|
ssize_t s = send(fd, (char *)s_send_packet + s_send_pos, s_send_packet[0] - s_send_pos, MSG_NOSIGNAL);
|
||||||
if (s >= 0) s_send_pos += s;
|
if (s >= 0)
|
||||||
if (s_send_pos >= s_send_packet[0])
|
s_send_pos += s;
|
||||||
{
|
if (s_send_pos >= s_send_packet[0])
|
||||||
free(s_send_packet);
|
{
|
||||||
s_send_packet = 0;
|
free(s_send_packet);
|
||||||
s_send_pos = 0;
|
s_send_packet = 0;
|
||||||
return 1;
|
s_send_pos = 0;
|
||||||
}
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_request_info(void)
|
void insim_request_info(void)
|
||||||
{
|
{
|
||||||
memset(s_conninfo, 0, sizeof s_conninfo);
|
memset(s_conninfo, 0, sizeof s_conninfo);
|
||||||
memset(s_carinfo, 0, sizeof s_carinfo);
|
memset(s_carinfo, 0, sizeof s_carinfo);
|
||||||
|
|
||||||
struct IS_TINY p;
|
struct IS_TINY p;
|
||||||
p.Size = sizeof p;
|
p.Size = sizeof p;
|
||||||
p.Type = ISP_TINY;
|
p.Type = ISP_TINY;
|
||||||
p.ReqI = 2;
|
p.ReqI = 2;
|
||||||
p.SubT = TINY_NCN;
|
p.SubT = TINY_NCN;
|
||||||
insim_queue(&p, sizeof p);
|
insim_queue(&p, sizeof p);
|
||||||
|
|
||||||
p.Size = sizeof p;
|
p.Size = sizeof p;
|
||||||
p.Type = ISP_TINY;
|
p.Type = ISP_TINY;
|
||||||
p.ReqI = 3;
|
p.ReqI = 3;
|
||||||
p.SubT = TINY_NPL;
|
p.SubT = TINY_NPL;
|
||||||
insim_queue(&p, sizeof p);
|
insim_queue(&p, sizeof p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_handle_tiny(int fd, const void *buffer)
|
void insim_handle_tiny(int fd, const void *buffer)
|
||||||
{
|
{
|
||||||
const struct IS_TINY *p = buffer;
|
const struct IS_TINY *p = buffer;
|
||||||
switch (p->SubT)
|
switch (p->SubT)
|
||||||
{
|
{
|
||||||
case TINY_NONE:
|
case TINY_NONE:
|
||||||
{
|
{
|
||||||
struct IS_TINY r;
|
struct IS_TINY r;
|
||||||
r.Size = sizeof r;
|
r.Size = sizeof r;
|
||||||
r.Type = ISP_TINY;
|
r.Type = ISP_TINY;
|
||||||
r.ReqI = 0;
|
r.ReqI = 0;
|
||||||
r.SubT = TINY_NONE;
|
r.SubT = TINY_NONE;
|
||||||
insim_queue(&r, sizeof r);
|
insim_queue(&r, sizeof r);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ltc_duty(const char *uname, int state)
|
static void ltc_duty(const char *uname, int state)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++)
|
||||||
if (!strcmp(uname, s_conninfo[i].uname)) {
|
{
|
||||||
s_conninfo[i].state = state;
|
if (!strcmp(uname, s_conninfo[i].uname))
|
||||||
printf("Player %s state %d\n", uname, state);
|
{
|
||||||
return;
|
s_conninfo[i].state = state;
|
||||||
}
|
printf("Player %s state %d\n", uname, state);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_handle_ism(int fd, const void *buffer)
|
void insim_handle_ism(int fd, const void *buffer)
|
||||||
{
|
{
|
||||||
const struct IS_ISM *p = buffer;
|
const struct IS_ISM *p = buffer;
|
||||||
|
|
||||||
printf("Joined %s\n", p->HName);
|
printf("Joined %s\n", p->HName);
|
||||||
insim_request_info();
|
insim_request_info();
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_handle_mso(int fd, const void *buffer)
|
void insim_handle_mso(int fd, const void *buffer)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
const struct IS_MSO *p = buffer;
|
const struct IS_MSO *p = buffer;
|
||||||
printf("%d %d %d %d %s\n", p->UCID, p->PLID, p->UserType, p->TextStart, p->Msg);
|
printf("%d %d %d %d %s\n", p->UCID, p->PLID, p->UserType, p->TextStart, p->Msg);
|
||||||
|
|
||||||
char buf[128], *bufp = buf;
|
char buf[128], *bufp = buf;
|
||||||
strncpy(buf, p->Msg, sizeof buf);
|
strncpy(buf, p->Msg, sizeof buf);
|
||||||
|
|
||||||
int state = 0;
|
int state = 0;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++)
|
||||||
char *a = strsep(&bufp, " ");
|
{
|
||||||
if (a == NULL) return;
|
char *a = strsep(&bufp, " ");
|
||||||
if (i == 0 && strcmp(a, "***")) return;
|
if (a == NULL)
|
||||||
if (i == 1 && (!strcmp(a, "Officer") || !strcmp(a, "Cadet"))) state |= 1;
|
return;
|
||||||
if (i == 2 && state == 1) name = a;
|
if (i == 0 && strcmp(a, "***"))
|
||||||
if (i == 3 && strcmp(a, "has")) return;
|
return;
|
||||||
if (i == 4 && strcmp(a, "gone")) return;
|
if (i == 1 && (!strcmp(a, "Officer") || !strcmp(a, "Cadet")))
|
||||||
if (i == 5 && !strcmp(a, "onduty")) ltc_duty(name, 1);
|
state |= 1;
|
||||||
if (i == 5 && !strcmp(a, "offduty")) ltc_duty(name, 0);
|
if (i == 2 && state == 1)
|
||||||
}
|
name = a;
|
||||||
|
if (i == 3 && strcmp(a, "has"))
|
||||||
|
return;
|
||||||
|
if (i == 4 && strcmp(a, "gone"))
|
||||||
|
return;
|
||||||
|
if (i == 5 && !strcmp(a, "onduty"))
|
||||||
|
ltc_duty(name, 1);
|
||||||
|
if (i == 5 && !strcmp(a, "offduty"))
|
||||||
|
ltc_duty(name, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_handle_ncn(int fd, const void *buffer)
|
void insim_handle_ncn(int fd, const void *buffer)
|
||||||
{
|
{
|
||||||
const struct IS_NCN *p = buffer;
|
const struct IS_NCN *p = buffer;
|
||||||
struct conninfo *c = s_conninfo + p->UCID;
|
struct conninfo *c = s_conninfo + p->UCID;
|
||||||
memset(c, 0, sizeof *c);
|
memset(c, 0, sizeof *c);
|
||||||
c->active = 1;
|
c->active = 1;
|
||||||
strncpy(c->uname, p->UName, sizeof c->uname);
|
strncpy(c->uname, p->UName, sizeof c->uname);
|
||||||
strncpy(c->pname, p->PName, sizeof c->pname);
|
strncpy(c->pname, p->PName, sizeof c->pname);
|
||||||
c->admin = p->Admin;
|
c->admin = p->Admin;
|
||||||
|
|
||||||
printf("Know about connection %s (%s) %d\n", c->pname, c->uname, c->admin);
|
printf("Know about connection %s (%s) %d\n", c->pname, c->uname, c->admin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_handle_cnl(int fd, const void *buffer)
|
void insim_handle_cnl(int fd, const void *buffer)
|
||||||
{
|
{
|
||||||
const struct IS_CNL *p = buffer;
|
const struct IS_CNL *p = buffer;
|
||||||
struct conninfo *c = s_conninfo + p->UCID;
|
struct conninfo *c = s_conninfo + p->UCID;
|
||||||
c->active = 0;
|
c->active = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_handle_cpr(int fd, const void *buffer)
|
void insim_handle_cpr(int fd, const void *buffer)
|
||||||
{
|
{
|
||||||
const struct IS_CPR *p = buffer;
|
const struct IS_CPR *p = buffer;
|
||||||
struct conninfo *c = s_conninfo + p->UCID;
|
struct conninfo *c = s_conninfo + p->UCID;
|
||||||
if (c->active == 0) fprintf(stderr, "Rename of inactive connection\n");
|
if (c->active == 0)
|
||||||
strncpy(c->pname, p->PName, sizeof c->pname);
|
fprintf(stderr, "Rename of inactive connection\n");
|
||||||
|
strncpy(c->pname, p->PName, sizeof c->pname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_handle_npl(int fd, const void *buffer)
|
void insim_handle_npl(int fd, const void *buffer)
|
||||||
{
|
{
|
||||||
const struct IS_NPL *p = buffer;
|
const struct IS_NPL *p = buffer;
|
||||||
struct carinfo *car = s_carinfo + p->PLID;
|
struct carinfo *car = s_carinfo + p->PLID;
|
||||||
memset(car, 0, sizeof *car);
|
memset(car, 0, sizeof *car);
|
||||||
car->active = 1;
|
car->active = 1;
|
||||||
//strncpy(car->cname, p->CName, sizeof car->cname);
|
// strncpy(car->cname, p->CName, sizeof car->cname);
|
||||||
car->ucid = p->UCID;
|
car->ucid = p->UCID;
|
||||||
car->mass = p->H_Mass;
|
car->mass = p->H_Mass;
|
||||||
car->intake = p->H_TRes;
|
car->intake = p->H_TRes;
|
||||||
|
|
||||||
strncpy(car->cname, find_car(p->CName, car->intake, car->mass), sizeof car->cname);
|
strncpy(car->cname, find_car(p->CName, car->intake, car->mass), sizeof car->cname);
|
||||||
|
|
||||||
printf("Car %d joined (%s) - %s\n", p->PLID, car->cname, s_conninfo[car->ucid].uname);
|
printf("Car %d joined (%s) - %s\n", p->PLID, car->cname, s_conninfo[car->ucid].uname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_handle_pll(int fd, const void *buffer)
|
void insim_handle_pll(int fd, const void *buffer)
|
||||||
{
|
{
|
||||||
const struct IS_PLL *p = buffer;
|
const struct IS_PLL *p = buffer;
|
||||||
struct carinfo *car = s_carinfo + p->PLID;
|
struct carinfo *car = s_carinfo + p->PLID;
|
||||||
car->active = 0;
|
car->active = 0;
|
||||||
printf("Car %d left - %s\n", p->PLID, s_conninfo[car->ucid].uname);
|
printf("Car %d left - %s\n", p->PLID, s_conninfo[car->ucid].uname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_handle_mci(int fd, const void *buffer)
|
void insim_handle_mci(int fd, const void *buffer)
|
||||||
{
|
{
|
||||||
const struct IS_MCI *p = buffer;
|
const struct IS_MCI *p = buffer;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < p->NumC; i++)
|
for (i = 0; i < p->NumC; i++)
|
||||||
{
|
{
|
||||||
const struct CompCar *c = p->Info + i;
|
const struct CompCar *c = p->Info + i;
|
||||||
struct carinfo *car = s_carinfo + c->PLID;
|
struct carinfo *car = s_carinfo + c->PLID;
|
||||||
|
|
||||||
car->position = c->Position;
|
car->position = c->Position;
|
||||||
car->info = c->Info;
|
car->info = c->Info;
|
||||||
car->sp3 = c->Sp3;
|
car->sp3 = c->Sp3;
|
||||||
car->x = c->X;
|
car->x = c->X;
|
||||||
car->y = c->Y;
|
car->y = c->Y;
|
||||||
car->z = c->Z;
|
car->z = c->Z;
|
||||||
car->speed = c->Speed;
|
car->speed = c->Speed;
|
||||||
car->direction = c->Direction;
|
car->direction = c->Direction;
|
||||||
car->heading = c->Heading;
|
car->heading = c->Heading;
|
||||||
car->angvel = c->AngVel;
|
car->angvel = c->AngVel;
|
||||||
|
|
||||||
car->hist_x[car->hist] = c->X;
|
car->hist_x[car->hist] = c->X;
|
||||||
car->hist_y[car->hist] = c->Y;
|
car->hist_y[car->hist] = c->Y;
|
||||||
car->hist_s[car->hist] = c->Speed;
|
car->hist_s[car->hist] = c->Speed;
|
||||||
car->hist = (car->hist + 1) % CARPATHSIZE;
|
car->hist = (car->hist + 1) % CARPATHSIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*insim_handler)(int fd, const void *buffer);
|
typedef void (*insim_handler)(int fd, const void *buffer);
|
||||||
|
|
||||||
static const insim_handler s_handlers[] =
|
static const insim_handler s_handlers[] =
|
||||||
{
|
{
|
||||||
NULL, // ISP_NONE // 0 : not used
|
NULL, // ISP_NONE // 0 : not used
|
||||||
NULL, // ISP_ISI // 1 - instruction : insim initialise
|
NULL, // ISP_ISI // 1 - instruction : insim initialise
|
||||||
NULL, // ISP_VER // 2 - info : version info
|
NULL, // ISP_VER // 2 - info : version info
|
||||||
insim_handle_tiny, // ISP_TINY // 3 - both ways : multi purpose
|
insim_handle_tiny, // ISP_TINY // 3 - both ways : multi purpose
|
||||||
NULL, // ISP_SMALL // 4 - both ways : multi purpose
|
NULL, // ISP_SMALL // 4 - both ways : multi purpose
|
||||||
NULL, // ISP_STA // 5 - info : state info
|
NULL, // ISP_STA // 5 - info : state info
|
||||||
NULL, // ISP_SCH // 6 - instruction : single character
|
NULL, // ISP_SCH // 6 - instruction : single character
|
||||||
NULL, // ISP_SFP // 7 - instruction : state flags pack
|
NULL, // ISP_SFP // 7 - instruction : state flags pack
|
||||||
NULL, // ISP_SCC // 8 - instruction : set car camera
|
NULL, // ISP_SCC // 8 - instruction : set car camera
|
||||||
NULL, // ISP_CPP // 9 - both ways : cam pos pack
|
NULL, // ISP_CPP // 9 - both ways : cam pos pack
|
||||||
insim_handle_ism, // ISP_ISM // 10 - info : start multiplayer
|
insim_handle_ism, // ISP_ISM // 10 - info : start multiplayer
|
||||||
insim_handle_mso, // ISP_MSO // 11 - info : message out
|
insim_handle_mso, // ISP_MSO // 11 - info : message out
|
||||||
NULL, // ISP_III // 12 - info : hidden /i message
|
NULL, // ISP_III // 12 - info : hidden /i message
|
||||||
NULL, // ISP_MST // 13 - instruction : type message or /command
|
NULL, // ISP_MST // 13 - instruction : type message or /command
|
||||||
NULL, // ISP_MTC // 14 - instruction : message to a connection
|
NULL, // ISP_MTC // 14 - instruction : message to a connection
|
||||||
NULL, // ISP_MOD // 15 - instruction : set screen mode
|
NULL, // ISP_MOD // 15 - instruction : set screen mode
|
||||||
NULL, // ISP_VTN // 16 - info : vote notification
|
NULL, // ISP_VTN // 16 - info : vote notification
|
||||||
NULL, // ISP_RST // 17 - info : race start
|
NULL, // ISP_RST // 17 - info : race start
|
||||||
insim_handle_ncn, // ISP_NCN // 18 - info : new connection
|
insim_handle_ncn, // ISP_NCN // 18 - info : new connection
|
||||||
insim_handle_cnl, // ISP_CNL // 19 - info : connection left
|
insim_handle_cnl, // ISP_CNL // 19 - info : connection left
|
||||||
insim_handle_cpr, // ISP_CPR // 20 - info : connection renamed
|
insim_handle_cpr, // ISP_CPR // 20 - info : connection renamed
|
||||||
insim_handle_npl, // ISP_NPL // 21 - info : new player (joined race)
|
insim_handle_npl, // ISP_NPL // 21 - info : new player (joined race)
|
||||||
NULL, // ISP_PLP // 22 - info : player pit (keeps slot in race)
|
NULL, // ISP_PLP // 22 - info : player pit (keeps slot in race)
|
||||||
insim_handle_pll, // ISP_PLL // 23 - info : player leave (spectate - loses slot)
|
insim_handle_pll, // ISP_PLL // 23 - info : player leave (spectate - loses slot)
|
||||||
NULL, // ISP_LAP // 24 - info : lap time
|
NULL, // ISP_LAP // 24 - info : lap time
|
||||||
NULL, // ISP_SPX // 25 - info : split x time
|
NULL, // ISP_SPX // 25 - info : split x time
|
||||||
NULL, // ISP_PIT // 26 - info : pit stop start
|
NULL, // ISP_PIT // 26 - info : pit stop start
|
||||||
NULL, // ISP_PSF // 27 - info : pit stop finish
|
NULL, // ISP_PSF // 27 - info : pit stop finish
|
||||||
NULL, // ISP_PLA // 28 - info : pit lane enter / leave
|
NULL, // ISP_PLA // 28 - info : pit lane enter / leave
|
||||||
NULL, // ISP_CCH // 29 - info : camera changed
|
NULL, // ISP_CCH // 29 - info : camera changed
|
||||||
NULL, // ISP_PEN // 30 - info : penalty given or cleared
|
NULL, // ISP_PEN // 30 - info : penalty given or cleared
|
||||||
NULL, // ISP_TOC // 31 - info : take over car
|
NULL, // ISP_TOC // 31 - info : take over car
|
||||||
NULL, // ISP_FLG // 32 - info : flag (yellow or blue)
|
NULL, // ISP_FLG // 32 - info : flag (yellow or blue)
|
||||||
NULL, // ISP_PFL // 33 - info : player flags (help flags)
|
NULL, // ISP_PFL // 33 - info : player flags (help flags)
|
||||||
NULL, // ISP_FIN // 34 - info : finished race
|
NULL, // ISP_FIN // 34 - info : finished race
|
||||||
NULL, // ISP_RES // 35 - info : result confirmed
|
NULL, // ISP_RES // 35 - info : result confirmed
|
||||||
NULL, // ISP_REO // 36 - both ways : reorder (info or instruction)
|
NULL, // ISP_REO // 36 - both ways : reorder (info or instruction)
|
||||||
NULL, // ISP_NLP // 37 - info : node and lap packet
|
NULL, // ISP_NLP // 37 - info : node and lap packet
|
||||||
insim_handle_mci, // ISP_MCI // 38 - info : multi car info
|
insim_handle_mci, // ISP_MCI // 38 - info : multi car info
|
||||||
NULL, // ISP_MSX // 39 - instruction : type message
|
NULL, // ISP_MSX // 39 - instruction : type message
|
||||||
NULL, // ISP_MSL // 40 - instruction : message to local computer
|
NULL, // ISP_MSL // 40 - instruction : message to local computer
|
||||||
NULL, // ISP_CRS // 41 - info : car reset
|
NULL, // ISP_CRS // 41 - info : car reset
|
||||||
NULL, // ISP_BFN // 42 - both ways : delete buttons / receive button requests
|
NULL, // ISP_BFN // 42 - both ways : delete buttons / receive button requests
|
||||||
NULL, // ISP_AXI // 43 - info : autocross layout information
|
NULL, // ISP_AXI // 43 - info : autocross layout information
|
||||||
NULL, // ISP_AXO // 44 - info : hit an autocross object
|
NULL, // ISP_AXO // 44 - info : hit an autocross object
|
||||||
NULL, // ISP_BTN // 45 - instruction : show a button on local or remote screen
|
NULL, // ISP_BTN // 45 - instruction : show a button on local or remote screen
|
||||||
NULL, // ISP_BTC // 46 - info : sent when a user clicks a button
|
NULL, // ISP_BTC // 46 - info : sent when a user clicks a button
|
||||||
NULL, // ISP_BTT // 47 - info : sent after typing into a button
|
NULL, // ISP_BTT // 47 - info : sent after typing into a button
|
||||||
NULL, // ISP_RIP // 48 - both ways : replay information packet
|
NULL, // ISP_RIP // 48 - both ways : replay information packet
|
||||||
NULL, // ISP_SSH // 49 - both ways : screenshot
|
NULL, // ISP_SSH // 49 - both ways : screenshot
|
||||||
NULL, // ISP_CON // 50 - info : contact between cars (collision report)
|
NULL, // ISP_CON // 50 - info : contact between cars (collision report)
|
||||||
NULL, // ISP_OBH // 51 - info : contact car + object (collision report)
|
NULL, // ISP_OBH // 51 - info : contact car + object (collision report)
|
||||||
NULL, // ISP_HLV // 52 - info : report incidents that would violate HLVC
|
NULL, // ISP_HLV // 52 - info : report incidents that would violate HLVC
|
||||||
NULL, // ISP_PLC // 53 - instruction : player cars
|
NULL, // ISP_PLC // 53 - instruction : player cars
|
||||||
NULL, // ISP_AXM // 54 - both ways : autocross multiple objects
|
NULL, // ISP_AXM // 54 - both ways : autocross multiple objects
|
||||||
NULL, // ISP_ACR // 55 - info : admin command report
|
NULL, // ISP_ACR // 55 - info : admin command report
|
||||||
};
|
};
|
||||||
|
|
||||||
void insim_handle(int fd, const uint8_t *buffer)
|
void insim_handle(int fd, const uint8_t *buffer)
|
||||||
{
|
{
|
||||||
uint8_t type = buffer[1];
|
uint8_t type = buffer[1];
|
||||||
if (type <= ISP_ACR && s_handlers[type] != NULL)
|
if (type <= ISP_ACR && s_handlers[type] != NULL)
|
||||||
{
|
{
|
||||||
s_handlers[type](fd, buffer);
|
s_handlers[type](fd, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int insim_recv(int fd, int can_write, int can_read, void *arg)
|
int insim_recv(int fd, int can_write, int can_read, void *arg)
|
||||||
{
|
{
|
||||||
struct insim_buffer *buffer = arg;
|
struct insim_buffer *buffer = arg;
|
||||||
|
|
||||||
if (can_write && buffer->state == 1)
|
if (can_write && buffer->state == 1)
|
||||||
{
|
{
|
||||||
insim_dequeue(fd);
|
insim_dequeue(fd);
|
||||||
}
|
}
|
||||||
if (can_read)
|
if (can_read)
|
||||||
{
|
{
|
||||||
if (buffer->pos >= sizeof buffer->buffer)
|
if (buffer->pos >= sizeof buffer->buffer)
|
||||||
{
|
{
|
||||||
printf("buffer full\n");
|
printf("buffer full\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ssize_t res = recv(fd, (char *)buffer->buffer + buffer->pos, sizeof buffer->buffer - buffer->pos, 0);
|
ssize_t res = recv(fd, (char *)buffer->buffer + buffer->pos, sizeof buffer->buffer - buffer->pos, 0);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (WSAGetLastError() == WSAECONNRESET)
|
if (WSAGetLastError() == WSAECONNRESET)
|
||||||
#else
|
#else
|
||||||
if (errno == ECONNRESET)
|
if (errno == ECONNRESET)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
printf("connreset\n");
|
printf("connreset\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
else if (WSAGetLastError() != WSAEWOULDBLOCK)
|
else if (WSAGetLastError() != WSAEWOULDBLOCK)
|
||||||
#else
|
#else
|
||||||
else if (errno != EWOULDBLOCK && errno != EAGAIN)
|
else if (errno != EWOULDBLOCK && errno != EAGAIN)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
printf("hmm: %s\n", strerror(errno));
|
printf("hmm: %s\n", strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
{
|
{
|
||||||
printf("nothing received\n");
|
printf("nothing received\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->pos += res;
|
buffer->pos += res;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
uint8_t size = buffer->buffer[buffer->offset];
|
uint8_t size = buffer->buffer[buffer->offset];
|
||||||
if (size % 4 != 0)
|
if (size % 4 != 0)
|
||||||
{
|
{
|
||||||
printf("invalid packet, size is %d\n", size);
|
printf("invalid packet, size is %d\n", size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer->pos - buffer->offset >= size)
|
if (buffer->pos - buffer->offset >= size)
|
||||||
{
|
{
|
||||||
insim_handle(fd, buffer->buffer + buffer->offset);
|
insim_handle(fd, buffer->buffer + buffer->offset);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer->pos - buffer->offset > size)
|
if (buffer->pos - buffer->offset > size)
|
||||||
{
|
{
|
||||||
buffer->offset += size;
|
buffer->offset += size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->pos = 0;
|
buffer->pos = 0;
|
||||||
buffer->offset = 0;
|
buffer->offset = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
#ifdef USE_IPV6
|
#ifdef USE_IPV6
|
||||||
|
@ -394,46 +409,46 @@ static void insim_connect(int fd, void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s_insim_tcp.state = 1;
|
s_insim_tcp.state = 1;
|
||||||
s_insim_tcp.pos = 0;
|
s_insim_tcp.pos = 0;
|
||||||
s_insim_tcp.offset = 0;
|
s_insim_tcp.offset = 0;
|
||||||
register_socket(fd, SM_READ | SM_WRITE, &insim_recv, &s_insim_tcp);
|
register_socket(fd, SM_READ | SM_WRITE, &insim_recv, &s_insim_tcp);
|
||||||
|
|
||||||
fd = network_listen(g_insim_port + 1, 0);
|
fd = network_listen(g_insim_port + 1, 0);
|
||||||
s_insim_udp.state = 2;
|
s_insim_udp.state = 2;
|
||||||
s_insim_udp.pos = 0;
|
s_insim_udp.pos = 0;
|
||||||
s_insim_udp.offset = 0;
|
s_insim_udp.offset = 0;
|
||||||
register_socket(fd, SM_READ, &insim_recv, &s_insim_udp);
|
register_socket(fd, SM_READ, &insim_recv, &s_insim_udp);
|
||||||
|
|
||||||
struct IS_ISI p;
|
struct IS_ISI p;
|
||||||
memset(&p, 0, sizeof p);
|
memset(&p, 0, sizeof p);
|
||||||
p.Size = sizeof p;
|
p.Size = sizeof p;
|
||||||
p.Type = ISP_ISI;
|
p.Type = ISP_ISI;
|
||||||
p.ReqI = 0;
|
p.ReqI = 0;
|
||||||
p.Zero = 0;
|
p.Zero = 0;
|
||||||
p.UDPPort = g_outgauge_port; //g_insim_port + 1;
|
p.UDPPort = g_outgauge_port; // g_insim_port + 1;
|
||||||
p.Flags = ISF_LOCAL;
|
p.Flags = ISF_LOCAL;
|
||||||
p.Sp0 = 0;
|
p.Sp0 = 0;
|
||||||
p.Prefix = 0;
|
p.Prefix = 0;
|
||||||
p.Interval = 100;
|
p.Interval = 100;
|
||||||
snprintf(p.Admin, sizeof p.Admin, "");
|
snprintf(p.Admin, sizeof p.Admin, "");
|
||||||
snprintf(p.IName, sizeof p.IName, "LFS Dashboard");
|
snprintf(p.IName, sizeof p.IName, "LFS Dashboard");
|
||||||
insim_queue(&p, sizeof p);
|
insim_queue(&p, sizeof p);
|
||||||
|
|
||||||
struct IS_SMALL s;
|
struct IS_SMALL s;
|
||||||
s.Size = sizeof s;
|
s.Size = sizeof s;
|
||||||
s.Type = ISP_SMALL;
|
s.Type = ISP_SMALL;
|
||||||
s.ReqI = 1;
|
s.ReqI = 1;
|
||||||
s.SubT = SMALL_SSG;
|
s.SubT = SMALL_SSG;
|
||||||
s.UVal = 1;
|
s.UVal = 1;
|
||||||
insim_queue(&s, sizeof s);
|
insim_queue(&s, sizeof s);
|
||||||
|
|
||||||
insim_request_info();
|
insim_request_info();
|
||||||
}
|
}
|
||||||
|
|
||||||
void insim_init(const char *hostname, int port)
|
void insim_init(const char *hostname, int port)
|
||||||
{
|
{
|
||||||
s_insim_tcp.state = 0;
|
s_insim_tcp.state = 0;
|
||||||
s_insim_udp.state = 0;
|
s_insim_udp.state = 0;
|
||||||
s_send_queue = queue_new();
|
s_send_queue = queue_new();
|
||||||
network_connect(hostname, port, &insim_connect, NULL);
|
network_connect(hostname, port, &insim_connect, NULL);
|
||||||
}
|
}
|
||||||
|
|
132
list.h
132
list.h
|
@ -3,70 +3,72 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define LIST(X, T, compare_func) \
|
#define LIST(X, T, compare_func) \
|
||||||
struct X ## _list_t \
|
struct X##_list_t \
|
||||||
{ \
|
{ \
|
||||||
size_t used; \
|
size_t used; \
|
||||||
size_t size; \
|
size_t size; \
|
||||||
T *items; \
|
T *items; \
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
static inline void X ## _list_init(struct X ## _list_t *list) \
|
static inline void X##_list_init(struct X##_list_t *list) \
|
||||||
{ \
|
{ \
|
||||||
list->used = 0; \
|
list->used = 0; \
|
||||||
list->size = 0; \
|
list->size = 0; \
|
||||||
list->items = NULL; \
|
list->items = NULL; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static inline void X ## _list_free(struct X ## _list_t *list) \
|
static inline void X##_list_free(struct X##_list_t *list) \
|
||||||
{ \
|
{ \
|
||||||
free(list->items); \
|
free(list->items); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static inline void X ## _list_add(struct X ## _list_t *list, T item) \
|
static inline void X##_list_add(struct X##_list_t *list, T item) \
|
||||||
{ \
|
{ \
|
||||||
if (list->used >= list->size) \
|
if (list->used >= list->size) \
|
||||||
{ \
|
{ \
|
||||||
list->size += 64U; \
|
list->size += 64U; \
|
||||||
T *new_items = realloc(list->items, sizeof *list->items * list->size); \
|
T *new_items = realloc(list->items, sizeof *list->items * list->size); \
|
||||||
if (new_items == NULL) \
|
if (new_items == NULL) \
|
||||||
{ \
|
{ \
|
||||||
fprintf(stderr, "Reallocating %s list to %u items (%u bytes) failed\n", #X, (unsigned)list->size, (unsigned)(sizeof *list->items * list->size)); \
|
fprintf(stderr, "Reallocating %s list to %u items (%u bytes) failed\n", #X, (unsigned)list->size, (unsigned)(sizeof *list->items * list->size)); \
|
||||||
list->size -= 64U; \
|
list->size -= 64U; \
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
list->items = new_items; \
|
list->items = new_items; \
|
||||||
} \
|
} \
|
||||||
list->items[list->used++] = item; \
|
list->items[list->used++] = item; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static inline void X ## _list_del_item(struct X ## _list_t *list, T item) \
|
static inline void X##_list_del_item(struct X##_list_t *list, T item) \
|
||||||
{ \
|
{ \
|
||||||
size_t i; \
|
size_t i; \
|
||||||
for (i = 0; i < list->used; i++) \
|
for (i = 0; i < list->used; i++) \
|
||||||
{ \
|
{ \
|
||||||
if (compare_func(&list->items[i], &item)) { \
|
if (compare_func(&list->items[i], &item)) \
|
||||||
list->items[i] = list->items[--list->used]; \
|
{ \
|
||||||
return; \
|
list->items[i] = list->items[--list->used]; \
|
||||||
} \
|
return; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
\
|
} \
|
||||||
static inline void X ## _list_del_index(struct X ## _list_t *list, size_t index) \
|
\
|
||||||
{ \
|
static inline void X##_list_del_index(struct X##_list_t *list, size_t index) \
|
||||||
list->items[index] = list->items[--list->used]; \
|
{ \
|
||||||
} \
|
list->items[index] = list->items[--list->used]; \
|
||||||
\
|
} \
|
||||||
static inline int X ## _list_contains(struct X ## _list_t *list, T item) \
|
\
|
||||||
{ \
|
static inline int X##_list_contains(struct X##_list_t *list, T item) \
|
||||||
size_t i; \
|
{ \
|
||||||
for (i = 0; i < list->used; i++) \
|
size_t i; \
|
||||||
{ \
|
for (i = 0; i < list->used; i++) \
|
||||||
if (compare_func(&list->items[i], &item)) { \
|
{ \
|
||||||
return 1; \
|
if (compare_func(&list->items[i], &item)) \
|
||||||
} \
|
{ \
|
||||||
} \
|
return 1; \
|
||||||
return 0; \
|
} \
|
||||||
}
|
} \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* LIST_H */
|
#endif /* LIST_H */
|
||||||
|
|
229
network_worker.c
229
network_worker.c
|
@ -14,7 +14,7 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
//#include "network.h"
|
// #include "network.h"
|
||||||
#include "network_worker.h"
|
#include "network_worker.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "worker.h"
|
#include "worker.h"
|
||||||
|
@ -23,124 +23,124 @@ static struct worker s_network_worker;
|
||||||
|
|
||||||
struct network_job
|
struct network_job
|
||||||
{
|
{
|
||||||
char *host;
|
char *host;
|
||||||
int port;
|
int port;
|
||||||
network_callback callback;
|
network_callback callback;
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
int resolve(const char *hostname, int port, struct sockaddr_in *addr)
|
int resolve(const char *hostname, int port, struct sockaddr_in *addr)
|
||||||
{
|
{
|
||||||
struct addrinfo *ai;
|
struct addrinfo *ai;
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
memset(&hints, 0, sizeof hints);
|
memset(&hints, 0, sizeof hints);
|
||||||
hints.ai_family = AF_INET;
|
hints.ai_family = AF_INET;
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
hints.ai_flags = AI_ADDRCONFIG;
|
hints.ai_flags = AI_ADDRCONFIG;
|
||||||
#endif
|
#endif
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
char port_name[6];
|
char port_name[6];
|
||||||
snprintf(port_name, sizeof port_name, "%u", port);
|
snprintf(port_name, sizeof port_name, "%u", port);
|
||||||
|
|
||||||
int e = getaddrinfo(hostname, port_name, &hints, &ai);
|
int e = getaddrinfo(hostname, port_name, &hints, &ai);
|
||||||
|
|
||||||
if (e != 0)
|
if (e != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "getaddrinfo: %s\n", strerror(errno));
|
fprintf(stderr, "getaddrinfo: %s\n", strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct addrinfo *runp;
|
struct addrinfo *runp;
|
||||||
for (runp = ai; runp != NULL; runp = runp->ai_next)
|
for (runp = ai; runp != NULL; runp = runp->ai_next)
|
||||||
{
|
{
|
||||||
struct sockaddr_in *ai_addr = (struct sockaddr_in *)runp->ai_addr;
|
struct sockaddr_in *ai_addr = (struct sockaddr_in *)runp->ai_addr;
|
||||||
|
|
||||||
/* Take the first address */
|
/* Take the first address */
|
||||||
*addr = *ai_addr;
|
*addr = *ai_addr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void network_worker(void *arg)
|
static void network_worker(void *arg)
|
||||||
{
|
{
|
||||||
struct network_job *job = arg;
|
struct network_job *job = arg;
|
||||||
|
|
||||||
if (job->callback != NULL)
|
if (job->callback != NULL)
|
||||||
{
|
{
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
if (!resolve(job->host, job->port, &addr))
|
if (!resolve(job->host, job->port, &addr))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Unable to resolve %s:%d\n", job->host, job->port);
|
fprintf(stderr, "Unable to resolve %s:%d\n", job->host, job->port);
|
||||||
if (job->callback != NULL)
|
if (job->callback != NULL)
|
||||||
{
|
{
|
||||||
job->callback(-1, job->data);
|
job->callback(-1, job->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (job->callback != NULL)
|
else if (job->callback != NULL)
|
||||||
{
|
{
|
||||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
fprintf(stderr, "socket: %d\n", WSAGetLastError());
|
fprintf(stderr, "socket: %d\n", WSAGetLastError());
|
||||||
#else
|
#else
|
||||||
fprintf(stderr, "socket: %s\n", strerror(errno));
|
fprintf(stderr, "socket: %s\n", strerror(errno));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
socket_set_nonblock(fd);
|
socket_set_nonblock(fd);
|
||||||
socket_set_nodelay(fd);
|
socket_set_nodelay(fd);
|
||||||
if (connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0)
|
if (connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
|
if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "connect: %d\n", WSAGetLastError());
|
fprintf(stderr, "connect: %d\n", WSAGetLastError());
|
||||||
fd = -1;
|
fd = -1;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (errno != EINPROGRESS && errno != EWOULDBLOCK)
|
if (errno != EINPROGRESS && errno != EWOULDBLOCK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "connect: %s\n", strerror(errno));
|
fprintf(stderr, "connect: %s\n", strerror(errno));
|
||||||
fd = -1;
|
fd = -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
job->callback(fd, job->data);
|
job->callback(fd, job->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(job->host);
|
free(job->host);
|
||||||
free(job);
|
free(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_worker_init(void)
|
void network_worker_init(void)
|
||||||
{
|
{
|
||||||
worker_init(&s_network_worker, "network", 60000, 1, network_worker);
|
worker_init(&s_network_worker, "network", 60000, 1, network_worker);
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_worker_deinit(void)
|
void network_worker_deinit(void)
|
||||||
{
|
{
|
||||||
worker_deinit(&s_network_worker);
|
worker_deinit(&s_network_worker);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *network_connect(const char *host, int port, network_callback callback, void *data)
|
void *network_connect(const char *host, int port, network_callback callback, void *data)
|
||||||
{
|
{
|
||||||
struct network_job *job = malloc(sizeof *job);
|
struct network_job *job = malloc(sizeof *job);
|
||||||
job->host = strdup(host);
|
job->host = strdup(host);
|
||||||
job->port = port;
|
job->port = port;
|
||||||
job->callback = callback;
|
job->callback = callback;
|
||||||
job->data = data;
|
job->data = data;
|
||||||
|
|
||||||
worker_queue(&s_network_worker, job);
|
worker_queue(&s_network_worker, job);
|
||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
int network_listen(int port, int tcp)
|
int network_listen(int port, int tcp)
|
||||||
|
@ -153,42 +153,43 @@ int network_listen(int port, int tcp)
|
||||||
fd = socket(AF_INET, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
|
fd = socket(AF_INET, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
fprintf(stderr, "socket: %d\n", WSAGetLastError());
|
fprintf(stderr, "socket: %d\n", WSAGetLastError());
|
||||||
#else
|
#else
|
||||||
fprintf(stderr, "socket: %s\n", strerror(errno));
|
fprintf(stderr, "socket: %s\n", strerror(errno));
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_IPV6
|
#ifdef USE_IPV6
|
||||||
struct sockaddr_in6 serv_addr;
|
struct sockaddr_in6 serv_addr;
|
||||||
serv_addr.sin6_family = AF_INET6;
|
serv_addr.sin6_family = AF_INET6;
|
||||||
serv_addr.sin6_addr = in6addr_any;
|
serv_addr.sin6_addr = in6addr_any;
|
||||||
serv_addr.sin6_port = htons(port);
|
serv_addr.sin6_port = htons(port);
|
||||||
#else
|
#else
|
||||||
struct sockaddr_in serv_addr;
|
struct sockaddr_in serv_addr;
|
||||||
serv_addr.sin_family = AF_INET;
|
serv_addr.sin_family = AF_INET;
|
||||||
serv_addr.sin_addr.s_addr = INADDR_ANY;
|
serv_addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
serv_addr.sin_port = htons(port);
|
serv_addr.sin_port = htons(port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int on = 1;
|
int on = 1;
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof on) == -1)
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof on) == -1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "setsockopt: Could not set SO_REUSEADDR: %s\n", strerror(errno));
|
fprintf(stderr, "setsockopt: Could not set SO_REUSEADDR: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(fd, (struct sockaddr *)&serv_addr, sizeof serv_addr) < 0)
|
if (bind(fd, (struct sockaddr *)&serv_addr, sizeof serv_addr) < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "bind: %s\n", strerror(errno));
|
fprintf(stderr, "bind: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_set_nonblock(fd);
|
socket_set_nonblock(fd);
|
||||||
if (tcp) socket_set_nodelay(fd);
|
if (tcp)
|
||||||
|
socket_set_nodelay(fd);
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
78
outgauge.c
78
outgauge.c
|
@ -1,8 +1,8 @@
|
||||||
//#define USE_IPV6
|
// #define USE_IPV6
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
//#include <ws2tcpip.h>
|
// #include <ws2tcpip.h>
|
||||||
#else
|
#else
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
@ -31,52 +31,55 @@ float g_consumption;
|
||||||
|
|
||||||
int outgauge_recv(int fd, int can_write, int can_read, void *arg)
|
int outgauge_recv(int fd, int can_write, int can_read, void *arg)
|
||||||
{
|
{
|
||||||
if (can_read)
|
if (can_read)
|
||||||
{
|
{
|
||||||
struct outgauge o;
|
struct outgauge o;
|
||||||
ssize_t len = recv(fd, (char *)&o, sizeof o, 0);
|
ssize_t len = recv(fd, (char *)&o, sizeof o, 0);
|
||||||
|
|
||||||
/* Ignore out of order packet */
|
/* Ignore out of order packet */
|
||||||
//if (o.time < s_prev_time)
|
// if (o.time < s_prev_time)
|
||||||
|
|
||||||
if (o.rpm < 0) o.rpm = 0;
|
if (o.rpm < 0)
|
||||||
|
o.rpm = 0;
|
||||||
memcpy(&g_outgauge, &o, len);
|
memcpy(&g_outgauge, &o, len);
|
||||||
g_fade &= ~1;
|
g_fade &= ~1;
|
||||||
|
|
||||||
g_released |= g_pressed & (~(o.flags & 3));
|
g_released |= g_pressed & (~(o.flags & 3));
|
||||||
|
|
||||||
if (!(g_pressed & 1) && (o.flags & 1)) g_shift_time = o.time;
|
if (!(g_pressed & 1) && (o.flags & 1))
|
||||||
if (!(g_pressed & 2) && (o.flags & 2)) g_ctrl_time = o.time;
|
g_shift_time = o.time;
|
||||||
g_pressed |= (o.flags & 3);
|
if (!(g_pressed & 2) && (o.flags & 2))
|
||||||
|
g_ctrl_time = o.time;
|
||||||
|
g_pressed |= (o.flags & 3);
|
||||||
|
|
||||||
if (g_owncar != o.playerid)
|
if (g_owncar != o.playerid)
|
||||||
{
|
{
|
||||||
if (o.fuel > 0)
|
if (o.fuel > 0)
|
||||||
{
|
{
|
||||||
g_owncar = o.playerid;
|
g_owncar = o.playerid;
|
||||||
g_consumption = 0;
|
g_consumption = 0;
|
||||||
s_car = get_car(o.car, NULL);
|
s_car = get_car(o.car, NULL);
|
||||||
s_prev_fuel = o.fuel;
|
s_prev_fuel = o.fuel;
|
||||||
g_fade &= ~2;
|
g_fade &= ~2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_fade |= 2;
|
g_fade |= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_fade &= ~2;
|
g_fade &= ~2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_prev_time > 0)
|
if (s_prev_time > 0)
|
||||||
{
|
{
|
||||||
if (o.fuel > s_prev_fuel)
|
if (o.fuel > s_prev_fuel)
|
||||||
{
|
{
|
||||||
g_consumption = 0;
|
g_consumption = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float interval = (o.time - s_prev_time) * 0.001;
|
float interval = (o.time - s_prev_time) * 0.001;
|
||||||
if (interval > 0)
|
if (interval > 0)
|
||||||
{
|
{
|
||||||
|
@ -88,18 +91,19 @@ int outgauge_recv(int fd, int can_write, int can_read, void *arg)
|
||||||
update_car(s_car, o.speed * interval, interval, g_consumption);
|
update_car(s_car, o.speed * interval, interval, g_consumption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s_prev_time = o.time;
|
s_prev_time = o.time;
|
||||||
s_prev_fuel = o.fuel;
|
s_prev_fuel = o.fuel;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void outgauge_init(int port)
|
void outgauge_init(int port)
|
||||||
{
|
{
|
||||||
int fd = network_listen(port, 0);
|
int fd = network_listen(port, 0);
|
||||||
if (fd < 0) return;
|
if (fd < 0)
|
||||||
register_socket(fd, SM_READ, &outgauge_recv, NULL);
|
return;
|
||||||
|
register_socket(fd, SM_READ, &outgauge_recv, NULL);
|
||||||
}
|
}
|
||||||
|
|
41
outgauge.h
41
outgauge.h
|
@ -5,26 +5,26 @@
|
||||||
|
|
||||||
struct outgauge
|
struct outgauge
|
||||||
{
|
{
|
||||||
uint32_t time;
|
uint32_t time;
|
||||||
char car[4];
|
char car[4];
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
uint8_t gear;
|
uint8_t gear;
|
||||||
uint8_t playerid;
|
uint8_t playerid;
|
||||||
float speed;
|
float speed;
|
||||||
float rpm;
|
float rpm;
|
||||||
float turbo;
|
float turbo;
|
||||||
float enginetemp;
|
float enginetemp;
|
||||||
float fuel;
|
float fuel;
|
||||||
float oilpressure;
|
float oilpressure;
|
||||||
float oiltemp;
|
float oiltemp;
|
||||||
uint32_t dashlights;
|
uint32_t dashlights;
|
||||||
uint32_t showlights;
|
uint32_t showlights;
|
||||||
float throttle;
|
float throttle;
|
||||||
float brake;
|
float brake;
|
||||||
float clutch;
|
float clutch;
|
||||||
char display1[16];
|
char display1[16];
|
||||||
char display2[16];
|
char display2[16];
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct outgauge g_outgauge;
|
extern struct outgauge g_outgauge;
|
||||||
|
@ -37,7 +37,6 @@ extern int g_released;
|
||||||
extern uint32_t g_shift_time;
|
extern uint32_t g_shift_time;
|
||||||
extern uint32_t g_ctrl_time;
|
extern uint32_t g_ctrl_time;
|
||||||
|
|
||||||
|
|
||||||
void outgauge_init(int port);
|
void outgauge_init(int port);
|
||||||
|
|
||||||
#endif /* OUTGAUGE_H */
|
#endif /* OUTGAUGE_H */
|
||||||
|
|
119
queue.c
119
queue.c
|
@ -4,95 +4,96 @@
|
||||||
|
|
||||||
struct queue_object_t
|
struct queue_object_t
|
||||||
{
|
{
|
||||||
struct queue_object_t *next;
|
struct queue_object_t *next;
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct queue_t
|
struct queue_t
|
||||||
{
|
{
|
||||||
pthread_mutex_t produce_mutex;
|
pthread_mutex_t produce_mutex;
|
||||||
pthread_mutex_t consume_mutex;
|
pthread_mutex_t consume_mutex;
|
||||||
struct queue_object_t *head;
|
struct queue_object_t *head;
|
||||||
struct queue_object_t *tail;
|
struct queue_object_t *tail;
|
||||||
struct queue_object_t *divider;
|
struct queue_object_t *divider;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct queue_t *queue_new(void)
|
struct queue_t *queue_new(void)
|
||||||
{
|
{
|
||||||
struct queue_t *queue = malloc(sizeof *queue);
|
struct queue_t *queue = malloc(sizeof *queue);
|
||||||
struct queue_object_t *qo = malloc(sizeof *qo);
|
struct queue_object_t *qo = malloc(sizeof *qo);
|
||||||
qo->next = NULL;
|
qo->next = NULL;
|
||||||
qo->data = NULL;
|
qo->data = NULL;
|
||||||
|
|
||||||
queue->head = qo;
|
queue->head = qo;
|
||||||
queue->tail = qo;
|
queue->tail = qo;
|
||||||
queue->divider = qo;
|
queue->divider = qo;
|
||||||
|
|
||||||
pthread_mutex_init(&queue->produce_mutex, NULL);
|
pthread_mutex_init(&queue->produce_mutex, NULL);
|
||||||
pthread_mutex_init(&queue->consume_mutex, NULL);
|
pthread_mutex_init(&queue->consume_mutex, NULL);
|
||||||
|
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void queue_delete(struct queue_t *queue)
|
void queue_delete(struct queue_t *queue)
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while (queue->head != NULL)
|
while (queue->head != NULL)
|
||||||
{
|
{
|
||||||
struct queue_object_t *qo = queue->head;
|
struct queue_object_t *qo = queue->head;
|
||||||
queue->head = qo->next;
|
queue->head = qo->next;
|
||||||
|
|
||||||
//free(qo->data);
|
// free(qo->data);
|
||||||
free(qo);
|
free(qo);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_destroy(&queue->produce_mutex);
|
pthread_mutex_destroy(&queue->produce_mutex);
|
||||||
pthread_mutex_destroy(&queue->consume_mutex);
|
pthread_mutex_destroy(&queue->consume_mutex);
|
||||||
|
|
||||||
free(queue);
|
free(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
int queue_produce(struct queue_t *queue, void *data)
|
int queue_produce(struct queue_t *queue, void *data)
|
||||||
{
|
{
|
||||||
if (queue == NULL) return 0;
|
if (queue == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
struct queue_object_t *qo = malloc(sizeof *qo);
|
struct queue_object_t *qo = malloc(sizeof *qo);
|
||||||
qo->next = NULL;
|
qo->next = NULL;
|
||||||
qo->data = data;
|
qo->data = data;
|
||||||
|
|
||||||
/* Lock needed? */
|
/* Lock needed? */
|
||||||
pthread_mutex_lock(&queue->produce_mutex);
|
pthread_mutex_lock(&queue->produce_mutex);
|
||||||
queue->tail->next = qo;
|
queue->tail->next = qo;
|
||||||
queue->tail = qo;
|
queue->tail = qo;
|
||||||
/* */
|
/* */
|
||||||
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while (queue->head != queue->divider)
|
while (queue->head != queue->divider)
|
||||||
{
|
{
|
||||||
struct queue_object_t *qo = queue->head;
|
struct queue_object_t *qo = queue->head;
|
||||||
queue->head = qo->next;
|
queue->head = qo->next;
|
||||||
|
|
||||||
//free(qo->data);
|
// free(qo->data);
|
||||||
free(qo);
|
free(qo);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&queue->produce_mutex);
|
pthread_mutex_unlock(&queue->produce_mutex);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int queue_consume(struct queue_t *queue, void **data)
|
int queue_consume(struct queue_t *queue, void **data)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&queue->consume_mutex);
|
pthread_mutex_lock(&queue->consume_mutex);
|
||||||
if (queue->divider != queue->tail)
|
if (queue->divider != queue->tail)
|
||||||
{
|
{
|
||||||
*data = queue->divider->next->data;
|
*data = queue->divider->next->data;
|
||||||
queue->divider = queue->divider->next;
|
queue->divider = queue->divider->next;
|
||||||
pthread_mutex_unlock(&queue->consume_mutex);
|
pthread_mutex_unlock(&queue->consume_mutex);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&queue->consume_mutex);
|
pthread_mutex_unlock(&queue->consume_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
218
socket.c
218
socket.c
|
@ -1,5 +1,5 @@
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
//#define USE_POLL
|
// #define USE_POLL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -28,15 +28,15 @@ int s_running;
|
||||||
|
|
||||||
struct socket_t
|
struct socket_t
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
int mode;
|
int mode;
|
||||||
socket_func socket_func;
|
socket_func socket_func;
|
||||||
void *arg;
|
void *arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int socket_compare(struct socket_t **a, struct socket_t **b)
|
static inline int socket_compare(struct socket_t **a, struct socket_t **b)
|
||||||
{
|
{
|
||||||
return (*a)->fd == (*b)->fd;
|
return (*a)->fd == (*b)->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST(socket, struct socket_t *, socket_compare)
|
LIST(socket, struct socket_t *, socket_compare)
|
||||||
|
@ -50,99 +50,105 @@ static int s_epoll_fd = -1;
|
||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
static struct socket_t *socket_get_by_fd(int fd)
|
static struct socket_t *socket_get_by_fd(int fd)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < s_sockets.used; i++)
|
for (i = 0; i < s_sockets.used; i++)
|
||||||
{
|
{
|
||||||
struct socket_t *s = s_sockets.items[i];
|
struct socket_t *s = s_sockets.items[i];
|
||||||
if (s->fd == fd) return s;
|
if (s->fd == fd)
|
||||||
}
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void register_socket(int fd, int mode, socket_func socket_func, void *arg)
|
void register_socket(int fd, int mode, socket_func socket_func, void *arg)
|
||||||
{
|
{
|
||||||
struct socket_t *s = malloc(sizeof *s);
|
struct socket_t *s = malloc(sizeof *s);
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
s->mode = mode;
|
s->mode = mode;
|
||||||
s->socket_func = socket_func;
|
s->socket_func = socket_func;
|
||||||
s->arg = arg;
|
s->arg = arg;
|
||||||
|
|
||||||
pthread_mutex_lock(&s_sockets_mutex);
|
pthread_mutex_lock(&s_sockets_mutex);
|
||||||
socket_list_add(&s_sockets, s);
|
socket_list_add(&s_sockets, s);
|
||||||
|
|
||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
if (s_epoll_fd == -1)
|
if (s_epoll_fd == -1)
|
||||||
{
|
{
|
||||||
s_epoll_fd = epoll_create(32);
|
s_epoll_fd = epoll_create(32);
|
||||||
if (s_epoll_fd == -1) fprintf(stderr, "register_socket(): epoll_create: %s\n", strerror(errno));
|
if (s_epoll_fd == -1)
|
||||||
}
|
fprintf(stderr, "register_socket(): epoll_create: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
struct epoll_event ev;
|
struct epoll_event ev;
|
||||||
ev.events = EPOLLIN;
|
ev.events = EPOLLIN;
|
||||||
ev.data.ptr = s;
|
ev.data.ptr = s;
|
||||||
int r = epoll_ctl(s_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
|
int r = epoll_ctl(s_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
|
||||||
if (r == -1) fprintf(stderr, "register_socket(): epoll_ctl: %s\n", strerror(errno));
|
if (r == -1)
|
||||||
|
fprintf(stderr, "register_socket(): epoll_ctl: %s\n", strerror(errno));
|
||||||
#endif /* USE_POLL */
|
#endif /* USE_POLL */
|
||||||
|
|
||||||
pthread_mutex_unlock(&s_sockets_mutex);
|
pthread_mutex_unlock(&s_sockets_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_flag_write(int fd)
|
void socket_flag_write(int fd)
|
||||||
{
|
{
|
||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
struct epoll_event ev;
|
struct epoll_event ev;
|
||||||
ev.events = EPOLLIN | EPOLLOUT;
|
ev.events = EPOLLIN | EPOLLOUT;
|
||||||
ev.data.ptr = socket_get_by_fd(fd);;
|
ev.data.ptr = socket_get_by_fd(fd);
|
||||||
int r = epoll_ctl(s_epoll_fd, EPOLL_CTL_MOD, fd, &ev);
|
;
|
||||||
if (r == -1) fprintf(stderr, "socket_flag_write(): epoll_ctl: %s\n", strerror(errno));
|
int r = epoll_ctl(s_epoll_fd, EPOLL_CTL_MOD, fd, &ev);
|
||||||
|
if (r == -1)
|
||||||
|
fprintf(stderr, "socket_flag_write(): epoll_ctl: %s\n", strerror(errno));
|
||||||
#endif /* USE_POLL */
|
#endif /* USE_POLL */
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_clear_write(int fd)
|
void socket_clear_write(int fd)
|
||||||
{
|
{
|
||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
struct epoll_event ev;
|
struct epoll_event ev;
|
||||||
ev.events = EPOLLIN;
|
ev.events = EPOLLIN;
|
||||||
ev.data.ptr = socket_get_by_fd(fd);
|
ev.data.ptr = socket_get_by_fd(fd);
|
||||||
int r = epoll_ctl(s_epoll_fd, EPOLL_CTL_MOD, fd, &ev);
|
int r = epoll_ctl(s_epoll_fd, EPOLL_CTL_MOD, fd, &ev);
|
||||||
if (r == -1) fprintf(stderr, "socket_clear_write(): epoll_ctl: %s\n", strerror(errno));
|
if (r == -1)
|
||||||
|
fprintf(stderr, "socket_clear_write(): epoll_ctl: %s\n", strerror(errno));
|
||||||
#endif /* USE_POLL */
|
#endif /* USE_POLL */
|
||||||
}
|
}
|
||||||
|
|
||||||
void deregister_socket(int fd)
|
void deregister_socket(int fd)
|
||||||
{
|
{
|
||||||
struct socket_t s;
|
struct socket_t s;
|
||||||
s.fd = fd;
|
s.fd = fd;
|
||||||
|
|
||||||
pthread_mutex_lock(&s_sockets_mutex);
|
pthread_mutex_lock(&s_sockets_mutex);
|
||||||
socket_list_del_item(&s_sockets, &s);
|
socket_list_del_item(&s_sockets, &s);
|
||||||
pthread_mutex_unlock(&s_sockets_mutex);
|
pthread_mutex_unlock(&s_sockets_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_init(void)
|
void socket_init(void)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
WSADATA WSA_Data;
|
WSADATA WSA_Data;
|
||||||
WSAStartup (0x101, & WSA_Data);
|
WSAStartup(0x101, &WSA_Data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_mutex_init(&s_sockets_mutex, NULL);
|
pthread_mutex_init(&s_sockets_mutex, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_deinit(void)
|
void socket_deinit(void)
|
||||||
{
|
{
|
||||||
if (s_sockets.used > 0)
|
if (s_sockets.used > 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[network] socket_deinit(): %u sockets remaining in list\n", (unsigned)s_sockets.used);
|
fprintf(stderr, "[network] socket_deinit(): %u sockets remaining in list\n", (unsigned)s_sockets.used);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
close(s_epoll_fd);
|
close(s_epoll_fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
socket_list_free(&s_sockets);
|
socket_list_free(&s_sockets);
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_set_nonblock(int fd)
|
void socket_set_nonblock(int fd)
|
||||||
|
@ -151,23 +157,23 @@ void socket_set_nonblock(int fd)
|
||||||
u_long iMode = 1;
|
u_long iMode = 1;
|
||||||
ioctlsocket(fd, FIONBIO, &iMode);
|
ioctlsocket(fd, FIONBIO, &iMode);
|
||||||
#else
|
#else
|
||||||
int flags = fcntl(fd, F_GETFL, 0);
|
int flags = fcntl(fd, F_GETFL, 0);
|
||||||
int res = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
int res = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[network] socket_set_nonblocK(): Could not set nonblocking IO: %s\n", strerror(errno));
|
fprintf(stderr, "[network] socket_set_nonblocK(): Could not set nonblocking IO: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_set_nodelay(int fd)
|
void socket_set_nodelay(int fd)
|
||||||
{
|
{
|
||||||
int b = 1;
|
int b = 1;
|
||||||
int res = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&b, sizeof b);
|
int res = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&b, sizeof b);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[network] socket_set_nonblock(): Could not set TCP_NODELAY: %s\n", strerror(errno));
|
fprintf(stderr, "[network] socket_set_nonblock(): Could not set TCP_NODELAY: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
|
@ -176,26 +182,27 @@ void socket_set_nodelay(int fd)
|
||||||
|
|
||||||
void *socket_run(void *arg)
|
void *socket_run(void *arg)
|
||||||
{
|
{
|
||||||
s_running = 1;
|
s_running = 1;
|
||||||
|
|
||||||
while (s_running)
|
while (s_running)
|
||||||
{
|
{
|
||||||
struct epoll_event events[EPOLL_EVENTS];
|
struct epoll_event events[EPOLL_EVENTS];
|
||||||
int n = epoll_wait(s_epoll_fd, events, EPOLL_EVENTS, 10000);
|
int n = epoll_wait(s_epoll_fd, events, EPOLL_EVENTS, 10000);
|
||||||
if (n == -1) fprintf(stderr, "socket_run(): epoll_wait: %s\n", strerror(errno));
|
if (n == -1)
|
||||||
|
fprintf(stderr, "socket_run(): epoll_wait: %s\n", strerror(errno));
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
struct socket_t *s = events[i].data.ptr;
|
struct socket_t *s = events[i].data.ptr;
|
||||||
int state = s->socket_func(s->fd, !!(events[i].events & EPOLLOUT), !!(events[i].events & EPOLLIN), s->arg);
|
int state = s->socket_func(s->fd, !!(events[i].events & EPOLLOUT), !!(events[i].events & EPOLLIN), s->arg);
|
||||||
if (!state)
|
if (!state)
|
||||||
{
|
{
|
||||||
close(s->fd);
|
close(s->fd);
|
||||||
s->fd = -1;
|
s->fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* USE_POLL */
|
#else /* USE_POLL */
|
||||||
|
@ -204,8 +211,8 @@ void *socket_run(void *arg)
|
||||||
{
|
{
|
||||||
s_running = 1;
|
s_running = 1;
|
||||||
|
|
||||||
while (s_running)
|
while (s_running)
|
||||||
{
|
{
|
||||||
|
|
||||||
unsigned i;
|
unsigned i;
|
||||||
int n;
|
int n;
|
||||||
|
@ -219,11 +226,13 @@ void *socket_run(void *arg)
|
||||||
for (i = 0; i < s_sockets.used; i++)
|
for (i = 0; i < s_sockets.used; i++)
|
||||||
{
|
{
|
||||||
int fd = s_sockets.items[i]->fd;
|
int fd = s_sockets.items[i]->fd;
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
{
|
{
|
||||||
if (s_sockets.items[i]->mode & SM_READ ) FD_SET(fd, &read_fd);
|
if (s_sockets.items[i]->mode & SM_READ)
|
||||||
if (s_sockets.items[i]->mode & SM_WRITE) FD_SET(fd, &write_fd);
|
FD_SET(fd, &read_fd);
|
||||||
}
|
if (s_sockets.items[i]->mode & SM_WRITE)
|
||||||
|
FD_SET(fd, &write_fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tv.tv_sec = 10;
|
tv.tv_sec = 10;
|
||||||
|
@ -235,27 +244,28 @@ void *socket_run(void *arg)
|
||||||
fprintf(stderr, "select: %s\n", strerror(errno));
|
fprintf(stderr, "select: %s\n", strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (n == 0) continue;
|
if (n == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
for (i = 0; i < s_sockets.used; i++)
|
for (i = 0; i < s_sockets.used; i++)
|
||||||
{
|
{
|
||||||
struct socket_t *s = s_sockets.items[i];
|
struct socket_t *s = s_sockets.items[i];
|
||||||
int can_write = FD_ISSET(s->fd, &write_fd);
|
int can_write = FD_ISSET(s->fd, &write_fd);
|
||||||
int can_read = FD_ISSET(s->fd, &read_fd);
|
int can_read = FD_ISSET(s->fd, &read_fd);
|
||||||
|
|
||||||
if (can_write || can_read)
|
if (can_write || can_read)
|
||||||
{
|
{
|
||||||
int state = s->socket_func(s->fd, can_write, can_read, s->arg);
|
int state = s->socket_func(s->fd, can_write, can_read, s->arg);
|
||||||
if (!state)
|
if (!state)
|
||||||
{
|
{
|
||||||
close(s->fd);
|
close(s->fd);
|
||||||
s->fd = -1;
|
s->fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("Socket thread finished\n");
|
printf("Socket thread finished\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* USE_POLL */
|
#endif /* USE_POLL */
|
||||||
|
|
7
socket.h
7
socket.h
|
@ -3,12 +3,13 @@
|
||||||
|
|
||||||
extern int s_running;
|
extern int s_running;
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
SM_READ = 1,
|
{
|
||||||
|
SM_READ = 1,
|
||||||
SM_WRITE = 2,
|
SM_WRITE = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int(*socket_func)(int fd, int can_write, int can_read, void *arg);
|
typedef int (*socket_func)(int fd, int can_write, int can_read, void *arg);
|
||||||
|
|
||||||
void register_socket(int fd, int mode, socket_func socket_func, void *arg);
|
void register_socket(int fd, int mode, socket_func socket_func, void *arg);
|
||||||
void deregister_socket(int fd);
|
void deregister_socket(int fd);
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 140 KiB |
58
text.c
58
text.c
|
@ -1,32 +1,44 @@
|
||||||
#include <GL/glfw.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <FTGL/ftgl.h>
|
#include <FTGL/ftgl.h>
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
|
|
||||||
void drawText(const char *text, FTGLfont *font, float x, float y, float xs, float ys, int xa, int ya)
|
void drawText(const char *text, FTGLfont *font, float x, float y, float xs, float ys, int xa, int ya)
|
||||||
{
|
{
|
||||||
float bounds[6];
|
float bounds[6];
|
||||||
ftglGetFontBBox(font, text, -1, bounds);
|
ftglGetFontBBox(font, text, -1, bounds);
|
||||||
int cx = bounds[3] - bounds[0];
|
int cx = bounds[3] - bounds[0];
|
||||||
int cy = bounds[4] - bounds[1];
|
int cy = bounds[4] - bounds[1];
|
||||||
|
|
||||||
float ox = 0, oy = 0;
|
float ox = 0, oy = 0;
|
||||||
switch (xa)
|
switch (xa)
|
||||||
{
|
{
|
||||||
case TA_LEFT: ox = 0; break;
|
case TA_LEFT:
|
||||||
case TA_RIGHT: ox = -1; break;
|
ox = 0;
|
||||||
case TA_CENTRE: ox = -0.5; break;
|
break;
|
||||||
}
|
case TA_RIGHT:
|
||||||
switch (ya)
|
ox = -1;
|
||||||
{
|
break;
|
||||||
case TA_TOP: oy = -1; break;
|
case TA_CENTRE:
|
||||||
case TA_BOTTOM: oy = 0; break;
|
ox = -0.5;
|
||||||
case TA_CENTRE: oy = -0.5; break;
|
break;
|
||||||
}
|
}
|
||||||
|
switch (ya)
|
||||||
|
{
|
||||||
|
case TA_TOP:
|
||||||
|
oy = -1;
|
||||||
|
break;
|
||||||
|
case TA_BOTTOM:
|
||||||
|
oy = 0;
|
||||||
|
break;
|
||||||
|
case TA_CENTRE:
|
||||||
|
oy = -0.5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(x, y, 0.0f);
|
glTranslatef(x, y, 0.0f);
|
||||||
glScalef(xs / TEXT_SIZE, ys / TEXT_SIZE, 1.0f);
|
glScalef(xs / TEXT_SIZE, ys / TEXT_SIZE, 1.0f);
|
||||||
glTranslatef(cx * ox, cy * oy, 0.0f);
|
glTranslatef(cx * ox, cy * oy, 0.0f);
|
||||||
ftglRenderFont(font, text, FTGL_RENDER_ALL);
|
ftglRenderFont(font, text, FTGL_RENDER_ALL);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
3
text.h
3
text.h
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#define TEXT_SIZE 64
|
#define TEXT_SIZE 64
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
TA_LEFT,
|
TA_LEFT,
|
||||||
TA_RIGHT,
|
TA_RIGHT,
|
||||||
TA_TOP,
|
TA_TOP,
|
||||||
|
|
100
timer.c
100
timer.c
|
@ -7,17 +7,17 @@
|
||||||
|
|
||||||
struct timer_t
|
struct timer_t
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
unsigned interval;
|
unsigned interval;
|
||||||
timer_func_t timer_func;
|
timer_func_t timer_func;
|
||||||
void *arg;
|
void *arg;
|
||||||
|
|
||||||
unsigned next_trigger;
|
unsigned next_trigger;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int timer_t_compare(struct timer_t **a, struct timer_t **b)
|
static inline int timer_t_compare(struct timer_t **a, struct timer_t **b)
|
||||||
{
|
{
|
||||||
return *a == *b;
|
return *a == *b;
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST(timer, struct timer_t *, timer_t_compare)
|
LIST(timer, struct timer_t *, timer_t_compare)
|
||||||
|
@ -26,76 +26,76 @@ static pthread_mutex_t s_timers_mutex;
|
||||||
|
|
||||||
struct timer_t *register_timer(const char *name, unsigned interval, timer_func_t timer_func, void *arg, int wait)
|
struct timer_t *register_timer(const char *name, unsigned interval, timer_func_t timer_func, void *arg, int wait)
|
||||||
{
|
{
|
||||||
struct timer_t *t = malloc(sizeof *t);
|
struct timer_t *t = malloc(sizeof *t);
|
||||||
t->name = strdup(name);
|
t->name = strdup(name);
|
||||||
t->interval = interval;
|
t->interval = interval;
|
||||||
t->timer_func = timer_func;
|
t->timer_func = timer_func;
|
||||||
t->arg = arg;
|
t->arg = arg;
|
||||||
|
|
||||||
/* Make timer run on next tick */
|
/* Make timer run on next tick */
|
||||||
t->next_trigger = gettime() + (wait ? t->interval : 0);
|
t->next_trigger = gettime() + (wait ? t->interval : 0);
|
||||||
|
|
||||||
pthread_mutex_lock(&s_timers_mutex);
|
pthread_mutex_lock(&s_timers_mutex);
|
||||||
timer_list_add(&s_timers, t);
|
timer_list_add(&s_timers, t);
|
||||||
pthread_mutex_unlock(&s_timers_mutex);
|
pthread_mutex_unlock(&s_timers_mutex);
|
||||||
|
|
||||||
fprintf(stderr, "Registered %s timer with %u ms interval\n", name, interval);
|
fprintf(stderr, "Registered %s timer with %u ms interval\n", name, interval);
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deregister_timer(struct timer_t *t)
|
void deregister_timer(struct timer_t *t)
|
||||||
{
|
{
|
||||||
timer_list_del_item(&s_timers, t);
|
timer_list_del_item(&s_timers, t);
|
||||||
|
|
||||||
fprintf(stderr, "Deregistered %s timer\n", t->name);
|
fprintf(stderr, "Deregistered %s timer\n", t->name);
|
||||||
|
|
||||||
free(t->name);
|
free(t->name);
|
||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void timers_deinit(void)
|
void timers_deinit(void)
|
||||||
{
|
{
|
||||||
while (s_timers.used > 0)
|
while (s_timers.used > 0)
|
||||||
{
|
{
|
||||||
deregister_timer(s_timers.items[0]);
|
deregister_timer(s_timers.items[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
timer_list_free(&s_timers);
|
timer_list_free(&s_timers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_timers(unsigned tick)
|
void process_timers(unsigned tick)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for (i = 0; i < s_timers.used; i++)
|
for (i = 0; i < s_timers.used; i++)
|
||||||
{
|
{
|
||||||
struct timer_t *t = s_timers.items[i];
|
struct timer_t *t = s_timers.items[i];
|
||||||
if (tick >= t->next_trigger)
|
if (tick >= t->next_trigger)
|
||||||
{
|
{
|
||||||
t->next_trigger = tick + t->interval;
|
t->next_trigger = tick + t->interval;
|
||||||
t->timer_func(t->arg);
|
t->timer_func(t->arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer_set_interval(struct timer_t *t, unsigned interval)
|
void timer_set_interval(struct timer_t *t, unsigned interval)
|
||||||
{
|
{
|
||||||
/* Adjust next triggering */
|
/* Adjust next triggering */
|
||||||
t->next_trigger += (interval - t->interval);
|
t->next_trigger += (interval - t->interval);
|
||||||
t->interval = interval;
|
t->interval = interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer_set_interval_by_name(const char *name, unsigned interval)
|
void timer_set_interval_by_name(const char *name, unsigned interval)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
for (i = 0; i < s_timers.used; i++)
|
for (i = 0; i < s_timers.used; i++)
|
||||||
{
|
{
|
||||||
struct timer_t *t = s_timers.items[i];
|
struct timer_t *t = s_timers.items[i];
|
||||||
if (strcmp(t->name, name) == 0)
|
if (strcmp(t->name, name) == 0)
|
||||||
{
|
{
|
||||||
timer_set_interval(t, interval);
|
timer_set_interval(t, interval);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
timer.h
2
timer.h
|
@ -1,7 +1,7 @@
|
||||||
#ifndef TIMER_H
|
#ifndef TIMER_H
|
||||||
#define TIMER_H
|
#define TIMER_H
|
||||||
|
|
||||||
typedef void(*timer_func_t)(void *arg);
|
typedef void (*timer_func_t)(void *arg);
|
||||||
|
|
||||||
struct timer_t;
|
struct timer_t;
|
||||||
|
|
||||||
|
|
174
worker.c
174
worker.c
|
@ -1,133 +1,133 @@
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
//#include <windows.h>
|
// #include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
//#include <sys/syscall.h>
|
// #include <sys/syscall.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
#include "worker.h"
|
#include "worker.h"
|
||||||
//#include "mcc.h"
|
// #include "mcc.h"
|
||||||
#include "gettime.h"
|
#include "gettime.h"
|
||||||
|
|
||||||
void *worker_thread(void *arg)
|
void *worker_thread(void *arg)
|
||||||
{
|
{
|
||||||
struct worker *worker = arg;
|
struct worker *worker = arg;
|
||||||
|
|
||||||
bool timeout = false;
|
bool timeout = false;
|
||||||
int jobs = 0;
|
int jobs = 0;
|
||||||
//pid_t tid = (pid_t)syscall(SYS_gettid);
|
// pid_t tid = (pid_t)syscall(SYS_gettid);
|
||||||
unsigned tid = 0;
|
unsigned tid = 0;
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
nice(worker->nice);
|
nice(worker->nice);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fprintf(stderr, "Queue worker %s thread (%u) started with nice %d\n", worker->name, tid, worker->nice);
|
fprintf(stderr, "Queue worker %s thread (%u) started with nice %d\n", worker->name, tid, worker->nice);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
clock_gettime(CLOCK_REALTIME, &ts);
|
clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
ts.tv_sec += worker->timeout;
|
ts.tv_sec += worker->timeout;
|
||||||
|
|
||||||
int s = sem_timedwait(&worker->sem, &ts);
|
int s = sem_timedwait(&worker->sem, &ts);
|
||||||
if (s == -1)
|
if (s == -1)
|
||||||
{
|
{
|
||||||
worker->thread_timeout = true;
|
worker->thread_timeout = true;
|
||||||
if (errno == ETIMEDOUT) {
|
if (errno == ETIMEDOUT)
|
||||||
timeout = true;
|
{
|
||||||
break;
|
timeout = true;
|
||||||
}
|
break;
|
||||||
fprintf(stderr, "Queue worker %s thread (%u): %s\n", worker->name, tid, strerror(errno));
|
}
|
||||||
break;
|
fprintf(stderr, "Queue worker %s thread (%u): %s\n", worker->name, tid, strerror(errno));
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
void *data;
|
void *data;
|
||||||
if (queue_consume(worker->queue, &data))
|
if (queue_consume(worker->queue, &data))
|
||||||
{
|
{
|
||||||
/* Null item added to the queue indicate we should exit. */
|
/* Null item added to the queue indicate we should exit. */
|
||||||
if (data == NULL) break;
|
if (data == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
worker->callback(data);
|
worker->callback(data);
|
||||||
jobs++;
|
jobs++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout)
|
if (timeout)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Queue worker %s thread (%u) exiting after %d jobs due to timeout\n", worker->name, tid, jobs);
|
fprintf(stderr, "Queue worker %s thread (%u) exiting after %d jobs due to timeout\n", worker->name, tid, jobs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Queue worker %s thread (%u) exiting after %d jobs\n", worker->name, tid, jobs);
|
fprintf(stderr, "Queue worker %s thread (%u) exiting after %d jobs\n", worker->name, tid, jobs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void worker_init(struct worker *worker, const char *name, unsigned timeout, int nice, worker_callback callback)
|
void worker_init(struct worker *worker, const char *name, unsigned timeout, int nice, worker_callback callback)
|
||||||
{
|
{
|
||||||
memset(worker, 0, sizeof *worker);
|
memset(worker, 0, sizeof *worker);
|
||||||
|
|
||||||
strncpy(worker->name, name, sizeof worker->name);
|
strncpy(worker->name, name, sizeof worker->name);
|
||||||
worker->thread_valid = false;
|
worker->thread_valid = false;
|
||||||
worker->thread_timeout = false;
|
worker->thread_timeout = false;
|
||||||
worker->timeout = timeout / 1000;
|
worker->timeout = timeout / 1000;
|
||||||
worker->nice = nice;
|
worker->nice = nice;
|
||||||
|
|
||||||
worker->queue = queue_new();
|
worker->queue = queue_new();
|
||||||
worker->callback = callback;
|
worker->callback = callback;
|
||||||
sem_init(&worker->sem, 0, 0);
|
sem_init(&worker->sem, 0, 0);
|
||||||
|
|
||||||
fprintf(stderr, "Queue worker %s initialised\n", worker->name);
|
fprintf(stderr, "Queue worker %s initialised\n", worker->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void worker_deinit(struct worker *worker)
|
void worker_deinit(struct worker *worker)
|
||||||
{
|
{
|
||||||
if (worker->thread_valid)
|
if (worker->thread_valid)
|
||||||
{
|
{
|
||||||
if (!worker->thread_timeout)
|
if (!worker->thread_timeout)
|
||||||
{
|
{
|
||||||
if (queue_produce(worker->queue, NULL))
|
if (queue_produce(worker->queue, NULL))
|
||||||
{
|
{
|
||||||
sem_post(&worker->sem);
|
sem_post(&worker->sem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_join(worker->thread, NULL);
|
pthread_join(worker->thread, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_delete(worker->queue);
|
queue_delete(worker->queue);
|
||||||
|
|
||||||
fprintf(stderr, "Queue worker %s deinitialised\n", worker->name);
|
fprintf(stderr, "Queue worker %s deinitialised\n", worker->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void worker_queue(struct worker *worker, void *data)
|
void worker_queue(struct worker *worker, void *data)
|
||||||
{
|
{
|
||||||
if (worker->thread_timeout)
|
if (worker->thread_timeout)
|
||||||
{
|
{
|
||||||
pthread_join(worker->thread, NULL);
|
pthread_join(worker->thread, NULL);
|
||||||
worker->thread_timeout = false;
|
worker->thread_timeout = false;
|
||||||
worker->thread_valid = false;
|
worker->thread_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!worker->thread_valid)
|
if (!worker->thread_valid)
|
||||||
{
|
{
|
||||||
worker->thread_valid = (pthread_create(&worker->thread, NULL, &worker_thread, worker) == 0);
|
worker->thread_valid = (pthread_create(&worker->thread, NULL, &worker_thread, worker) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queue_produce(worker->queue, data))
|
if (queue_produce(worker->queue, data))
|
||||||
{
|
{
|
||||||
sem_post(&worker->sem);
|
sem_post(&worker->sem);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Queue worker %s unable to queue\n", worker->name);
|
fprintf(stderr, "Queue worker %s unable to queue\n", worker->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
22
worker.h
22
worker.h
|
@ -4,24 +4,24 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
|
|
||||||
typedef void(*worker_callback)(void *arg);
|
typedef void (*worker_callback)(void *arg);
|
||||||
|
|
||||||
struct worker
|
struct worker
|
||||||
{
|
{
|
||||||
char name[16];
|
char name[16];
|
||||||
int thread_valid;
|
int thread_valid;
|
||||||
int thread_timeout;
|
int thread_timeout;
|
||||||
unsigned timeout;
|
unsigned timeout;
|
||||||
int nice;
|
int nice;
|
||||||
|
|
||||||
struct queue_t *queue;
|
struct queue_t *queue;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
worker_callback callback;
|
worker_callback callback;
|
||||||
sem_t sem;
|
sem_t sem;
|
||||||
};
|
};
|
||||||
|
|
||||||
void worker_init(struct worker *worker, const char *name, unsigned timeout, int nice, worker_callback callback);
|
void worker_init(struct worker *worker, const char *name, unsigned timeout, int nice, worker_callback callback);
|
||||||
void worker_deinit(struct worker *worker);
|
void worker_deinit(struct worker *worker);
|
||||||
void worker_queue(struct worker* worker, void *data);
|
void worker_queue(struct worker *worker, void *data);
|
||||||
|
|
||||||
#endif /* WORKER_H */
|
#endif /* WORKER_H */
|
||||||
|
|
Loading…
Reference in New Issue