draw.c refactor. draw.c now handles outer draw routine, previous contents moved to maps.c
Former-commit-id: c1374d41abd475f83a32fa9ec639d0feef018a20 Former-commit-id: 39838a5e1d346c49df1a8f65c910db943a228c61
This commit is contained in:
parent
cb8b16c406
commit
a9a6bc9584
|
@ -1,284 +1,85 @@
|
||||||
Dump1090 README
|
#spidr1090
|
||||||
===
|
|
||||||
|
|
||||||
Dump 1090 is a Mode S decoder specifically designed for RTLSDR devices.
|
###HARDWARE
|
||||||
|
|
||||||
The main features are:
|
####Pi Zero Version
|
||||||
|
Part | Link | Cost
|
||||||
|
--- | --- | ---
|
||||||
|
Raspberry Pi Zero W | | $10
|
||||||
|
Adafruit 2.4" PiTFT Hat| (https://www.adafruit.com/product/2455) | $35
|
||||||
|
NooElec Nano3 SDR | | $28
|
||||||
|
Adafruit GPS Hat | (https://www.adafruit.com/product/2324) | $45
|
||||||
|
Antenna | |
|
||||||
|
USB Jack | |
|
||||||
|
MicroSD Card | |
|
||||||
|
| | Total: $118+
|
||||||
|
|
||||||
* Robust decoding of weak messages, with mode1090 many users observed
|
####Battery Options
|
||||||
improved range compared to other popular decoders.
|
(https://en.wikipedia.org/wiki/List_of_battery_sizes)
|
||||||
* Network support: TCP30003 stream (MSG5...), Raw packets, HTTP.
|
Portrait Orientation:
|
||||||
* Embedded HTTP server that displays the currently detected aircrafts on
|
18500 Batteries (18mm x 50mm), ~1000-2000mAh ea.
|
||||||
Google Map.
|
The Pi Zero configuration consumes are 500mAh
|
||||||
* Single bit errors correction using the 24 bit CRC.
|
|
||||||
* Ability to decode DF11, DF17 messages.
|
|
||||||
* Ability to decode DF formats like DF0, DF4, DF5, DF16, DF20 and DF21
|
|
||||||
where the checksum is xored with the ICAO address by brute forcing the
|
|
||||||
checksum field using recently seen ICAO addresses.
|
|
||||||
* Decode raw IQ samples from file (using --ifile command line switch).
|
|
||||||
* Interactive command-line-interfae mode where aircrafts currently detected
|
|
||||||
are shown as a list refreshing as more data arrives.
|
|
||||||
* CPR coordinates decoding and track calculation from velocity.
|
|
||||||
* TCP server streaming and recceiving raw data to/from connected clients
|
|
||||||
(using --net).
|
|
||||||
|
|
||||||
Installation
|
Landscape Orientation
|
||||||
---
|
18650 batteries (18mm x 65mm). ~2200-3500mAh ea.
|
||||||
|
Adafruit pack + PowerBoost Charger, ~$40
|
||||||
|
Anker PowerCore 10000, ~$25
|
||||||
|
|
||||||
Type "make".
|
Other options
|
||||||
|
external recharger (maybe cheaper and smaller?) along with 18500/18650
|
||||||
|
|
||||||
Normal usage
|
Some 18500 / 18650 include current protection inside, such as:
|
||||||
---
|
http://www.ebay.com/itm/2-x-Panasonic-NCR-18500-2000mAh-LI-ION-RECHARGEABLE-BATTERY-PCB-button-top-case-/391378348412?epid=1830264923&hash=item5b1ff7a97c:g:ePgAAOSwFqJWswnj,
|
||||||
|
otherwise would require external protection circuit to be used in parallel.
|
||||||
|
|
||||||
To capture traffic directly from your RTL device and show the captured traffic
|
|
||||||
on standard output, just run the program without options at all:
|
|
||||||
|
|
||||||
./dump1090
|
|
||||||
|
|
||||||
To just output hexadecimal messages:
|
####Pi 3 Version
|
||||||
|
This gets you a slightly bigger screen, and slightly better performance using the SDR Smart rather than the Nano 3, but requires a ton of annoying port/header clipping and desoldering.
|
||||||
|
|
||||||
./dump1090 --raw
|
Part | Link | Cost
|
||||||
|
--- | --- | ---
|
||||||
|
Raspberry Pi 3 | | $35
|
||||||
|
Adafruit 2.8" PiTFT Hat| https://www.adafruit.com/product/2423 | $45
|
||||||
|
NooElec SDR Smart | | $20
|
||||||
|
GlobalSat MicroGPS Dongle | (https://www.amazon.com/GlobalSat-ND-105C-Micro-USB-Receiver/dp/B00N32HKIW/ref=sr_1_3?ie=UTF8&qid=1505829420&sr=8-3&keywords=gps+dongle) | $30
|
||||||
|
Antenna | |
|
||||||
|
USB Jack | |
|
||||||
|
MicroSD Card | |
|
||||||
|
| | Total: $130+
|
||||||
|
|
||||||
To run the program in interactive mode:
|
|
||||||
|
|
||||||
./dump1090 --interactive
|
alt screen https://www.amazon.com/3-5inch-RPi-LCD-Directly-pluggable-Displaying/dp/B01N48NOXI/ref=sr_1_26?ie=UTF8&qid=1505871836&sr=8-26&keywords=pi+3.5%22+tft, $30 instead of 45, larger, not cap touch
|
||||||
|
|
||||||
To run the program in interactive mode, with networking support, and connect
|
####Battery Options
|
||||||
with your browser to http://localhost:8080 to see live traffic:
|
18650 batteries (18mm x 65mm). ~2200mAH ea.
|
||||||
|
Adafruit pack + PowerBoost Charger, ~$40
|
||||||
|
http://www.ebay.com/itm/3-7-volts-6400-mAh-1S2P-18650-Li-Ion-Battery-Pack-PCB-protected-Panasonic-Cells-/221923032745?hash=item33aba4bea9:g:0-IAAOSw14xWLSr2
|
||||||
|
|
||||||
./dump1090 --interactive --net
|
###INSTALLATION
|
||||||
|
|
||||||
In iteractive mode it is possible to have a less information dense but more
|
####On RPI
|
||||||
"arcade style" output, where the screen is refreshed every second displaying
|
|
||||||
all the recently seen aircrafts with some additional information such as
|
|
||||||
altitude and flight number, extracted from the received Mode S packets.
|
|
||||||
|
|
||||||
Using files as source of data
|
1. Follow [Adafruit PiTFT install guide] (https://learn.adafruit.com/adafruit-2-2-pitft-hat-320-240-primary-display-for-raspberry-pi/easy-install)
|
||||||
---
|
|
||||||
|
|
||||||
To decode data from file, use:
|
2. Install SDL and RTL-SDR libararies
|
||||||
|
```
|
||||||
|
sudo apt-get install libsdl1.2-dev libsdl-ttf2.0-dev libsdl-gfx1.2-dev wiringpi
|
||||||
|
```
|
||||||
|
3. Download spidr
|
||||||
|
```
|
||||||
|
git clone sdfsdfdfs
|
||||||
|
```
|
||||||
|
|
||||||
./dump1090 --ifile /path/to/binfile
|
4. Build spidr with RPI flag set
|
||||||
|
```
|
||||||
|
cd spidr
|
||||||
|
make RPI=1
|
||||||
|
```
|
||||||
|
|
||||||
The binary file should be created using `rtl_sdr` like this (or with any other
|
TODO
|
||||||
program that is able to output 8-bit unsigned IQ samples at 2Mhz sample rate).
|
make install should set up service?
|
||||||
|
|
||||||
rtl_sdr -f 1090000000 -s 2000000 -g 50 output.bin
|
|
||||||
|
|
||||||
In the example `rtl_sdr` a gain of 50 is used, simply you should use the highest
|
|
||||||
gain availabe for your tuner. This is not needed when calling Dump1090 itself
|
|
||||||
as it is able to select the highest gain supported automatically.
|
|
||||||
|
|
||||||
It is possible to feed the program with data via standard input using
|
|
||||||
the --ifile option with "-" as argument.
|
|
||||||
|
|
||||||
Additional options
|
|
||||||
---
|
|
||||||
|
|
||||||
Dump1090 can be called with other command line options to set a different
|
|
||||||
gain, frequency, and so forth. For a list of options use:
|
|
||||||
|
|
||||||
./dump1090 --help
|
|
||||||
|
|
||||||
Everything is not documented here should be obvious, and for most users calling
|
|
||||||
it without arguments at all is the best thing to do.
|
|
||||||
|
|
||||||
Reliability
|
|
||||||
---
|
|
||||||
|
|
||||||
By default Dump1090 checks for decoding errors using the 24-bit CRC checksum,
|
|
||||||
where available. Messages with errors are discarded.
|
|
||||||
|
|
||||||
The --fix command line switch enables fixing single bit error correction
|
|
||||||
based on the CRC checksum. Technically, it uses a table of precomputed
|
|
||||||
checksum differences resulting from single bit errors to look up the
|
|
||||||
wrong bit position.
|
|
||||||
|
|
||||||
This is indeed able to fix errors and works reliably in my experience,
|
|
||||||
however if you are interested in very reliable data I suggest to use
|
|
||||||
the --no-fix command line switch in order to disable error fixing.
|
|
||||||
|
|
||||||
Performances and sensibility of detection
|
|
||||||
---
|
|
||||||
|
|
||||||
In my limited experience Dump1090 was able to decode a big number of messages
|
|
||||||
even in conditions where I encountered problems using other programs, however
|
|
||||||
no formal test was performed so I can't really claim that this program is
|
|
||||||
better or worse compared to other similar programs.
|
|
||||||
|
|
||||||
If you can capture traffic that Dump1090 is not able to decode properly, drop
|
|
||||||
me an email with a download link. I may try to improve the detection during
|
|
||||||
my free time (this is just an hobby project).
|
|
||||||
|
|
||||||
Network server features
|
|
||||||
---
|
|
||||||
|
|
||||||
By enabling the networking support with --net Dump1090 starts listening
|
|
||||||
for clients connections on port 30002 and 30001 (you can change both the
|
|
||||||
ports if you want, see --help output).
|
|
||||||
|
|
||||||
Port 30002
|
|
||||||
---
|
|
||||||
|
|
||||||
Connected clients are served with data ASAP as they arrive from the device
|
|
||||||
(or from file if --ifile is used) in the raw format similar to the following:
|
|
||||||
|
|
||||||
*8D451E8B99019699C00B0A81F36E;
|
|
||||||
|
|
||||||
Every entry is separated by a simple newline (LF character, hex 0x0A).
|
|
||||||
|
|
||||||
Port 30001
|
|
||||||
---
|
|
||||||
|
|
||||||
Port 30001 is the raw input port, and can be used to feed Dump1090 with
|
|
||||||
data in the same format as specified above, with hex messages starting with
|
|
||||||
a `*` and ending with a `;` character.
|
|
||||||
|
|
||||||
So for instance if there is another remote Dump1090 instance collecting data
|
|
||||||
it is possible to sum the output to a local Dump1090 instance doing something
|
|
||||||
like this:
|
|
||||||
|
|
||||||
nc remote-dump1090.example.net 30002 | nc localhost 30001
|
|
||||||
|
|
||||||
It is important to note that what is received via port 30001 is also
|
|
||||||
broadcasted to clients listening to port 30002.
|
|
||||||
|
|
||||||
In general everything received from port 30001 is handled exactly like the
|
|
||||||
normal traffic from RTL devices or from file when --ifile is used.
|
|
||||||
|
|
||||||
It is possible to use Dump1090 just as an hub using --ifile with /dev/zero
|
|
||||||
as argument as in the following example:
|
|
||||||
|
|
||||||
./dump1090 --net-only
|
|
||||||
|
|
||||||
Or alternatively to see what's happening on the screen:
|
|
||||||
|
|
||||||
./dump1090 --net-only --interactive
|
|
||||||
|
|
||||||
Then you can feed it from different data sources from the internet.
|
|
||||||
|
|
||||||
Port 30003
|
|
||||||
---
|
|
||||||
|
|
||||||
Connected clients are served with messages in SBS1 (BaseStation) format,
|
|
||||||
similar to:
|
|
||||||
|
|
||||||
MSG,4,,,738065,,,,,,,,420,179,,,0,,0,0,0,0
|
|
||||||
MSG,3,,,738065,,,,,,,35000,,,34.81609,34.07810,,,0,0,0,0
|
|
||||||
|
|
||||||
This can be used to feed data to various sharing sites without the need to use another decoder.
|
|
||||||
|
|
||||||
Antenna
|
|
||||||
---
|
|
||||||
|
|
||||||
Mode S messages are transmitted in the 1090 Mhz frequency. If you have a decent
|
|
||||||
antenna you'll be able to pick up signals from aircrafts pretty far from your
|
|
||||||
position, especially if you are outdoor and in a position with a good sky view.
|
|
||||||
|
|
||||||
You can easily build a very cheap antenna following the istructions at:
|
|
||||||
|
|
||||||
http://antirez.com/news/46
|
|
||||||
|
|
||||||
With this trivial antenna I was able to pick up signals of aircrafts 200+ Km
|
|
||||||
away from me.
|
|
||||||
|
|
||||||
If you are interested in a more serious antenna check the following
|
|
||||||
resources:
|
|
||||||
|
|
||||||
* http://gnuradio.org/redmine/attachments/download/246/06-foster-adsb.pdf
|
|
||||||
* http://www.lll.lu/~edward/edward/adsb/antenna/ADSBantenna.html
|
|
||||||
* http://modesbeast.com/pix/adsb-ant-drawing.gif
|
|
||||||
|
|
||||||
Aggressive mode
|
|
||||||
---
|
|
||||||
|
|
||||||
With --aggressive it is possible to activate the *aggressive mode* that is a
|
|
||||||
modified version of the Mode S packet detection and decoding.
|
|
||||||
The aggresive mode uses more CPU usually (especially if there are many planes
|
|
||||||
sending DF17 packets), but can detect a few more messages.
|
|
||||||
|
|
||||||
The algorithm in aggressive mode is modified in the following ways:
|
|
||||||
|
|
||||||
* Up to two demodulation errors are tolerated (adjacent entires in the
|
|
||||||
magnitude vector with the same eight). Normally only messages without
|
|
||||||
errors are checked.
|
|
||||||
* It tries to fix DF17 messages with CRC errors resulting from any two bit
|
|
||||||
errors.
|
|
||||||
|
|
||||||
The use of aggressive mdoe is only advised in places where there is
|
|
||||||
low traffic in order to have a chance to capture some more messages.
|
|
||||||
|
|
||||||
Debug mode
|
|
||||||
---
|
|
||||||
|
|
||||||
The Debug mode is a visual help to improve the detection algorithm or to
|
|
||||||
understand why the program is not working for a given input.
|
|
||||||
|
|
||||||
In this mode messages are displayed in an ASCII-art style graphical
|
|
||||||
representation, where the individial magnitude bars sampled at 2Mhz are
|
|
||||||
displayed.
|
|
||||||
|
|
||||||
An index shows the sample number, where 0 is the sample where the first
|
|
||||||
Mode S peak was found. Some additional background noise is also added
|
|
||||||
before the first peak to provide some context.
|
|
||||||
|
|
||||||
To enable debug mode and check what combinations of packets you can
|
|
||||||
log, use `mode1090 --help` to obtain a list of available debug flags.
|
|
||||||
|
|
||||||
Debug mode includes an optional javascript output that is used to visualize
|
|
||||||
packets using a web browser, you can use the file debug.html under the
|
|
||||||
'tools' directory to load the generated frames.js file.
|
|
||||||
|
|
||||||
How this program works?
|
|
||||||
---
|
|
||||||
|
|
||||||
The code is very documented and written in order to be easy to understand.
|
|
||||||
For the diligent programmer with a Mode S specification on his hands it
|
|
||||||
should be trivial to understand how it works.
|
|
||||||
|
|
||||||
The algorithms I used were obtained basically looking at many messages
|
|
||||||
as displayed using a trow-away SDL program, and trying to model the algorithm
|
|
||||||
based on how the messages look graphically.
|
|
||||||
|
|
||||||
How to test the program?
|
|
||||||
---
|
|
||||||
|
|
||||||
If you have an RTLSDR device and you happen to be in an area where there
|
|
||||||
are aircrafts flying over your head, just run the program and check for signals.
|
|
||||||
|
|
||||||
However if you don't have an RTLSDR device, or if in your area the presence
|
|
||||||
of aircrafts is very limited, you may want to try the sample file distributed
|
|
||||||
with the Dump1090 distribution under the "testfiles" directory.
|
|
||||||
|
|
||||||
Just run it like this:
|
|
||||||
|
|
||||||
./dump1090 --ifile testfiles/modes1.bin
|
|
||||||
|
|
||||||
What is --strip mode?
|
|
||||||
---
|
|
||||||
|
|
||||||
It is just a simple filter that will get raw IQ 8 bit samples in input
|
|
||||||
and will output a file missing all the parts of the file where I and Q
|
|
||||||
are lower than the specified <level> for more than 32 samples.
|
|
||||||
|
|
||||||
Use it like this:
|
|
||||||
|
|
||||||
cat big.bin | ./dump1090 --snip 25 > small.bin
|
|
||||||
|
|
||||||
I used it in order to create a small test file to include inside this
|
|
||||||
program source code distribution.
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
---
|
|
||||||
|
|
||||||
Dump1090 was written during some free time during xmas 2012, it is an hobby
|
|
||||||
project so I'll be able to address issues and improve it only during
|
|
||||||
free time, however you are incouraged to send pull requests in order to
|
|
||||||
improve the program. A good starting point can be the TODO list included in
|
|
||||||
the source distribution.
|
|
||||||
|
|
||||||
Credits
|
|
||||||
---
|
|
||||||
|
|
||||||
Dump1090 was written by Salvatore Sanfilippo <antirez@gmail.com> and is
|
|
||||||
released under the BSD three clause license.
|
|
||||||
|
|
1
sdl1090/TerminusTTF-4.46.0.ttf.REMOVED.git-id
Normal file
1
sdl1090/TerminusTTF-4.46.0.ttf.REMOVED.git-id
Normal file
|
@ -0,0 +1 @@
|
||||||
|
eafa3a6e408def39bcd002f60a6d9a9810d54234
|
1
sdl1090/TerminusTTF-Bold-4.46.0.ttf.REMOVED.git-id
Normal file
1
sdl1090/TerminusTTF-Bold-4.46.0.ttf.REMOVED.git-id
Normal file
|
@ -0,0 +1 @@
|
||||||
|
9dc2aed0a76993fd7ba9c28e0f55fce873a8c790
|
|
@ -11,4 +11,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SCREEN_WIDTH 320
|
#define SCREEN_WIDTH 320
|
||||||
#define SCREEN_HEIGHT 240
|
#define SCREEN_HEIGHT 480
|
||||||
|
|
||||||
|
#define UPSCALE 3
|
312
sdl1090/draw.c
312
sdl1090/draw.c
|
@ -1,294 +1,46 @@
|
||||||
#include "dump1090.h"
|
#include "dump1090.h"
|
||||||
#include "draw.h"
|
#include "structs.h"
|
||||||
#include "parula.h"
|
#include "SDL/SDL_rotozoom.h"
|
||||||
#include "magma.h"
|
|
||||||
#include "SDL/SDL_gfxPrimitives.h"
|
|
||||||
|
|
||||||
#define LOGMAXDIST 1000.0
|
static uint64_t mstime(void) {
|
||||||
#define MAXDIST 50.0
|
struct timeval tv;
|
||||||
|
uint64_t mst;
|
||||||
|
|
||||||
#define AA 0
|
gettimeofday(&tv, NULL);
|
||||||
|
mst = ((uint64_t)tv.tv_sec)*1000;
|
||||||
#define MAGMA 0
|
mst += tv.tv_usec/1000;
|
||||||
|
return mst;
|
||||||
void CROSSVP(double *v, double *u, double *w)
|
|
||||||
{
|
|
||||||
v[0] = u[1]*w[2] - u[2]*(w)[1];
|
|
||||||
v[1] = u[2]*w[0] - u[0]*(w)[2];
|
|
||||||
v[2] = u[0]*w[1] - u[1]*(w)[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Color setColor(uint8_t r, uint8_t g, uint8_t b) {
|
void draw() {
|
||||||
SDL_Color out;
|
if ((mstime() - Modes.interactive_last_update) > MODES_INTERACTIVE_REFRESH_TIME) {
|
||||||
out.r = r;
|
|
||||||
out.g = g;
|
|
||||||
out.b = b;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Color signalToColor(int signal) {
|
Modes.interactive_last_update = mstime();
|
||||||
SDL_Color planeColor;
|
|
||||||
|
|
||||||
if(signal > 127) {
|
SDL_FillRect(game.screen, NULL, 0);
|
||||||
signal = 127;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(signal < 0) {
|
if (Modes.map) {
|
||||||
planeColor = setColor(96, 96, 96);
|
drawMap();
|
||||||
} else {
|
//drawList(3,320);
|
||||||
if(MAGMA) {
|
} else {
|
||||||
planeColor = setColor(magma[signal][0], magma[signal][1], magma[signal][2]);
|
drawList(10,0);
|
||||||
} else {
|
}
|
||||||
planeColor = setColor(parula[signal][0], parula[signal][1], parula[signal][2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return planeColor;
|
#ifdef RPI
|
||||||
}
|
SDL_Flip(game.screen);
|
||||||
|
#else
|
||||||
|
SDL_Rect clip;
|
||||||
|
|
||||||
int screenDist(double d) {
|
SDL_Surface *temp = SDL_DisplayFormat(zoomSurface(game.screen, UPSCALE, UPSCALE, 0));
|
||||||
if(Modes.mapLogDist) {
|
|
||||||
return round((double)SCREEN_WIDTH * 0.5 * log(1.0+fabs(d)) / log(1.0+LOGMAXDIST));
|
|
||||||
} else {
|
|
||||||
return round((double)SCREEN_WIDTH * 0.5 * fabs(d) / MAXDIST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void screenCoords(int *outX, int *outY, double dx, double dy) {
|
clip.x = 0;
|
||||||
*outX = (SCREEN_WIDTH>>1) + ((dx>0) ? 1 : -1) * screenDist(dx);
|
clip.y = 0;
|
||||||
*outY = (SCREEN_HEIGHT>>1) + ((dy>0) ? 1 : -1) * screenDist(dy);
|
clip.w = temp->w;
|
||||||
}
|
clip.h = temp->h;
|
||||||
|
|
||||||
int outOfBounds(int x, int y) {
|
SDL_BlitSurface(temp, &clip, game.bigScreen, 0);
|
||||||
if(x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT ) {
|
|
||||||
return 1;
|
SDL_Flip(game.bigScreen);
|
||||||
} else {
|
#endif
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawPlaneHeading(double dx, double dy, double heading, int signal, char *flight)
|
|
||||||
{
|
|
||||||
int x, y;
|
|
||||||
screenCoords(&x, &y, dx, dy);
|
|
||||||
|
|
||||||
if(outOfBounds(x,y)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Color planeColor = signalToColor(signal);
|
|
||||||
|
|
||||||
double body = 8.0;
|
|
||||||
double wing = 6.0;
|
|
||||||
double tail = 3.0;
|
|
||||||
|
|
||||||
double vec[3];
|
|
||||||
vec[0] = sin(heading * M_PI / 180);
|
|
||||||
vec[1] = cos(heading * M_PI / 180);
|
|
||||||
vec[2] = 0;
|
|
||||||
|
|
||||||
double up[] = {0,0,1};
|
|
||||||
|
|
||||||
double out[3];
|
|
||||||
|
|
||||||
CROSSVP(out,vec,up);
|
|
||||||
|
|
||||||
int x1, x2, y1, y2;
|
|
||||||
|
|
||||||
//body
|
|
||||||
x1 = x + round(-body*vec[0]);
|
|
||||||
y1 = y + round(-body*vec[1]);
|
|
||||||
x2 = x + round(body*vec[0]);
|
|
||||||
y2 = y + round(body*vec[1]);
|
|
||||||
|
|
||||||
if(AA) {
|
|
||||||
aalineRGBA(game.screen,x1,y1,x2,y2,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
||||||
aatrigonRGBA(game.screen, x + round(-wing*.35*out[0]), y + round(-wing*.35*out[1]), x + round(wing*.35*out[0]), y + round(wing*.35*out[1]), x1, y1,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
||||||
aacircleRGBA(game.screen, x2,y2,1,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
||||||
} else {
|
|
||||||
thickLineRGBA(game.screen,x,y,x2,y2,2,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
||||||
filledTrigonRGBA(game.screen, x + round(-wing*.35*out[0]), y + round(-wing*.35*out[1]), x + round(wing*.35*out[0]), y + round(wing*.35*out[1]), x1, y1,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
||||||
filledCircleRGBA(game.screen, x2,y2,1,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//wing
|
|
||||||
x1 = x + round(-wing*out[0]);
|
|
||||||
y1 = y + round(-wing*out[1]);
|
|
||||||
x2 = x + round(wing*out[0]);
|
|
||||||
y2 = y + round(wing*out[1]);
|
|
||||||
|
|
||||||
if(AA) {
|
|
||||||
aatrigonRGBA(game.screen, x1, y1, x2, y2, x+round(body*.35*vec[0]), y+round(body*.35*vec[1]),planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
||||||
} else {
|
|
||||||
filledTrigonRGBA(game.screen, x1, y1, x2, y2, x+round(body*.35*vec[0]), y+round(body*.35*vec[1]),planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//tail
|
|
||||||
x1 = x + round(-body*.75*vec[0]) + round(-tail*out[0]);
|
|
||||||
y1 = y + round(-body*.75*vec[1]) + round(-tail*out[1]);
|
|
||||||
x2 = x + round(-body*.75*vec[0]) + round(tail*out[0]);
|
|
||||||
y2 = y + round(-body*.75*vec[1]) + round(tail*out[1]);
|
|
||||||
|
|
||||||
if(AA) {
|
|
||||||
aatrigonRGBA (game.screen, x1, y1, x2, y2, x+round(-body*.5*vec[0]), y+round(-body*.5*vec[1]),planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
||||||
} else {
|
|
||||||
filledTrigonRGBA (game.screen, x1, y1, x2, y2, x+round(-body*.5*vec[0]), y+round(-body*.5*vec[1]),planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
drawString(flight, x + 10, y + 10, game.font, planeColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawPlane(double dx, double dy, int signal)
|
|
||||||
{
|
|
||||||
|
|
||||||
int x, y;
|
|
||||||
screenCoords(&x, &y, dx, dy);
|
|
||||||
|
|
||||||
if(outOfBounds(x,y)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Color planeColor = signalToColor(signal);
|
|
||||||
|
|
||||||
int length = 3.0;
|
|
||||||
|
|
||||||
rectangleRGBA (game.screen, x - length, y - length, x+length, y + length, planeColor.r, planeColor.g, planeColor.b, SDL_ALPHA_OPAQUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawTrail(double *oldDx, double *oldDy, time_t * oldSeen, int idx) {
|
|
||||||
|
|
||||||
|
|
||||||
int currentIdx, prevIdx;
|
|
||||||
|
|
||||||
int currentX, currentY, prevX, prevY;
|
|
||||||
|
|
||||||
time_t now = time(NULL);
|
|
||||||
|
|
||||||
for(int i=0; i < (MODES_INTERACTIVE_TRAIL_LENGTH - 1); i++) {
|
|
||||||
currentIdx = (idx - i) % MODES_INTERACTIVE_TRAIL_LENGTH;
|
|
||||||
currentIdx = currentIdx < 0 ? currentIdx + MODES_INTERACTIVE_TRAIL_LENGTH : currentIdx;
|
|
||||||
prevIdx = (idx - (i + 1)) % MODES_INTERACTIVE_TRAIL_LENGTH;
|
|
||||||
prevIdx = prevIdx < 0 ? prevIdx + MODES_INTERACTIVE_TRAIL_LENGTH : prevIdx;
|
|
||||||
|
|
||||||
if(oldDx[currentIdx] == 0 || oldDy[currentIdx] == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(oldDx[prevIdx] == 0 || oldDy[prevIdx] == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
screenCoords(¤tX, ¤tY, oldDx[currentIdx], oldDy[currentIdx]);
|
|
||||||
|
|
||||||
screenCoords(&prevX, &prevY, oldDx[prevIdx], oldDy[prevIdx]);
|
|
||||||
|
|
||||||
if(outOfBounds(currentX,currentY)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(outOfBounds(prevX,prevY)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double age = 1.0 - (double)(now - oldSeen[currentIdx]) / MODES_INTERACTIVE_TRAIL_TTL;
|
|
||||||
|
|
||||||
if(age < 0) {
|
|
||||||
age = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t colorVal = (uint8_t)floor(127.0 * age);
|
|
||||||
|
|
||||||
if(AA) {
|
|
||||||
aalineRGBA(game.screen, prevX, prevY, currentX, currentY,colorVal, colorVal, colorVal, SDL_ALPHA_OPAQUE);
|
|
||||||
} else {
|
|
||||||
thickLineRGBA(game.screen, prevX, prevY, currentX, currentY, 2, colorVal, colorVal, colorVal, SDL_ALPHA_OPAQUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void drawGrid()
|
|
||||||
{
|
|
||||||
int p1km = screenDist(1.0);
|
|
||||||
int p10km = screenDist(10.0);
|
|
||||||
int p100km = screenDist(100.0);
|
|
||||||
|
|
||||||
hlineRGBA (game.screen, 0, SCREEN_WIDTH, SCREEN_HEIGHT>>1, 127, 127, 127, SDL_ALPHA_OPAQUE);
|
|
||||||
vlineRGBA (game.screen, SCREEN_WIDTH>>1, 0, SCREEN_HEIGHT, 127, 127, 127, SDL_ALPHA_OPAQUE);
|
|
||||||
|
|
||||||
if(AA) {
|
|
||||||
aacircleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p1km, 249,38,114, SDL_ALPHA_OPAQUE);
|
|
||||||
aacircleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p10km, 187,29,86, SDL_ALPHA_OPAQUE);
|
|
||||||
aacircleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p100km, 125,19,57, SDL_ALPHA_OPAQUE);
|
|
||||||
} else {
|
|
||||||
circleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p1km, 249,38,114, SDL_ALPHA_OPAQUE);
|
|
||||||
circleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p10km, 187,29,86, SDL_ALPHA_OPAQUE);
|
|
||||||
circleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p100km, 125,19,57, SDL_ALPHA_OPAQUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
drawString("1km", (SCREEN_WIDTH>>1) + p1km + 5, (SCREEN_HEIGHT>>1) + 5, game.font, setColor(249,38,114));
|
|
||||||
drawString("10km", (SCREEN_WIDTH>>1) + p10km + 5, (SCREEN_HEIGHT>>1) + 5, game.font, setColor(187,29,86));
|
|
||||||
drawString("100km", (SCREEN_WIDTH>>1) + p100km + 5, (SCREEN_HEIGHT>>1) + 5, game.font, setColor(125,19,57));
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawGeography() {
|
|
||||||
int x1, y1, x2, y2;
|
|
||||||
for(int i=1; i<mapPoints_count/2; i++) {
|
|
||||||
|
|
||||||
if(!mapPoints_relative[i * 2] || !mapPoints_relative[(i - 1) * 2 + 1] || !mapPoints_relative[i * 2] || !mapPoints_relative[i * 2 + 1]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
screenCoords(&x1, &y1, mapPoints_relative[(i - 1) * 2], -mapPoints_relative[(i - 1) * 2 + 1]);
|
|
||||||
screenCoords(&x2, &y2, mapPoints_relative[i * 2], -mapPoints_relative[i * 2 + 1]);
|
|
||||||
|
|
||||||
if(outOfBounds(x1,y1) && outOfBounds(x2,y2)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SDL_Color geoColor;
|
|
||||||
|
|
||||||
// double x1d = (double) abs(x1 - (SCREEN_WIDTH>>1));
|
|
||||||
// double y1d = (double) abs(y1 - (SCREEN_HEIGHT>>1));
|
|
||||||
|
|
||||||
// double colorDist = sqrt(x1d * x1d + y1d * y1d) / (double) SCREEN_HEIGHT;
|
|
||||||
|
|
||||||
// colorDist = (colorDist < 0.0) ? 0.0 : colorDist;
|
|
||||||
// colorDist = (colorDist > 1.0) ? 1.0 : colorDist;
|
|
||||||
|
|
||||||
// geoColor.r = (uint8_t) (colorDist * 114.0 + (1.0 - colorDist) * 166.0);
|
|
||||||
// geoColor.g = (uint8_t) (colorDist * 29.0 + (1.0 - colorDist) * 266.0);
|
|
||||||
// geoColor.b = (uint8_t) (colorDist * 240.0 + (1.0 - colorDist) * 16.0);
|
|
||||||
|
|
||||||
geoColor.r = 100;
|
|
||||||
geoColor.g = 0;
|
|
||||||
geoColor.b = 200;
|
|
||||||
|
|
||||||
if(AA) {
|
|
||||||
aalineRGBA(game.screen, x1, y1, x2, y2,geoColor.r,geoColor.g,geoColor.b, SDL_ALPHA_OPAQUE);
|
|
||||||
} else {
|
|
||||||
lineRGBA(game.screen, x1, y1, x2, y2,geoColor.r,geoColor.g,geoColor.b, SDL_ALPHA_OPAQUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void delay(unsigned int frameLimit)
|
|
||||||
{
|
|
||||||
unsigned int ticks = SDL_GetTicks();
|
|
||||||
|
|
||||||
if (frameLimit < ticks)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frameLimit > ticks + 16)
|
|
||||||
{
|
|
||||||
SDL_Delay(16);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SDL_Delay(frameLimit - ticks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
#include "structs.h"
|
|
||||||
|
|
||||||
Game game;
|
|
|
@ -38,7 +38,15 @@ void init(char *title)
|
||||||
|
|
||||||
SDL_ShowCursor(SDL_DISABLE);
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
|
|
||||||
game.screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 16, SDL_HWPALETTE|SDL_DOUBLEBUF);
|
#ifndef RPI
|
||||||
|
game.bigScreen = SDL_SetVideoMode(SCREEN_WIDTH * UPSCALE, SCREEN_HEIGHT * UPSCALE, 32, SDL_HWPALETTE|SDL_DOUBLEBUF);
|
||||||
|
game.screen = SDL_CreateRGBSurface(0, SCREEN_WIDTH, SCREEN_HEIGHT, 32, 0, 0, 0, 0);
|
||||||
|
#else
|
||||||
|
game.screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 16, SDL_HWPALETTE|SDL_DOUBLEBUF);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (game.screen == NULL)
|
if (game.screen == NULL)
|
||||||
{
|
{
|
||||||
|
@ -49,9 +57,9 @@ void init(char *title)
|
||||||
|
|
||||||
/* Load the font */
|
/* Load the font */
|
||||||
|
|
||||||
game.font = loadFont("Anonymous_Pro_B.ttf", 12);
|
game.font = loadFont("TerminusTTF-Bold-4.46.0.ttf", 12);
|
||||||
|
|
||||||
game.listFont = loadFont("Anonymous_Pro_B.ttf", 18);
|
game.listFont = loadFont("TerminusTTF-Bold-4.46.0.ttf", 18);
|
||||||
|
|
||||||
/* Set the screen title */
|
/* Set the screen title */
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,6 @@
|
||||||
#include "parula.h"
|
#include "parula.h"
|
||||||
#include "SDL/SDL_gfxPrimitives.h"
|
#include "SDL/SDL_gfxPrimitives.h"
|
||||||
|
|
||||||
static uint64_t mstime(void) {
|
|
||||||
struct timeval tv;
|
|
||||||
uint64_t mst;
|
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
mst = ((uint64_t)tv.tv_sec)*1000;
|
|
||||||
mst += tv.tv_usec/1000;
|
|
||||||
return mst;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Color pink = {249,38,114,255};
|
SDL_Color pink = {249,38,114,255};
|
||||||
SDL_Color blue = {102,217,239,255};
|
SDL_Color blue = {102,217,239,255};
|
||||||
SDL_Color green = {166,226,46,255};
|
SDL_Color green = {166,226,46,255};
|
||||||
|
@ -24,24 +14,16 @@ SDL_Color darkGrey = {64,64,64,255};
|
||||||
SDL_Color black = {0,0,0,255};
|
SDL_Color black = {0,0,0,255};
|
||||||
SDL_Color white = {255,255,255,255};
|
SDL_Color white = {255,255,255,255};
|
||||||
|
|
||||||
void drawList() {
|
void drawList(int rows, int top) {
|
||||||
struct aircraft *a = Modes.aircrafts;
|
struct aircraft *a = Modes.aircrafts;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
char progress;
|
char progress;
|
||||||
char spinner[4] = "|/-\\";
|
char spinner[4] = "|/-\\";
|
||||||
|
|
||||||
// Refresh screen every (MODES_INTERACTIVE_REFRESH_TIME) miliseconde
|
|
||||||
if ((mstime() - Modes.interactive_last_update) < MODES_INTERACTIVE_REFRESH_TIME)
|
|
||||||
{return;}
|
|
||||||
|
|
||||||
Modes.interactive_last_update = mstime();
|
|
||||||
|
|
||||||
progress = spinner[time(NULL)%4];
|
progress = spinner[time(NULL)%4];
|
||||||
|
|
||||||
SDL_FillRect(game.screen, NULL, 0);
|
drawStringBG(" Flight Alt(m) km/h D(km) H S ", 0, top, game.listFont, black, white);
|
||||||
|
|
||||||
drawStringBG(" Flight Alt(m) km/h D(km) H S ", 0, 0, game.listFont, black, white);
|
|
||||||
|
|
||||||
// int xstride = 10;
|
// int xstride = 10;
|
||||||
// for(int i = 0; i < 320 / xstride; i++) {
|
// for(int i = 0; i < 320 / xstride; i++) {
|
||||||
|
@ -54,7 +36,7 @@ void drawList() {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
int numNoDir = 0;
|
int numNoDir = 0;
|
||||||
while(a && (count < 10)) {
|
while(a && (count < rows)) {
|
||||||
if ((now - a->seen) < Modes.interactive_display_ttl)
|
if ((now - a->seen) < Modes.interactive_display_ttl)
|
||||||
{
|
{
|
||||||
int msgs = a->messages;
|
int msgs = a->messages;
|
||||||
|
@ -151,7 +133,7 @@ void drawList() {
|
||||||
|
|
||||||
if ((now - a->seen) > 30 ) {
|
if ((now - a->seen) > 30 ) {
|
||||||
|
|
||||||
drawString(a->flight, 0, (count + 1) * 20, game.listFont, (SDL_Color){96,96,96,255});
|
drawString(a->flight, 0, top + (count + 1) * 20, game.listFont, (SDL_Color){96,96,96,255});
|
||||||
|
|
||||||
// printf("\x1B[1;30m%-8s%5s %4s %5s %c%c %d",
|
// printf("\x1B[1;30m%-8s%5s %4s %5s %c%c %d",
|
||||||
// a->flight,
|
// a->flight,
|
||||||
|
@ -161,15 +143,15 @@ void drawList() {
|
||||||
// cLat, cLon,
|
// cLat, cLon,
|
||||||
// (int)((float)signalAverage/25.0f));
|
// (int)((float)signalAverage/25.0f));
|
||||||
} else {
|
} else {
|
||||||
drawString(a->flight, 10, (count + 1) * 20, game.listFont, pink);
|
drawString(a->flight, 10, top + (count + 1) * 20, game.listFont, pink);
|
||||||
|
|
||||||
drawString(strFl, 90, (count + 1) * 20, game.listFont, orange);
|
drawString(strFl, 90, top + (count + 1) * 20, game.listFont, orange);
|
||||||
|
|
||||||
drawString(strGs, 160, (count + 1) * 20, game.listFont, green);
|
drawString(strGs, 160, top + (count + 1) * 20, game.listFont, green);
|
||||||
|
|
||||||
drawString(strD, 210, (count + 1) * 20, game.listFont, blue);
|
drawString(strD, 210, top + (count + 1) * 20, game.listFont, blue);
|
||||||
|
|
||||||
drawString(strDir, 270, (count + 1) * 20, game.listFont, yellow);
|
drawString(strDir, 270, top + (count + 1) * 20, game.listFont, yellow);
|
||||||
|
|
||||||
// drawString(strS, 290, (count + 1) * 20, game.listFont, (SDL_Color){255,9,96,255});
|
// drawString(strS, 290, (count + 1) * 20, game.listFont, (SDL_Color){255,9,96,255});
|
||||||
|
|
||||||
|
@ -189,7 +171,4 @@ void drawList() {
|
||||||
}
|
}
|
||||||
a = a->next;
|
a = a->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Flip(game.screen);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
293
sdl1090/maps.c
293
sdl1090/maps.c
|
@ -1,32 +1,287 @@
|
||||||
|
|
||||||
#include "dump1090.h"
|
#include "dump1090.h"
|
||||||
#include "structs.h"
|
#include "structs.h"
|
||||||
|
#include "parula.h"
|
||||||
|
#include "magma.h"
|
||||||
|
#include "SDL/SDL_gfxPrimitives.h"
|
||||||
|
|
||||||
//
|
#define LOGMAXDIST 1000.0
|
||||||
// ============================= Utility functions ==========================
|
#define MAXDIST 50.0
|
||||||
//
|
|
||||||
static uint64_t mstime(void) {
|
|
||||||
struct timeval tv;
|
|
||||||
uint64_t mst;
|
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
#define AA 0
|
||||||
mst = ((uint64_t)tv.tv_sec)*1000;
|
|
||||||
mst += tv.tv_usec/1000;
|
#define MAGMA 0
|
||||||
return mst;
|
|
||||||
|
void CROSSVP(double *v, double *u, double *w)
|
||||||
|
{
|
||||||
|
v[0] = u[1]*w[2] - u[2]*(w)[1];
|
||||||
|
v[1] = u[2]*w[0] - u[0]*(w)[2];
|
||||||
|
v[2] = u[0]*w[1] - u[1]*(w)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Color setColor(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
SDL_Color out;
|
||||||
|
out.r = r;
|
||||||
|
out.g = g;
|
||||||
|
out.b = b;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Color signalToColor(int signal) {
|
||||||
|
SDL_Color planeColor;
|
||||||
|
|
||||||
|
if(signal > 127) {
|
||||||
|
signal = 127;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(signal < 0) {
|
||||||
|
planeColor = setColor(96, 96, 96);
|
||||||
|
} else {
|
||||||
|
if(MAGMA) {
|
||||||
|
planeColor = setColor(magma[signal][0], magma[signal][1], magma[signal][2]);
|
||||||
|
} else {
|
||||||
|
planeColor = setColor(parula[signal][0], parula[signal][1], parula[signal][2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return planeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
int screenDist(double d) {
|
||||||
|
|
||||||
|
double scale_factor = (SCREEN_WIDTH > SCREEN_HEIGHT) ? SCREEN_WIDTH : SCREEN_HEIGHT;
|
||||||
|
|
||||||
|
if(Modes.mapLogDist) {
|
||||||
|
return round(scale_factor* 0.5 * log(1.0+fabs(d)) / log(1.0+LOGMAXDIST));
|
||||||
|
} else {
|
||||||
|
return round(scale_factor * 0.5 * fabs(d) / MAXDIST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void screenCoords(int *outX, int *outY, double dx, double dy) {
|
||||||
|
*outX = (SCREEN_WIDTH>>1) + ((dx>0) ? 1 : -1) * screenDist(dx);
|
||||||
|
*outY = (SCREEN_HEIGHT>>1) + ((dy>0) ? 1 : -1) * screenDist(dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
int outOfBounds(int x, int y) {
|
||||||
|
if(x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT ) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawPlaneHeading(double dx, double dy, double heading, int signal, char *flight)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
screenCoords(&x, &y, dx, dy);
|
||||||
|
|
||||||
|
if(outOfBounds(x,y)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Color planeColor = signalToColor(signal);
|
||||||
|
|
||||||
|
double body = 8.0;
|
||||||
|
double wing = 6.0;
|
||||||
|
double tail = 3.0;
|
||||||
|
|
||||||
|
double vec[3];
|
||||||
|
vec[0] = sin(heading * M_PI / 180);
|
||||||
|
vec[1] = cos(heading * M_PI / 180);
|
||||||
|
vec[2] = 0;
|
||||||
|
|
||||||
|
double up[] = {0,0,1};
|
||||||
|
|
||||||
|
double out[3];
|
||||||
|
|
||||||
|
CROSSVP(out,vec,up);
|
||||||
|
|
||||||
|
int x1, x2, y1, y2;
|
||||||
|
|
||||||
|
//body
|
||||||
|
x1 = x + round(-body*vec[0]);
|
||||||
|
y1 = y + round(-body*vec[1]);
|
||||||
|
x2 = x + round(body*vec[0]);
|
||||||
|
y2 = y + round(body*vec[1]);
|
||||||
|
|
||||||
|
if(AA) {
|
||||||
|
aalineRGBA(game.screen,x1,y1,x2,y2,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
||||||
|
aatrigonRGBA(game.screen, x + round(-wing*.35*out[0]), y + round(-wing*.35*out[1]), x + round(wing*.35*out[0]), y + round(wing*.35*out[1]), x1, y1,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
||||||
|
aacircleRGBA(game.screen, x2,y2,1,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
||||||
|
} else {
|
||||||
|
thickLineRGBA(game.screen,x,y,x2,y2,2,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
||||||
|
filledTrigonRGBA(game.screen, x + round(-wing*.35*out[0]), y + round(-wing*.35*out[1]), x + round(wing*.35*out[0]), y + round(wing*.35*out[1]), x1, y1,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
||||||
|
filledCircleRGBA(game.screen, x2,y2,1,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//wing
|
||||||
|
x1 = x + round(-wing*out[0]);
|
||||||
|
y1 = y + round(-wing*out[1]);
|
||||||
|
x2 = x + round(wing*out[0]);
|
||||||
|
y2 = y + round(wing*out[1]);
|
||||||
|
|
||||||
|
if(AA) {
|
||||||
|
aatrigonRGBA(game.screen, x1, y1, x2, y2, x+round(body*.35*vec[0]), y+round(body*.35*vec[1]),planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
||||||
|
} else {
|
||||||
|
filledTrigonRGBA(game.screen, x1, y1, x2, y2, x+round(body*.35*vec[0]), y+round(body*.35*vec[1]),planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//tail
|
||||||
|
x1 = x + round(-body*.75*vec[0]) + round(-tail*out[0]);
|
||||||
|
y1 = y + round(-body*.75*vec[1]) + round(-tail*out[1]);
|
||||||
|
x2 = x + round(-body*.75*vec[0]) + round(tail*out[0]);
|
||||||
|
y2 = y + round(-body*.75*vec[1]) + round(tail*out[1]);
|
||||||
|
|
||||||
|
if(AA) {
|
||||||
|
aatrigonRGBA (game.screen, x1, y1, x2, y2, x+round(-body*.5*vec[0]), y+round(-body*.5*vec[1]),planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
||||||
|
} else {
|
||||||
|
filledTrigonRGBA (game.screen, x1, y1, x2, y2, x+round(-body*.5*vec[0]), y+round(-body*.5*vec[1]),planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawString(flight, x + 10, y + 10, game.font, planeColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawPlane(double dx, double dy, int signal)
|
||||||
|
{
|
||||||
|
|
||||||
|
int x, y;
|
||||||
|
screenCoords(&x, &y, dx, dy);
|
||||||
|
|
||||||
|
if(outOfBounds(x,y)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Color planeColor = signalToColor(signal);
|
||||||
|
|
||||||
|
int length = 3.0;
|
||||||
|
|
||||||
|
rectangleRGBA (game.screen, x - length, y - length, x+length, y + length, planeColor.r, planeColor.g, planeColor.b, SDL_ALPHA_OPAQUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawTrail(double *oldDx, double *oldDy, time_t * oldSeen, int idx) {
|
||||||
|
|
||||||
|
|
||||||
|
int currentIdx, prevIdx;
|
||||||
|
|
||||||
|
int currentX, currentY, prevX, prevY;
|
||||||
|
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
|
for(int i=0; i < (MODES_INTERACTIVE_TRAIL_LENGTH - 1); i++) {
|
||||||
|
currentIdx = (idx - i) % MODES_INTERACTIVE_TRAIL_LENGTH;
|
||||||
|
currentIdx = currentIdx < 0 ? currentIdx + MODES_INTERACTIVE_TRAIL_LENGTH : currentIdx;
|
||||||
|
prevIdx = (idx - (i + 1)) % MODES_INTERACTIVE_TRAIL_LENGTH;
|
||||||
|
prevIdx = prevIdx < 0 ? prevIdx + MODES_INTERACTIVE_TRAIL_LENGTH : prevIdx;
|
||||||
|
|
||||||
|
if(oldDx[currentIdx] == 0 || oldDy[currentIdx] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(oldDx[prevIdx] == 0 || oldDy[prevIdx] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
screenCoords(¤tX, ¤tY, oldDx[currentIdx], oldDy[currentIdx]);
|
||||||
|
|
||||||
|
screenCoords(&prevX, &prevY, oldDx[prevIdx], oldDy[prevIdx]);
|
||||||
|
|
||||||
|
if(outOfBounds(currentX,currentY)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(outOfBounds(prevX,prevY)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double age = pow(1.0 - (double)(now - oldSeen[currentIdx]) / MODES_INTERACTIVE_TRAIL_TTL, 2.2);
|
||||||
|
|
||||||
|
if(age < 0) {
|
||||||
|
age = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t colorVal = (uint8_t)floor(255.0 * age);
|
||||||
|
|
||||||
|
if(AA) {
|
||||||
|
aalineRGBA(game.screen, prevX, prevY, currentX, currentY,colorVal, colorVal, colorVal, SDL_ALPHA_OPAQUE);
|
||||||
|
} else {
|
||||||
|
//thickLineRGBA(game.screen, prevX, prevY, currentX, currentY, 2, colorVal, colorVal, colorVal, SDL_ALPHA_OPAQUE);
|
||||||
|
thickLineRGBA(game.screen, prevX, prevY, currentX, currentY, 2, colorVal, colorVal, colorVal, SDL_ALPHA_OPAQUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void drawGrid()
|
||||||
|
{
|
||||||
|
int p1km = screenDist(1.0);
|
||||||
|
int p10km = screenDist(10.0);
|
||||||
|
int p100km = screenDist(100.0);
|
||||||
|
|
||||||
|
hlineRGBA (game.screen, 0, SCREEN_WIDTH, SCREEN_HEIGHT>>1, 127, 127, 127, SDL_ALPHA_OPAQUE);
|
||||||
|
vlineRGBA (game.screen, SCREEN_WIDTH>>1, 0, SCREEN_HEIGHT, 127, 127, 127, SDL_ALPHA_OPAQUE);
|
||||||
|
|
||||||
|
if(AA) {
|
||||||
|
aacircleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p1km, 249,38,114, SDL_ALPHA_OPAQUE);
|
||||||
|
aacircleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p10km, 187,29,86, SDL_ALPHA_OPAQUE);
|
||||||
|
aacircleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p100km, 125,19,57, SDL_ALPHA_OPAQUE);
|
||||||
|
} else {
|
||||||
|
circleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p1km, 249,38,114, SDL_ALPHA_OPAQUE);
|
||||||
|
circleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p10km, 187,29,86, SDL_ALPHA_OPAQUE);
|
||||||
|
circleRGBA (game.screen, SCREEN_WIDTH>>1, SCREEN_HEIGHT>>1, p100km, 125,19,57, SDL_ALPHA_OPAQUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawString("1km", (SCREEN_WIDTH>>1) + p1km + 5, (SCREEN_HEIGHT>>1) + 5, game.font, setColor(249,38,114));
|
||||||
|
drawString("10km", (SCREEN_WIDTH>>1) + p10km + 5, (SCREEN_HEIGHT>>1) + 5, game.font, setColor(187,29,86));
|
||||||
|
drawString("100km", (SCREEN_WIDTH>>1) + p100km + 5, (SCREEN_HEIGHT>>1) + 5, game.font, setColor(125,19,57));
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawGeography() {
|
||||||
|
int x1, y1, x2, y2;
|
||||||
|
for(int i=1; i<mapPoints_count/2; i++) {
|
||||||
|
|
||||||
|
if(!mapPoints_relative[i * 2] || !mapPoints_relative[(i - 1) * 2 + 1] || !mapPoints_relative[i * 2] || !mapPoints_relative[i * 2 + 1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
screenCoords(&x1, &y1, mapPoints_relative[(i - 1) * 2], -mapPoints_relative[(i - 1) * 2 + 1]);
|
||||||
|
screenCoords(&x2, &y2, mapPoints_relative[i * 2], -mapPoints_relative[i * 2 + 1]);
|
||||||
|
|
||||||
|
if(outOfBounds(x1,y1) && outOfBounds(x2,y2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SDL_Color geoColor;
|
||||||
|
|
||||||
|
// double x1d = (double) abs(x1 - (SCREEN_WIDTH>>1));
|
||||||
|
// double y1d = (double) abs(y1 - (SCREEN_HEIGHT>>1));
|
||||||
|
|
||||||
|
// double colorDist = sqrt(x1d * x1d + y1d * y1d) / (double) SCREEN_HEIGHT;
|
||||||
|
|
||||||
|
// colorDist = (colorDist < 0.0) ? 0.0 : colorDist;
|
||||||
|
// colorDist = (colorDist > 1.0) ? 1.0 : colorDist;
|
||||||
|
|
||||||
|
// geoColor.r = (uint8_t) (colorDist * 114.0 + (1.0 - colorDist) * 166.0);
|
||||||
|
// geoColor.g = (uint8_t) (colorDist * 29.0 + (1.0 - colorDist) * 266.0);
|
||||||
|
// geoColor.b = (uint8_t) (colorDist * 240.0 + (1.0 - colorDist) * 16.0);
|
||||||
|
|
||||||
|
geoColor.r = 100;
|
||||||
|
geoColor.g = 0;
|
||||||
|
geoColor.b = 200;
|
||||||
|
|
||||||
|
if(AA) {
|
||||||
|
aalineRGBA(game.screen, x1, y1, x2, y2,geoColor.r,geoColor.g,geoColor.b, SDL_ALPHA_OPAQUE);
|
||||||
|
} else {
|
||||||
|
lineRGBA(game.screen, x1, y1, x2, y2,geoColor.r,geoColor.g,geoColor.b, SDL_ALPHA_OPAQUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawMap(void) {
|
void drawMap(void) {
|
||||||
struct aircraft *a = Modes.aircrafts;
|
struct aircraft *a = Modes.aircrafts;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
|
||||||
// Refresh screen every (MODES_INTERACTIVE_REFRESH_TIME) miliseconde
|
|
||||||
if ((mstime() - Modes.interactive_last_update) < MODES_INTERACTIVE_REFRESH_TIME)
|
|
||||||
{return;}
|
|
||||||
|
|
||||||
Modes.interactive_last_update = mstime();
|
|
||||||
|
|
||||||
SDL_FillRect(game.screen, NULL, 0);
|
|
||||||
|
|
||||||
drawGeography();
|
drawGeography();
|
||||||
|
|
||||||
drawGrid();
|
drawGrid();
|
||||||
|
@ -57,6 +312,4 @@ void drawMap(void) {
|
||||||
}
|
}
|
||||||
a = a->next;
|
a = a->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Flip(game.screen);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
typedef struct Game
|
typedef struct Game
|
||||||
{
|
{
|
||||||
SDL_Surface *screen;
|
SDL_Surface *screen;
|
||||||
|
SDL_Surface *bigScreen;
|
||||||
TTF_Font *font;
|
TTF_Font *font;
|
||||||
TTF_Font *listFont;
|
TTF_Font *listFont;
|
||||||
} Game;
|
} Game;
|
||||||
|
@ -24,15 +25,11 @@ void cleanup(void);
|
||||||
//input.c
|
//input.c
|
||||||
void getInput(void);
|
void getInput(void);
|
||||||
|
|
||||||
//draw.c
|
|
||||||
void drawGeography();
|
|
||||||
void drawPlaneHeading(double , double , double, int, char *);
|
|
||||||
void drawPlane(double , double, int);
|
|
||||||
void drawTrail(double *, double *, time_t *, int);
|
|
||||||
void drawGrid();
|
|
||||||
|
|
||||||
//mapdata.c
|
//mapdata.c
|
||||||
void initMaps();
|
void initMaps();
|
||||||
|
|
||||||
//list.c
|
//list.c
|
||||||
void drawList();
|
void drawList(int rows, int top);
|
||||||
|
|
||||||
|
//draw.c
|
||||||
|
void draw();
|
|
@ -1 +1 @@
|
||||||
0539f0c770f684b7ef79f185c195a747d2736a87
|
421a8bc720c21c7084c1bd73d4831dae5f24cf9f
|
|
@ -235,9 +235,6 @@ void showCopyright(void) {
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
int j, fd;
|
int j, fd;
|
||||||
struct client *c;
|
struct client *c;
|
||||||
|
@ -362,12 +359,7 @@ int main(int argc, char **argv) {
|
||||||
interactiveShowData();
|
interactiveShowData();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Modes.map) {
|
draw();
|
||||||
drawMap();
|
|
||||||
} else {
|
|
||||||
drawList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if ((fd == ANET_ERR) || (recv(c->fd, pk_buf, sizeof(pk_buf), MSG_PEEK | MSG_DONTWAIT) == 0)) {
|
if ((fd == ANET_ERR) || (recv(c->fd, pk_buf, sizeof(pk_buf), MSG_PEEK | MSG_DONTWAIT) == 0)) {
|
||||||
free(c);
|
free(c);
|
||||||
|
|
Loading…
Reference in a new issue