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
|
||||
improved range compared to other popular decoders.
|
||||
* Network support: TCP30003 stream (MSG5...), Raw packets, HTTP.
|
||||
* Embedded HTTP server that displays the currently detected aircrafts on
|
||||
Google Map.
|
||||
* 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).
|
||||
####Battery Options
|
||||
(https://en.wikipedia.org/wiki/List_of_battery_sizes)
|
||||
Portrait Orientation:
|
||||
18500 Batteries (18mm x 50mm), ~1000-2000mAh ea.
|
||||
The Pi Zero configuration consumes are 500mAh
|
||||
|
||||
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
|
||||
with your browser to http://localhost:8080 to see live traffic:
|
||||
####Battery Options
|
||||
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
|
||||
"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.
|
||||
####On RPI
|
||||
|
||||
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
|
||||
program that is able to output 8-bit unsigned IQ samples at 2Mhz sample rate).
|
||||
TODO
|
||||
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
|
||||
|
||||
#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 "draw.h"
|
||||
#include "parula.h"
|
||||
#include "magma.h"
|
||||
#include "SDL/SDL_gfxPrimitives.h"
|
||||
#include "structs.h"
|
||||
#include "SDL/SDL_rotozoom.h"
|
||||
|
||||
#define LOGMAXDIST 1000.0
|
||||
#define MAXDIST 50.0
|
||||
static uint64_t mstime(void) {
|
||||
struct timeval tv;
|
||||
uint64_t mst;
|
||||
|
||||
#define AA 0
|
||||
|
||||
#define MAGMA 0
|
||||
|
||||
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];
|
||||
gettimeofday(&tv, NULL);
|
||||
mst = ((uint64_t)tv.tv_sec)*1000;
|
||||
mst += tv.tv_usec/1000;
|
||||
return mst;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
void draw() {
|
||||
if ((mstime() - Modes.interactive_last_update) > MODES_INTERACTIVE_REFRESH_TIME) {
|
||||
|
||||
SDL_Color signalToColor(int signal) {
|
||||
SDL_Color planeColor;
|
||||
Modes.interactive_last_update = mstime();
|
||||
|
||||
if(signal > 127) {
|
||||
signal = 127;
|
||||
}
|
||||
SDL_FillRect(game.screen, NULL, 0);
|
||||
|
||||
if(signal < 0) {
|
||||
planeColor = setColor(96, 96, 96);
|
||||
if (Modes.map) {
|
||||
drawMap();
|
||||
//drawList(3,320);
|
||||
} 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]);
|
||||
}
|
||||
drawList(10,0);
|
||||
}
|
||||
|
||||
return planeColor;
|
||||
}
|
||||
#ifdef RPI
|
||||
SDL_Flip(game.screen);
|
||||
#else
|
||||
SDL_Rect clip;
|
||||
|
||||
int screenDist(double d) {
|
||||
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) {
|
||||
*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 = 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);
|
||||
SDL_Surface *temp = SDL_DisplayFormat(zoomSurface(game.screen, UPSCALE, UPSCALE, 0));
|
||||
|
||||
clip.x = 0;
|
||||
clip.y = 0;
|
||||
clip.w = temp->w;
|
||||
clip.h = temp->h;
|
||||
|
||||
SDL_BlitSurface(temp, &clip, game.bigScreen, 0);
|
||||
|
||||
SDL_Flip(game.bigScreen);
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
#include "structs.h"
|
||||
|
||||
Game game;
|
|
@ -38,7 +38,15 @@ void init(char *title)
|
|||
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
|
||||
#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)
|
||||
{
|
||||
|
@ -49,9 +57,9 @@ void init(char *title)
|
|||
|
||||
/* 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 */
|
||||
|
||||
|
|
|
@ -3,16 +3,6 @@
|
|||
#include "parula.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 blue = {102,217,239,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 white = {255,255,255,255};
|
||||
|
||||
void drawList() {
|
||||
void drawList(int rows, int top) {
|
||||
struct aircraft *a = Modes.aircrafts;
|
||||
time_t now = time(NULL);
|
||||
int count = 0;
|
||||
char progress;
|
||||
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];
|
||||
|
||||
SDL_FillRect(game.screen, NULL, 0);
|
||||
|
||||
drawStringBG(" Flight Alt(m) km/h D(km) H S ", 0, 0, game.listFont, black, white);
|
||||
drawStringBG(" Flight Alt(m) km/h D(km) H S ", 0, top, game.listFont, black, white);
|
||||
|
||||
// int xstride = 10;
|
||||
// for(int i = 0; i < 320 / xstride; i++) {
|
||||
|
@ -54,7 +36,7 @@ void drawList() {
|
|||
// }
|
||||
|
||||
int numNoDir = 0;
|
||||
while(a && (count < 10)) {
|
||||
while(a && (count < rows)) {
|
||||
if ((now - a->seen) < Modes.interactive_display_ttl)
|
||||
{
|
||||
int msgs = a->messages;
|
||||
|
@ -151,7 +133,7 @@ void drawList() {
|
|||
|
||||
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",
|
||||
// a->flight,
|
||||
|
@ -161,15 +143,15 @@ void drawList() {
|
|||
// cLat, cLon,
|
||||
// (int)((float)signalAverage/25.0f));
|
||||
} 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});
|
||||
|
||||
|
@ -189,7 +171,4 @@ void drawList() {
|
|||
}
|
||||
a = a->next;
|
||||
}
|
||||
|
||||
SDL_Flip(game.screen);
|
||||
|
||||
}
|
||||
|
|
293
sdl1090/maps.c
293
sdl1090/maps.c
|
@ -1,32 +1,287 @@
|
|||
|
||||
#include "dump1090.h"
|
||||
#include "structs.h"
|
||||
#include "parula.h"
|
||||
#include "magma.h"
|
||||
#include "SDL/SDL_gfxPrimitives.h"
|
||||
|
||||
//
|
||||
// ============================= Utility functions ==========================
|
||||
//
|
||||
static uint64_t mstime(void) {
|
||||
struct timeval tv;
|
||||
uint64_t mst;
|
||||
#define LOGMAXDIST 1000.0
|
||||
#define MAXDIST 50.0
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
mst = ((uint64_t)tv.tv_sec)*1000;
|
||||
mst += tv.tv_usec/1000;
|
||||
return mst;
|
||||
#define AA 0
|
||||
|
||||
#define MAGMA 0
|
||||
|
||||
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) {
|
||||
struct aircraft *a = Modes.aircrafts;
|
||||
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();
|
||||
|
||||
drawGrid();
|
||||
|
@ -57,6 +312,4 @@ void drawMap(void) {
|
|||
}
|
||||
a = a->next;
|
||||
}
|
||||
|
||||
SDL_Flip(game.screen);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
typedef struct Game
|
||||
{
|
||||
SDL_Surface *screen;
|
||||
SDL_Surface *bigScreen;
|
||||
TTF_Font *font;
|
||||
TTF_Font *listFont;
|
||||
} Game;
|
||||
|
@ -24,15 +25,11 @@ void cleanup(void);
|
|||
//input.c
|
||||
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
|
||||
void initMaps();
|
||||
|
||||
//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 j, fd;
|
||||
struct client *c;
|
||||
|
@ -362,12 +359,7 @@ int main(int argc, char **argv) {
|
|||
interactiveShowData();
|
||||
}
|
||||
|
||||
if (Modes.map) {
|
||||
drawMap();
|
||||
} else {
|
||||
drawList();
|
||||
}
|
||||
|
||||
draw();
|
||||
|
||||
if ((fd == ANET_ERR) || (recv(c->fd, pk_buf, sizeof(pk_buf), MSG_PEEK | MSG_DONTWAIT) == 0)) {
|
||||
free(c);
|
||||
|
|
Loading…
Reference in a new issue