Browse Source

Initial commit

master
Peter Nelson 7 years ago
commit
9192d614d2
  1. 21
      Makefile
  2. 200
      audio.c
  3. 17
      audio.h
  4. BIN
      bing.wav
  5. BIN
      bip.wav
  6. BIN
      bop.wav
  7. 119
      cars.c
  8. 31
      cars.h
  9. 45
      cars.txt
  10. 182
      config.c
  11. 15
      config.h
  12. 237
      gauge.c
  13. 73
      gauge.h
  14. 13
      gauges.txt
  15. 81
      gettime.h
  16. 439
      insim.c
  17. 2237
      insim.h
  18. 994
      lfsdash.c
  19. 72
      list.h
  20. 194
      network_worker.c
  21. 12
      network_worker.h
  22. BIN
      off.wav
  23. BIN
      on.wav
  24. 105
      outgauge.c
  25. 43
      outgauge.h
  26. 98
      queue.c
  27. 11
      queue.h
  28. 261
      socket.c
  29. 26
      socket.h
  30. BIN
      symbols512.tga
  31. 32
      text.c
  32. 16
      text.h
  33. 101
      timer.c
  34. 15
      timer.h
  35. 133
      worker.c
  36. 27
      worker.h

21
Makefile

@ -0,0 +1,21 @@
SRCS := lfsdash.c
SRCS += audio.c
SRCS += cars.c
SRCS += config.c
SRCS += gauge.c
SRCS += insim.c
SRCS += network_worker.c
SRCS += outgauge.c
SRCS += queue.c
SRCS += socket.c
SRCS += text.c
SRCS += timer.c
SRCS += worker.c
OBJS := $(SRCS:.c=.o)
CFLAGS += `pkg-config libglfw ftgl openal --cflags` -g
LDFLAGS += `pkg-config libglfw ftgl openal --libs` -g
lfsdash: $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) -o $@

200
audio.c

@ -0,0 +1,200 @@
#include <stdio.h>
#include <stdlib.h>
//#include <GL/glut.h>
#include <AL/al.h>
#include <AL/alc.h>
#include <string.h>
#include <stdint.h>
#include "audio.h"
#define NUM_BUFFERS 5
#define NUM_SOURCES 6
#define NUM_ENVIRONMENTS 1
ALCdevice *dev;
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.
ALfloat listenerPos[]={0.0,0.0,4.0};
ALfloat listenerVel[]={0.0,0.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.
ALfloat source0Pos[]={ -2.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.
ALuint buffer[NUM_BUFFERS];
ALuint source[NUM_SOURCES];
ALuint environment[NUM_ENVIRONMENTS];
int file_read_int32_le(char *buffer, FILE *file)
{
int r = fread(buffer, sizeof(char), 4, file);
uint32_t ret = (uint8_t)buffer[0];
ret |= (uint8_t)buffer[1] << 8;
ret |= (uint8_t)buffer[2] << 16;
ret |= (uint8_t)buffer[3] << 24;
return ret;
}
int file_read_int16_le(char *buffer, FILE *file)
{
int r = fread(buffer, sizeof(char), 2, file);
uint16_t ret = (uint8_t)buffer[0];
ret |= (uint8_t)buffer[1] << 8;
return ret;
}
void file_ignore_bytes(FILE *file, int bytes)
{
fseek(file, bytes, SEEK_CUR);
}
void *file_allocate_and_read_bytes(FILE *file, size_t bytes)
{
void *buffer = malloc(bytes);
fread(buffer, 1, bytes, file);
return buffer;
}
static inline ALenum GetFormatFromInfo(short channels, short bitsPerSample) {
if (channels == 1)
return AL_FORMAT_MONO16;
return AL_FORMAT_STEREO16;
}
void audio_load(const char *filename, ALuint buffer)
{
FILE* file = fopen(filename, "rb");
char xbuffer[5];
memset(xbuffer, 0, sizeof xbuffer);
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "RIFF") != 0)
printf("Not a WAV file: %s\n", xbuffer);
file_read_int32_le(xbuffer, file);
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "WAVE") != 0)
printf("Not a WAV file: %s\n", xbuffer);
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "fmt ") != 0)
printf("Invalid WAV file: %s\n", xbuffer);
int size = file_read_int32_le(xbuffer, file);
short audioFormat = file_read_int16_le(xbuffer, file);
short channels = file_read_int16_le(xbuffer, file);
int sampleRate = file_read_int32_le(xbuffer, file);
int byteRate = file_read_int32_le(xbuffer, file);
file_read_int16_le(xbuffer, file);
short bitsPerSample = file_read_int16_le(xbuffer, file);
size -= 16;
file_ignore_bytes(file, size);
if (fread(xbuffer, sizeof(char), 4, file) != 4 || strcmp(xbuffer, "data") != 0)
printf("Invalid WAV file: %s\n", xbuffer);
int dataChunkSize = file_read_int32_le(xbuffer, file);
unsigned char* bufferData = file_allocate_and_read_bytes(file, (size_t) dataChunkSize);
float duration = (float)(dataChunkSize) / byteRate;
alBufferData(buffer, GetFormatFromInfo(channels, bitsPerSample), bufferData, dataChunkSize, sampleRate);
free(bufferData);
fclose(file);
}
void audio_init(void)
{
dev = alcOpenDevice(NULL);
if (!dev)
{
fprintf(stderr, "Oops\n");
return;
}
ctx = alcCreateContext(dev, NULL);
alcMakeContextCurrent(ctx);
if (!ctx)
{
fprintf(stderr, "Oops2\n");
return;
}
alListenerfv(AL_POSITION,listenerPos);
alListenerfv(AL_VELOCITY,listenerVel);
alListenerfv(AL_ORIENTATION,listenerOri);
alGetError(); // clear any error messages
// Generate buffers, or else no sound will happen!
alGenBuffers(NUM_BUFFERS, buffer);
if (alGetError() != AL_NO_ERROR) {
printf("- Error creating buffers !!\n");
exit(1);
}
audio_load("off.wav", buffer[FX_OFF]);
audio_load("on.wav", buffer[FX_ON]);
audio_load("bing.wav", buffer[FX_BING]);
audio_load("bip.wav", buffer[FX_BIP]);
audio_load("bop.wav", buffer[FX_BOP]);
alGetError(); /* clear error */
alGenSources(NUM_SOURCES, source);
if (alGetError() != AL_NO_ERROR)
{
printf("- Error creating sources !!\n");
exit(2);
}
int ii;
for (ii = 0; ii < NUM_SOURCES; ii++)
{
alSourcef(source[ii], AL_PITCH, 1.0f);
alSourcef(source[ii], AL_GAIN, 1.0f);
alSourcefv(source[ii], AL_POSITION, source0Pos);
alSourcefv(source[ii], AL_VELOCITY, source0Vel);
//alSourcei(source[0], AL_BUFFER, buffer[0]);
alSourcei(source[ii], AL_LOOPING, AL_FALSE);
}
}
void audio_deinit(void)
{
int ii;
for (ii = 0; ii < NUM_SOURCES; ii++)
{
alSourceStop(source[ii]);
}
alDeleteSources(NUM_SOURCES, source);
alDeleteBuffers(NUM_BUFFERS, buffer);
alcMakeContextCurrent(NULL);
alcDestroyContext(ctx);
alcCloseDevice(dev);
}
void audio_volume(float f)
{
int ii;
for (ii = 0; ii < NUM_SOURCES; ii++)
{
alSourcef(source[ii], AL_GAIN, f);
}
}
float frand(float mult)
{
return ((float)rand() / (float)RAND_MAX) * mult;
}
void audio_play(int s, int b)
{
alSourceStop(source[s]);
alSourcei(source[s], AL_BUFFER, buffer[b]);
alSourcePlay(source[s]);
}

