forked from sam-itt/sofis
-
Notifications
You must be signed in to change notification settings - Fork 0
/
elevator-gauge.c
286 lines (249 loc) · 8.69 KB
/
elevator-gauge.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/*
* SPDX-FileCopyrightText: 2021 Samuel Cuella <samuel.cuella@gmail.com>
*
* This file is part of SoFIS - an open source EFIS
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL_gpu.h>
#include "elevator-gauge.h"
#include "misc.h"
#include "res-dirs.h"
static void elevator_gauge_render(ElevatorGauge *self, Uint32 dt, RenderContext *ctx);
static void elevator_gauge_update_state(ElevatorGauge *self, Uint32 dt);
static void *elevator_gauge_dispose(ElevatorGauge *self);
static BaseGaugeOps elevator_gauge_ops = {
.render = (RenderFunc)elevator_gauge_render,
.update_state = (StateUpdateFunc)elevator_gauge_update_state,
.dispose = (DisposeFunc)elevator_gauge_dispose
};
static bool elevator_gauge_build_elevator(ElevatorGauge *self, Uint32 color);
/**
* @brief Creates a new ElevatorGauge. Calling code is responsible
* for the freeing.
*
* @see elevator_gauge_init for params and return value
*/
ElevatorGauge *elevator_gauge_new(bool marked, Location elevator_location,
PCF_Font *font, SDL_Color color,
float from, float to, float step,
int bar_max_w, int bar_max_h,
int nzones, ColorZone *zones)
{
ElevatorGauge *self;
bool rv;
self = calloc(1, sizeof(ElevatorGauge));
if(self){
rv = elevator_gauge_init(self,
marked, elevator_location,
font, color,
from, to, step,
bar_max_w, bar_max_h,
nzones, zones);
if(!rv){
return base_gauge_free(BASE_GAUGE(self));
}
}
return self;
}
/**
* @brief Inits a ElevatorGauge
*
* @param self a ElevatorGauge
* @param marked Write values corresponding to hatch marks
* @param location Which side (left or right) to put the elevator relative
* to the ruler.
* @param font The font to use for markings
* @param color the color to use when writing hatch marks and markings
* @param from start of the value range
* @param to end of the value range
* @param step increment in value units (meters, degrees, etc.) of hatch
* marks. Passing in a negative value will create only hatch marks at the
* begining/end of the range. See generic_ruler_init for a discussion of
* valid @p step values.
* @param bar_max_w Maximum width of the bar itself. It can be shrinked to
* accomodate the needed number of hatch marks.
* @param bar_max_h Maximum height of the bar itself. The gauge will be
* larger to accomadate markings (if any) and cursor(s).
* @param nzones size of the @p zones array, 0 if none
* @param zones array of ColorZones that will be used in the gauge. NULL
* for none.
* @return @p self on success, NULL on failure.
*
* @note Array is copied, caller can pass in a temporary local array.
*
* @see generic_ruler_init
* @see elevator_gauge_new
*/
ElevatorGauge *elevator_gauge_init(ElevatorGauge *self,
bool marked, Location elevator_location,
PCF_Font *font, SDL_Color color,
float from, float to, float step,
int bar_max_w, int bar_max_h,
int nzones, ColorZone *zones)
{
Location marks_location;
Location spine_location;
self->elevator_location = elevator_location;
marks_location = (self->elevator_location == Left) ? Right : Left;
spine_location = elevator_location;
generic_ruler_init(&(self->ruler),
RulerVertical, RulerGrowAgainstAxis,
from, to, step,
font, marks_location, 0,
bar_max_w, bar_max_h
);
SFV_GAUGE(self)->value = from;
self->nzones = nzones;
self->zones = calloc(self->nzones, sizeof(ColorZone));
if(!self->zones)
return NULL;
for(int i = 0; i < nzones; i++){
self->zones[i] = zones[i];
}
Uint32 fcolor;
fcolor = SDL_MapRGBA(
GENERIC_LAYER(&self->ruler)->canvas->format,
color.r, color.g, color.b, color.a
);
/*Draws the ruler*/
bool rv;
if(self->nzones > 0){
bool rv = generic_ruler_draw_zones(&self->ruler, spine_location, self->nzones, self->zones, 0.7);
if(!rv)
printf("Draw zones failed!\n");
}
rv = generic_ruler_etch_hatches(&(self->ruler), fcolor, false, true, marks_location);
if(!rv)
printf("Draw etches failed!\n");
if(marked && font){ /*Font will also be used to tag the cursors (itf)*/
rv = generic_ruler_etch_markings(&(self->ruler), marks_location, font, fcolor, 0);
if(!rv)
printf("Draw markings failed!\n");
}
generic_layer_build_texture(GENERIC_LAYER(&self->ruler));
elevator_gauge_build_elevator(self, fcolor);
if(!self->elevator)
return false;
self->ruler_rect = (SDL_Rect){
.x = self->elevator->canvas->w,
.y = 0,
.w = GENERIC_LAYER(&self->ruler)->canvas->w,
.h = GENERIC_LAYER(&self->ruler)->canvas->h
};
/* TODO: Move me as first operation to ensure that Ops are always
* set when we return NULL so that base_gauge_dispose (called by
* base_gauge_free) can properly dispose any gauge-allocated resources*/
base_gauge_init(BASE_GAUGE(self),
&elevator_gauge_ops,
GENERIC_LAYER(&self->ruler)->canvas->w + self->elevator->canvas->w,
GENERIC_LAYER(&self->ruler)->canvas->h
);
return self;
}
/**
* @brief Release resources held by @p self.
*
* @param self a ElevatorGauge
*/
static void *elevator_gauge_dispose(ElevatorGauge *self)
{
generic_ruler_dispose(&self->ruler);
if(self->elevator)
generic_layer_free(self->elevator);
if(self->zones)
free(self->zones);
return self;
}
bool elevator_gauge_set_value(ElevatorGauge *self, float value, bool animated)
{
bool rv = true;
BaseAnimation *animation;
generic_ruler_clip_value(&self->ruler, &value);
return sfv_gauge_set_value(SFV_GAUGE(self), value, animated);
}
/*
* @brief Creates the elevator bitmap
*
* INTERNAL USE ONLY
*
* TODO: Generate the cursor otf without using files
*/
static bool elevator_gauge_build_elevator(ElevatorGauge *self, Uint32 color)
{
char *filename;
int startx, endx;
if(self->elevator_location != Left && self->elevator_location != Right){
printf("Unsupported location\n");
return false;
}
filename = (self->elevator_location == Left) ? IMG_DIR"/lh-cursor10.png" : IMG_DIR"/rh-cursor10.png";
SDL_Surface *triangle = IMG_Load(filename);
if(!triangle)
return NULL;
SDL_SetSurfaceBlendMode(triangle, SDL_BLENDMODE_NONE);
self->elevator = generic_layer_new(triangle->w, self->ruler.ruler_area.h);
if(!self->elevator)
return NULL;
/*Blit triangle at top left of elevator*/
SDL_BlitSurface(triangle, NULL, self->elevator->canvas, NULL);
SDL_FreeSurface(triangle);
/*Creates the 'tail'*/
startx = (self->elevator_location == Left)
? 0
: self->elevator->canvas->w - 4;
endx = (self->elevator_location == Left)
? 4
: self->elevator->canvas->w;
generic_layer_lock(self->elevator);
Uint32 *pixels = self->elevator->canvas->pixels;
for(int y = 4; y < self->elevator->canvas->h; y++){
for(int x = startx; x < endx; x++)
pixels[y * self->elevator->canvas->w + x] = color;
}
generic_layer_unlock(self->elevator);
generic_layer_build_texture(self->elevator);
return true;
}
static void elevator_gauge_update_state(ElevatorGauge *self, Uint32 dt)
{
int yinc;
int elevator_top;
yinc = generic_ruler_get_pixel_increment_for(&self->ruler, SFV_GAUGE(self)->value);
elevator_top = SDLExt_RectLastY(&self->ruler.ruler_area) - yinc;
/*Area to copy from the whole elevator image*/
self->state.elevator_src = (SDL_Rect){
.x = 0,
.y = 0,
.w = self->elevator->canvas->w,
.h = yinc + 1
};
/*Where to put it*/
self->state.elevator_dst = (SDL_Rect){
.x = (self->elevator_location == Left)
? 0
: SDLExt_RectLastX(&self->ruler_rect) + 1,
.y = self->ruler_rect.y + elevator_top,
.w = self->state.elevator_src.w,
.h = self->state.elevator_src.h
};
}
static void elevator_gauge_render(ElevatorGauge *self, Uint32 dt, RenderContext *ctx)
{
base_gauge_blit_layer(BASE_GAUGE(self), ctx,
GENERIC_LAYER(&self->ruler),
NULL,
&self->ruler_rect
);
base_gauge_blit_layer(BASE_GAUGE(self), ctx,
self->elevator,
&self->state.elevator_src,
&self->state.elevator_dst
);
}