17
audio.h

@ -0,0 +1,17 @@
#ifndef AUDIO_H
#define AUDIO_H
enum {
FX_ON,
FX_OFF,
FX_BING,
FX_BIP,
FX_BOP,
};
void audio_init(void);
void audio_deinit(void);
void audio_volume(float f);
void audio_play(int s, int on);
#endif /* AUDIO_H */

BIN
bing.wav

BIN
bip.wav

BIN
bop.wav

119
cars.c

@ -0,0 +1,119 @@
#include "cars.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct car s_cars[MAX_CARS];
#ifdef WIN32
#include <stddef.h>
#include <string.h>
#include <stdio.h>
char* strsep(char** stringp, const char* delim)
{
char* start = *stringp;
char* p;
p = (start != NULL) ? strpbrk(start, delim) : NULL;
if (p == NULL)
{
*stringp = NULL;
}
else
{
*p = '\0';
*stringp = p + 1;
}
return start;
}
#endif
void init_cars(void)
{
memset(s_cars, 0, sizeof s_cars);
FILE *f = fopen("cars.txt", "r");
if (!f) return;
struct car *car = s_cars;
while (!feof(f))
{
char buf[1024];
if (fgets(buf, sizeof buf, f) <= 0) break;
if (*buf == '#') continue;
char *bufp = buf, *p;
p = strsep(&bufp, ",");
strncpy(car->tag, p, sizeof car->tag);
p = strsep(&bufp, ",");
strncpy(car->base, p, sizeof car->base);
p = strsep(&bufp, ",");
strncpy(car->cls, p, sizeof car->cls);
p = strsep(&bufp, ",");
car->intake = strtol(p, NULL, 10);
p = strsep(&bufp, ",");
car->weight = strtol(p, NULL, 10);
p = strsep(&bufp, ",");
strncpy(car->name, p, sizeof car->name);
p = strsep(&bufp, ",");
car->maxrpm = strtof(p, NULL);
p = strsep(&bufp, ",");
car->maxfuel = strtof(p, NULL);
p = strsep(&bufp, ",");
car->maxboost = strtof(p, NULL);
p = strsep(&bufp, ",");
car->maxspeed = strtof(p, NULL);
car++;
if (car - s_cars == MAX_CARS) break;
}
fclose(f);
}
int get_car(const char tag[4], struct car *car)
{
int i;
for (i = 0; i < MAX_CARS; i++)
{
if (!strcmp(s_cars[i].tag, tag))
{
if (car != NULL) memcpy(car, &s_cars[i], sizeof *car);
return i;
}
}
return -1;
}
const char *find_car(const char tag[4], int intake, int weight)
{
const struct car *best = NULL;
int i;
for (i = 0; i < MAX_CARS; i++)
{
const struct car *car = s_cars + i;
if (!strcmp(car->base, tag))
{
if (car->intake <= intake && car->weight <= weight)
{
if (best == NULL || (car->intake >= best->intake && car->weight >= best->weight))
{
best = s_cars + i;
}
}
}
}
return best->tag;
}
void update_car(int carnum, float dist, float time, float cons)
{
s_cars[carnum].dist += dist;
s_cars[carnum].time += time;
s_cars[carnum].cons += cons;
}

31
cars.h

@ -0,0 +1,31 @@
#ifndef CARS_H
#define CARS_H
#define MAX_CARS 60
struct car
{
char tag[4];
char base[4];
char cls[20];
char name[20];
float maxrpm;
float maxfuel;
float maxboost;
float maxspeed;
int intake;
int weight;
float dist;
float time;
float cons;
};
extern struct car s_cars[MAX_CARS];
void init_cars(void);
int get_car(const char tag[4], struct car *car);
const char *find_car(const char tag[4], int intake, int weight);
void update_car(int carnum, float dist, float time, float cons);
#endif /* CARS_H */

45
cars.txt

@ -0,0 +1,45 @@
UF1,UF1,STD,0,0,UF 1000,6983.477051,35.0,0.0,100
XFG,XFG,STD,0,0,XF GTI,7978.992188,45.0,0.0,120
XRG,XRG,STD,0,0,XR GT,6980.518066,65.0,0.0,130
LX4,LX4,TBO,0,0,LX4,8974.058594,40.0,0.0,130
LX6,LX6,LRF,0,0,LX6,8975.434570,40.0,0.0,140
RB4,RB4,TBO,0,0,RB4 GT,7480.626465,75.0,0.731383,150
FXO,FXO,TBO,0,0,FXO TURBO,7482.368164,75.0,0.733507,160
XRT,XRT,TBO,0,0,XR GT TURBO,7480.955078,75.0,0.830510,160
RAC,RAC,LRF,0,0,RACEABOUT,6985.558594,42.0,0.482715,160
FZ5,FZ5,LRF,0,0,FZ50,7971.276855,90.0,0.0,180
UFR,UFR,NGT,0,0,UF GTR,8978.926758,60.0,0.0,160
XFR,XFR,NGT,0,0,XF GTR,7979.339355,70.0,0.0,180
FXR,FXR,GTR,0,0,FXO GTR,7492.066895,100.0,1.759917,200
XRR,XRR,GTR,0,0,XR GTR,7492.067383,100.0,1.759917,200
FZR,FZR,GTR,0,0,FZ50 GTR,8474.996094,100.0,0.0,200
MRT,MRT,S-S,0,0,MRT5,12917.661133,20.0,0.138831,120
FBM,FBM,S-S,0,0,FORMULA BMW FB02,9179.628906,42.0,0.0,140
FOX,FOX,S-S,0,0,FORMULA XR,7481.007324,38.0,0.0,150
FO8,FO8,S-S,0,0,FORMULA V8,9476.702148,125.0,0.0,180
BF1,BF1,S-S,0,0,BMW SAUBER F1.06,19912.447266,95.0,0.0,220
FX2,FXR,GT2,23,0,FXO GT2,7492.066895,100.0,1.759917,200
XR2,XRR,GT2,24,0,XR GT2,7492.067383,100.0,1.759917,200
FZ2,FZR,GT2,20,0,FZ50 GT2,8474.996094,100.0,0.0,200
FX9,FXR,GT9,24,0,FXO GT9,7492.066895,100.0,1.759917,200
XR9,XRR,GT9,25,0,XR GT9,7492.067383,100.0,1.759917,200
FZ9,FZR,GT9,21,0,FZ50 GT9,8474.996094,100.0,0.0,200
FXP,FXR,GTP,10,10,FXO GTP,7492.066895,100.0,1.759917,200
XRP,XRR,GTP,10,20,XR GTP,7492.067383,100.0,1.759917,200
FZP,FZR,GTP,10,0,FZ50 GTP,8474.996094,100.0,0.0,200
FX3,FXR,GT3,32,0,FXO GT3,7492.066895,100.0,1.759917,200
XR3,XRR,GT3,34,0,XR GT3,7492.067383,100.0,1.759917,200
FZ3,FZR,GT3,28,0,FZ50 GT3,8474.996094,100.0,0.0,200
FX4,FXR,GT4,44,75,FXO GT4,7492.066895,100.0,1.759917,200
XR4,XRR,GT4,44,100,XR GT4,7492.067383,100.0,1.759917,200
FZ4,FZR,GT4,37,100,FZ50 GT4,8474.996094,100.0,0.0,200
UF4,UFR,GT4,12,50,UF GT4,8978.926758,60.0,0.0,160
XF4,XFR,GT4,10,60,XF GT4,7979.339355,70.0,0.0,180
UFB,UFR,BGT,45,0,UF-BR,8978.926758,60.0,0.0,160
XFB,XFR,BGT,43,0,XF-BR,7979.339355,70.0,0.0,180
RBS,RB4,S-series,4,60,RB4-S,7480.626465,75.0,0.731383,150
FXS,FXO,S-series,6,70,FXO-S,7482.368164,75.0,0.733507,160
XRS,XRT,S-series,5,60,XR GT-S,7480.955078,75.0,0.830510,160
FZS,FZ5,S-series,22,50,FZ50 S,7971.276855,90.0,0.0,180
FO,FXO,TWC,5,0,FO TURBO,7482.368164,75.0,0.733507,160
XT,XRT,TWC,1,0,XT TURBO,7480.955078,75.0,0.830510,160

182
config.c

@ -0,0 +1,182 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#define MAXCONFIGLEN 64
struct configitem
{
char setting[MAXCONFIGLEN];
char value[MAXCONFIGLEN];
struct configitem *next;
};
static struct
{
const char *filename;
struct configitem *head;
} s_config;
static void config_free(void)
{
struct configitem *prev;
struct configitem *curr = s_config.head;
s_config.head = NULL;
while (curr != NULL)
{
prev = curr;
curr = curr->next;
free(prev);
}
}
void config_set_string(const char *key, const char *value)
{
struct configitem *item;
struct configitem **itemp = &s_config.head;
while (*itemp != NULL)
{
if (strcasecmp((*itemp)->setting, key) == 0)
{
item = *itemp;
if (value == NULL)
{
*itemp = item->next;
free(item);
}
else
{
strncpy(item->value, value, sizeof item->value);
}
return;
}
itemp = &(*itemp)->next;
}
if (value == NULL) return;
*itemp = malloc(sizeof *item);
item = *itemp;
strncpy(item->setting, key, sizeof item->setting);
strncpy(item->value, value, sizeof item->value);
item->next = NULL;
}
static void config_rehash(void)
{
FILE *f = fopen(s_config.filename, "r");
if (f == NULL) return;
config_free();
while (!feof(f))
{
char buf[256];
if (fgets(buf, sizeof buf, f) <= 0) break;
/* Ignore comments */
if (*buf == '#') continue;
char *n = strchr(buf, '=');
if (n == NULL) continue;
*n++ = '\0';
char *eol = strchr(n, '\n');
if (eol != NULL) *eol = '\0';
config_set_string(buf, n);
}
fclose(f);
}
static void config_write(void)
{
FILE *f = fopen(s_config.filename, "w");
if (f == NULL) return;
struct configitem *curr;
for (curr = s_config.head; curr != NULL; curr = curr->next)
{
fprintf(f, "%s=%s\n", curr->setting, curr->value);
}
fclose(f);
}
void config_init(const char *filename)
{
s_config.filename = filename;
s_config.head = NULL;
config_rehash();
}
void config_deinit(void)
{
config_write();
config_free();
}
void config_set_int(const char *setting, int value)
{
char c[MAXCONFIGLEN];
snprintf(c, sizeof c, "%d", value);
config_set_string(setting, c);
}
void config_set_float(const char *setting, float value)
{
char c[MAXCONFIGLEN];
snprintf(c, sizeof c, "%f", value);
config_set_string(setting, c);
}
int config_get_string(const char *setting, char **value)
{
struct configitem *curr;
for (curr = s_config.head; curr != NULL; curr = curr->next)
{
if (strcasecmp(curr->setting, setting) == 0)
{
*value = curr->value;
return 1;
}
}
*value = NULL;
return 0;
}
int config_get_int(const char *setting, int *value)
{
char *c, *endptr;
int v;
if (!config_get_string(setting, &c)) return 0;
v = strtol(c, &endptr, 10);
if (*endptr != '\0') return 0;
*value = v;
return 1;
}
int config_get_float(const char *setting, float *value)
{
char *c, *endptr;
float v;
if (!config_get_string(setting, &c)) return 0;
v = strtof(c, &endptr);
if (*endptr != '\0') return 0;
*value = v;
return 1;
}

15
config.h

@ -0,0 +1,15 @@
#ifndef CONFIG_H
#define CONFIG_H
void config_init(const char *filename);
void config_deinit(void);
void config_set_string(const char *setting, const char *value);
void config_set_int(const char *setting, int value);
void config_set_float(const char *setting, float value);
int config_get_string(const char *setting, char **value);
int config_get_int(const char *setting, int *value);
int config_get_float(const char *setting, float *value);
#endif /* CONFIG_H */

237
gauge.c

@ -0,0 +1,237 @@
#include <GL/glfw.h>
#include <FTGL/ftgl.h>
#include <math.h>
#include <stdio.h>
#include "gauge.h"
#include "text.h"
void init_gauges(void)
{
}
void DrawArc(float inner, float outer, float start_angle, float arc_angle, int num_segments)
{
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 tangetial_factor = tanf(theta);
float radial_factor = cosf(theta);
float xi = inner * sinf(start_angle); //we now start at the start angle
float yi = inner * cosf(start_angle);
float xo = outer * sinf(start_angle); //we now start at the 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);
float txi = -yi;
float tyi = xi;
xi += txi * tangetial_factor;
yi += tyi * tangetial_factor;
xi *= radial_factor;
yi *= radial_factor;
float txo = -yo;
float tyo = xo;
xo += txo * tangetial_factor;
yo += tyo * tangetial_factor;
xo *= radial_factor;
yo *= radial_factor;
}
glEnd();
}
/*
float theta = 2 * 3.1415926 / (float)num_segments;
float c = cosf(theta);//precalculate the sine and cosine
float s = sinf(theta);
float t;
float x = r;//we start at angle = 0
float y = 0;
glBegin(GL_LINE_LOOP);
int ii;
for(ii = 0; ii < num_segments; ii++)
{
glVertex3f(x + cx, y + cy, 0);//output vertex
//apply the rotation matrix
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
glEnd();
}*/
void drawDial(const struct gauge *gauge, float value, int style)
{
float range = gauge->rangemax - gauge->rangemin;
float angle = gauge->anglemax - gauge->anglemin;
float cura = (value - gauge->rangemin) / range * angle + gauge->anglemin;
switch (style)
{
case GT_NONE:
break;
case GT_BAR:
glColor4f(gauge->dial.r, gauge->dial.g, gauge->dial.b, gauge->dial.a);
DrawArc(gauge->majorstart, gauge->majorend, cura, cura - gauge->anglemin, 10);
break;
case GT_LINE2:
glColor4f(gauge->dial.r, gauge->dial.g, gauge->dial.b, gauge->dial.a);
glBegin(GL_LINES);
glVertex3f(0, 0, 0);
glVertex3f(sin(cura), cos(cura), 0);
glEnd();
break;
case GT_LINE:
glColor4f(1.0, 0.0, 0.0, 1.0);
glBegin(GL_LINES);
glVertex3f(sin(cura) * 0.8, cos(cura) * 0.8, 0);
glVertex3f(sin(cura), cos(cura), 0);
glEnd();
break;
default:
case GT_NEEDLE:
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);
glBegin(GL_TRIANGLE_STRIP);
//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.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.005, 1.0, 0.0);
glVertex3f(0.005, 1.0, 0.0);
//glVertex3f(0.0, 1.0, 0.0);
glEnd();
break;
}
}
void draw_gauge(const struct gauge *gauge, float value, float red, FTGLfont *font, int gaugetype)
{
float range = gauge->rangemax - gauge->rangemin;
float angle = gauge->anglemax - gauge->anglemin;
float major;// = angle / (range / gauge->majorstep + 0.0);
float minor;// = angle / (range / gauge->minorstep + 0.0);
float cura;
float x1, y1, x2, y2;
int ii;
float majorstep = gauge->majorstep;
float minorstep = gauge->minorstep;
while (1) {
major = angle / (range / majorstep + 0.0);
minor = angle / (range / minorstep + 0.0);
if (fabsf(major) < 12 * M_PI / 180.0) {
majorstep *= 2;
minorstep = majorstep / 2;
} else {
break;
}
}
if (value < gauge->rangemin) value = gauge->rangemin;
if (value > gauge->rangemax * 2) value = gauge->rangemax * 2;
glPushMatrix();
glScalef(gauge->radius, gauge->radius, 1.0);
if (red > 0) {
glLineWidth(1.0);
glColor4f(0.8, 0.0, 0.0, 1.0);
cura = (red - gauge->rangemin) / range * angle + gauge->anglemin;
/*
float x1 = sin(cura) * gauge->majorstart;
float y1 = cos(cura) * gauge->majorstart;
float x2 = sin(cura) * gauge->majorend;
float y2 = cos(cura) * gauge->majorend;
glBegin(GL_LINES);
glVertex3f(x1, y1, 0);
glVertex3f(x2, y2, 0);
glEnd();*/
// printf("%f -> %f\n", cura, gauge->anglemax);
DrawArc(gauge->majorstart, gauge->majorend, gauge->anglemax, gauge->anglemax - cura, 10);
}
glLineWidth(gauge->minorwidth);
glColor4f(gauge->minor.r, gauge->minor.g, gauge->minor.b, gauge->minor.a);
// for (cura = gauge->anglemin; cura < gauge->anglemax; cura += minor)
for (ii = 0; ii <= range / minorstep; ii++)
{
if (red > 0 && ii * minorstep >= red) {
glColor4f(1.0, 1.0, 1.0, 1.0);
}
float cura = gauge->anglemin + ii * minor;
x1 = sin(cura) * gauge->minorstart;
y1 = cos(cura) * gauge->minorstart;
x2 = sin(cura) * gauge->minorend;
y2 = cos(cura) * gauge->minorend;
glBegin(GL_LINES);
glVertex3f(x1, y1, 0);
glVertex3f(x2, y2, 0);
glEnd();
}
glLineWidth(gauge->majorwidth);
glColor4f(gauge->major.r, gauge->major.g, gauge->major.b, gauge->major.a);
// for (cura = gauge->anglemin; cura < gauge->anglemax; cura += major)
for (ii = 0; ii <= range / majorstep; ii++)
{
if (red > 0 && ii * majorstep > red) {
glColor4f(1.0, 1.0, 1.0, 1.0);
}
float cura = gauge->anglemin + ii * major;
x1 = sin(cura) * gauge->majorstart;
y1 = cos(cura) * gauge->majorstart;
x2 = sin(cura) * gauge->majorend;
y2 = cos(cura) * gauge->majorend;
glBegin(GL_LINES);
glVertex3f(x1, y1, 0);
glVertex3f(x2, y2, 0);
glEnd();
char text[10];
if (gauge->majorstep > 100) {
snprintf(text, sizeof text, "%d", (int)(ii * majorstep / 1000 + gauge->rangemin));
} else {
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 offs = gauge->majorstart - scale;
drawText(text, font, sin(cura) * offs, cos(cura) * offs, scale, scale, TA_CENTRE, TA_CENTRE);
}
drawDial(gauge, value, gaugetype);
glPopMatrix();
}

73
gauge.h

@ -0,0 +1,73 @@
#ifndef GAUGE_H
#define GAUGE_H
#include <FTGL/ftgl.h>
struct colour
{
float r, g, b, a;
};
#define OG_SHIFT 1 // key
#define OG_CTRL 2 // key
#define OG_TURBO 8192 // show turbo gauge
#define OG_KM 16384 // if not set - user prefers MILES
#define OG_BAR 32768 // if not set - user prefers PSI
// DL_x - bits for OutGaugePack DashLights and ShowLights
enum
{
DL_SHIFT, // bit 0 - shift light
DL_FULLBEAM, // bit 1 - full beam
DL_HANDBRAKE, // bit 2 - handbrake
DL_PITSPEED, // bit 3 - pit speed limiter
DL_TC, // bit 4 - TC active or switched off
DL_SIGNAL_L, // bit 5 - left turn signal
DL_SIGNAL_R, // bit 6 - right turn signal
DL_SIGNAL_ANY, // bit 7 - shared turn signal
DL_OILWARN, // bit 8 - oil pressure warning
DL_BATTERY, // bit 9 - battery warning
DL_ABS, // bit 10 - ABS active or switched off
DL_SPARE, // bit 11
DL_NUM
};
struct gauge
{
char name[16];
float radius;
float anglemin;
float anglemax;
float rangemin;
float rangemax;
float majorstep;
float majorwidth;
float majorstart;
float majorend;
struct colour major;
float minorstep;
float minorwidth;
float minorstart;
float minorend;
struct colour minor;
struct colour dial;
};
enum {
GT_NONE,
GT_NEEDLE,
GT_LINE,
GT_LINE2,
GT_BAR,
};
void init_gauges(void);
void drawDial(const struct gauge *gauge, float value, int style);
void draw_gauge(const struct gauge *gauge, float value, float red, FTGLfont *font, int gaugetype);
#endif /* GAUGE_H */

13
gauges.txt

@ -0,0 +1,13 @@
# name, start angle, end angle
# major: r, g, b, a, width, start, end
# minor: r, g, b, a, width, start, end
# dial: r, g, b, a
regular,30.0,270.0
1.0,1.0,1.0,1.0,3.0,0.9,1.0
0.8,0.8,0.8,1.0,1.0,0.95,0.97
1.0,0.0,0.0,0.5
fuel,150.0,210.0
1.0,1.0,1.0,1.0,3.0,0.9,1.0
0.8,0.8,0.8,1.0,1.0,0.95,0.97
1.0,0.0,0.0,0.5

81
gettime.h

@ -0,0 +1,81 @@
#ifndef GETTIME_H
#define GETTIME_H
#include <time.h>
#ifdef WIN32
#include <windows.h>
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 0
static inline LARGE_INTEGER getFILETIMEoffset()
{
SYSTEMTIME s;
FILETIME f;
LARGE_INTEGER t;
s.wYear = 1970;
s.wMonth = 1;
s.wDay = 1;
s.wHour = 0;
s.wMinute = 0;
s.wSecond = 0;
s.wMilliseconds = 0;
SystemTimeToFileTime(&s, &f);
t.QuadPart = f.dwHighDateTime;
t.QuadPart <<= 32;
t.QuadPart |= f.dwLowDateTime;
return t;
}
static inline int clock_gettime(int X, struct timespec *ts)
{
LARGE_INTEGER t;
FILETIME f;
double microseconds;
static LARGE_INTEGER offset;
static double frequencyToMicroseconds;
static int initialized = 0;
static BOOL usePerformanceCounter = 0;
if (!initialized) {
LARGE_INTEGER performanceFrequency;
initialized = 1;
usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
if (usePerformanceCounter) {
QueryPerformanceCounter(&offset);
frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
} else {
offset = getFILETIMEoffset();
frequencyToMicroseconds = 10.;
}
}
if (usePerformanceCounter) {
QueryPerformanceCounter(&t);
} else {
GetSystemTimeAsFileTime(&f);
t.QuadPart = f.dwHighDateTime;
t.QuadPart <<= 32;
t.QuadPart |= f.dwLowDateTime;
}
t.QuadPart -= offset.QuadPart;
microseconds = (double)t.QuadPart / frequencyToMicroseconds;
t.QuadPart = microseconds;
ts->tv_sec = t.QuadPart / 1000000;
ts->tv_nsec = (t.QuadPart % 1000000) * 1000;
return 0;
}
#endif
static inline unsigned gettime(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}
#endif

439
insim.c

@ -0,0 +1,439 @@
//#define USE_IPV6
#include <stdlib.h>
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#define MSG_NOSIGNAL 0
#else
//#include <sys/types.h>
#include <sys/socket.h>
//#include <netinet/in.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "cars.h"
#include "socket.h"
#include "insim.h"
#include "network_worker.h"
#include "queue.h"
#include "outgauge.h"
struct conninfo s_conninfo[256];
struct carinfo s_carinfo[256];
struct insim_buffer {
int state;
uint8_t buffer[65536];
int pos;
int offset;
};
static struct insim_buffer s_insim_tcp;
static struct insim_buffer s_insim_udp;
static struct queue_t *s_send_queue;
static uint8_t *s_send_packet;
static uint8_t s_send_pos;
void insim_queue(const void *buffer, size_t size)
{
uint8_t *packet = malloc(size);
memcpy(packet, buffer, size);
queue_produce(s_send_queue, packet);
}
int insim_dequeue(int fd)
{
if (s_send_packet == NULL) queue_consume(s_send_queue, (void *)&s_send_packet);
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);
if (s >= 0) s_send_pos += s;
if (s_send_pos >= s_send_packet[0])
{
free(s_send_packet);
s_send_packet = 0;
s_send_pos = 0;
return 1;
}
}
return 0;
}
void insim_request_info(void)
{
memset(s_conninfo, 0, sizeof s_conninfo);
memset(s_carinfo, 0, sizeof s_carinfo);
struct IS_TINY p;
p.Size = sizeof p;
p.Type = ISP_TINY;
p.ReqI = 2;
p.SubT = TINY_NCN;
insim_queue(&p, sizeof p);
p.Size = sizeof p;
p.Type = ISP_TINY;
p.ReqI = 3;
p.SubT = TINY_NPL;
insim_queue(&p, sizeof p);
}
void insim_handle_tiny(int fd, const void *buffer)
{
const struct IS_TINY *p = buffer;
switch (p->SubT)
{
case TINY_NONE:
{
struct IS_TINY r;
r.Size = sizeof r;
r.Type = ISP_TINY;
r.ReqI = 0;
r.SubT = TINY_NONE;
insim_queue(&r, sizeof r);
break;
}
}
}
static void ltc_duty(const char *uname, int state)
{
int i;
for (i = 0; i < 256; i++) {
if (!strcmp(uname, s_conninfo[i].uname)) {
s_conninfo[i].state = state;
printf("Player %s state %d\n", uname, state);
return;
}
}
}
void insim_handle_ism(int fd, const void *buffer)
{
const struct IS_ISM *p = buffer;
printf("Joined %s\n", p->HName);
insim_request_info();
}
void insim_handle_mso(int fd, const void *buffer)
{
return;
const struct IS_MSO *p = buffer;
printf("%d %d %d %d %s\n", p->UCID, p->PLID, p->UserType, p->TextStart, p->Msg);
char buf[128], *bufp = buf;
strncpy(buf, p->Msg, sizeof buf);
int state = 0;
char *name = NULL;
int i;
for (i = 0; i < 10; i++) {
char *a = strsep(&bufp, " ");
if (a == NULL) return;
if (i == 0 && strcmp(a, "***")) return;
if (i == 1 && (!strcmp(a, "Officer") || !strcmp(a, "Cadet"))) state |= 1;
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)
{
const struct IS_NCN *p = buffer;
struct conninfo *c = s_conninfo + p->UCID;
memset(c, 0, sizeof *c);
c->active = 1;
strncpy(c->uname, p->UName, sizeof c->uname);
strncpy(c->pname, p->PName, sizeof c->pname);
c->admin = p->Admin;
printf("Know about connection %s (%s) %d\n", c->pname, c->uname, c->admin);
}
void insim_handle_cnl(int fd, const void *buffer)
{
const struct IS_CNL *p = buffer;
struct conninfo *c = s_conninfo + p->UCID;
c->active = 0;
}
void insim_handle_cpr(int fd, const void *buffer)
{
const struct IS_CPR *p = buffer;
struct conninfo *c = s_conninfo + p->UCID;
if (c->active == 0) fprintf(stderr, "Rename of inactive connection\n");
strncpy(c->pname, p->PName, sizeof c->pname);
}
void insim_handle_npl(int fd, const void *buffer)
{
const struct IS_NPL *p = buffer;
struct carinfo *car = s_carinfo + p->PLID;
memset(car, 0, sizeof *car);
car->active = 1;
//strncpy(car->cname, p->CName, sizeof car->cname);
car->ucid = p->UCID;
car->mass = p->H_Mass;
car->intake = p->H_TRes;
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);
}
void insim_handle_pll(int fd, const void *buffer)
{
const struct IS_PLL *p = buffer;
struct carinfo *car = s_carinfo + p->PLID;
car->active = 0;
printf("Car %d left - %s\n", p->PLID, s_conninfo[car->ucid].uname);
}
void insim_handle_mci(int fd, const void *buffer)
{
const struct IS_MCI *p = buffer;
int i;
for (i = 0; i < p->NumC; i++)
{
const struct CompCar *c = p->Info + i;
struct carinfo *car = s_carinfo + c->PLID;
car->position = c->Position;
car->info = c->Info;
car->sp3 = c->Sp3;
car->x = c->X;
car->y = c->Y;
car->z = c->Z;
car->speed = c->Speed;
car->direction = c->Direction;
car->heading = c->Heading;
car->angvel = c->AngVel;
car->hist_x[car->hist] = c->X;
car->hist_y[car->hist] = c->Y;
car->hist_s[car->hist] = c->Speed;
car->hist = (car->hist + 1) % CARPATHSIZE;
}
}
typedef void (*insim_handler)(int fd, const void *buffer);
static const insim_handler s_handlers[] =
{
NULL, // ISP_NONE // 0 : not used
NULL, // ISP_ISI // 1 - instruction : insim initialise
NULL, // ISP_VER // 2 - info : version info
insim_handle_tiny, // ISP_TINY // 3 - both ways : multi purpose
NULL, // ISP_SMALL // 4 - both ways : multi purpose
NULL, // ISP_STA // 5 - info : state info
NULL, // ISP_SCH // 6 - instruction : single character
NULL, // ISP_SFP // 7 - instruction : state flags pack
NULL, // ISP_SCC // 8 - instruction : set car camera
NULL, // ISP_CPP // 9 - both ways : cam pos pack
insim_handle_ism, // ISP_ISM // 10 - info : start multiplayer
insim_handle_mso, // ISP_MSO // 11 - info : message out
NULL, // ISP_III // 12 - info : hidden /i message
NULL, // ISP_MST // 13 - instruction : type message or /command
NULL, // ISP_MTC // 14 - instruction : message to a connection
NULL, // ISP_MOD // 15 - instruction : set screen mode
NULL, // ISP_VTN // 16 - info : vote notification
NULL, // ISP_RST // 17 - info : race start
insim_handle_ncn, // ISP_NCN // 18 - info : new connection
insim_handle_cnl, // ISP_CNL // 19 - info : connection left
insim_handle_cpr, // ISP_CPR // 20 - info : connection renamed
insim_handle_npl, // ISP_NPL // 21 - info : new player (joined race)
NULL, // ISP_PLP // 22 - info : player pit (keeps slot in race)
insim_handle_pll, // ISP_PLL // 23 - info : player leave (spectate - loses slot)
NULL, // ISP_LAP // 24 - info : lap time
NULL, // ISP_SPX // 25 - info : split x time
NULL, // ISP_PIT // 26 - info : pit stop start
NULL, // ISP_PSF // 27 - info : pit stop finish
NULL, // ISP_PLA // 28 - info : pit lane enter / leave
NULL, // ISP_CCH // 29 - info : camera changed
NULL, // ISP_PEN // 30 - info : penalty given or cleared
NULL, // ISP_TOC // 31 - info : take over car
NULL, // ISP_FLG // 32 - info : flag (yellow or blue)
NULL, // ISP_PFL // 33 - info : player flags (help flags)
NULL, // ISP_FIN // 34 - info : finished race
NULL, // ISP_RES // 35 - info : result confirmed
NULL, // ISP_REO // 36 - both ways : reorder (info or instruction)
NULL, // ISP_NLP // 37 - info : node and lap packet
insim_handle_mci, // ISP_MCI // 38 - info : multi car info
NULL, // ISP_MSX // 39 - instruction : type message
NULL, // ISP_MSL // 40 - instruction : message to local computer
NULL, // ISP_CRS // 41 - info : car reset
NULL, // ISP_BFN // 42 - both ways : delete buttons / receive button requests
NULL, // ISP_AXI // 43 - info : autocross layout information
NULL, // ISP_AXO // 44 - info : hit an autocross object
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_BTT // 47 - info : sent after typing into a button
NULL, // ISP_RIP // 48 - both ways : replay information packet
NULL, // ISP_SSH // 49 - both ways : screenshot
NULL, // ISP_CON // 50 - info : contact between cars (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_PLC // 53 - instruction : player cars
NULL, // ISP_AXM // 54 - both ways : autocross multiple objects
NULL, // ISP_ACR // 55 - info : admin command report
};
void insim_handle(int fd, const uint8_t *buffer)
{
uint8_t type = buffer[1];
if (type <= ISP_ACR && s_handlers[type] != NULL)
{
s_handlers[type](fd, buffer);
}
}
int insim_recv(int fd, int can_write, int can_read, void *arg)
{
struct insim_buffer *buffer = arg;
if (can_write && buffer->state == 1)
{
insim_dequeue(fd);
}
if (can_read)
{
if (buffer->pos >= sizeof buffer->buffer)
{
printf("buffer full\n");
return 0;
}
ssize_t res = recv(fd, (char *)buffer->buffer + buffer->pos, sizeof buffer->buffer - buffer->pos, 0);
if (res == -1)
{
#ifdef WIN32
if (WSAGetLastError() == WSAECONNRESET)
#else
if (errno == ECONNRESET)
#endif
{
printf("connreset\n");
return 0;
}
#ifdef WIN32
else if (WSAGetLastError() != WSAEWOULDBLOCK)
#else
else if (errno != EWOULDBLOCK && errno != EAGAIN)
#endif
{
printf("hmm: %s\n", strerror(errno));
return 0;
}
}
if (res == 0)
{
printf("nothing received\n");
return 0;
}
buffer->pos += res;
while (1)
{
uint8_t size = buffer->buffer[buffer->offset];
if (size % 4 != 0)
{
printf("invalid packet, size is %d\n", size);
return 0;
}
if (buffer->pos - buffer->offset >= size)
{
insim_handle(fd, buffer->buffer + buffer->offset);
}
else
{
break;
}
if (buffer->pos - buffer->offset > size)
{
buffer->offset += size;
}
else
{
buffer->pos = 0;
buffer->offset = 0;
}
}
}
return 1;
}
/*
#ifdef USE_IPV6
static struct sockaddr_in6 serv_addr;
#else
static struct sockaddr_in serv_addr;
#endif
*/
extern int g_outgauge_port;
extern int g_insim_port;
static void insim_connect(int fd, void *arg)
{
if (fd == -1)
{
return;
}
s_insim_tcp.state = 1;
s_insim_tcp.pos = 0;
s_insim_tcp.offset = 0;
register_socket(fd, SM_READ | SM_WRITE, &insim_recv, &s_insim_tcp);
fd = network_listen(g_insim_port + 1, 0);
s_insim_udp.state = 2;
s_insim_udp.pos = 0;
s_insim_udp.offset = 0;
register_socket(fd, SM_READ, &insim_recv, &s_insim_udp);
struct IS_ISI p;
memset(&p, 0, sizeof p);
p.Size = sizeof p;
p.Type = ISP_ISI;
p.ReqI = 0;
p.Zero = 0;
p.UDPPort = g_outgauge_port; //g_insim_port + 1;
p.Flags = ISF_LOCAL;
p.Sp0 = 0;
p.Prefix = 0;
p.Interval = 100;
snprintf(p.Admin, sizeof p.Admin, "");
snprintf(p.IName, sizeof p.IName, "LFS Dashboard");
insim_queue(&p, sizeof p);
struct IS_SMALL s;
s.Size = sizeof s;
s.Type = ISP_SMALL;
s.ReqI = 1;
s.SubT = SMALL_SSG;
s.UVal = 1;
insim_queue(&s, sizeof s);
insim_request_info();
}
void insim_init(const char *hostname, int port)
{
s_insim_tcp.state = 0;
s_insim_udp.state = 0;
s_send_queue = queue_new();
network_connect(hostname, port, &insim_connect, NULL);
}

2237
insim.h
File diff suppressed because it is too large
View File

994
lfsdash.c

@ -0,0 +1,994 @@
#include <GL/glfw.h>
#include <FTGL/ftgl.h>
#include <pthread.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include "outgauge.h"
#include "cars.h"
#include "config.h"
#include "gauge.h"
#include "socket.h"
#include "audio.h"
#include "text.h"
#include "insim.h"
#include "network_worker.h"
static GLuint s_symbols[1];
struct sympos {
float a, b, c, d;
int flag;
struct colour off;
struct colour on;
};
/*
DL_SHIFT, // bit 0 - shift light
DL_FULLBEAM, // bit 1 - full beam
DL_HANDBRAKE, // bit 2 - handbrake
DL_PITSPEED, // bit 3 - pit speed limiter
DL_TC, // bit 4 - TC active or switched off
DL_SIGNAL_L, // bit 5 - left turn signal
DL_SIGNAL_R, // bit 6 - right turn signal
DL_SIGNAL_ANY, // bit 7 - shared turn signal
DL_OILWARN, // bit 8 - oil pressure warning
DL_BATTERY, // bit 9 - battery warning
DL_ABS, // bit 10 - ABS active or switched off
DL_SPARE, // bit 11
*/
static int dl_to_sympos[] = {
18, 0, 12, 17, 11, 15, 16,