huangcm
2025-09-01 53d8e046ac1bf2ebe94f671983e3d3be059df91a
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
/*
 * \file        tp_track.c
 * \brief
 *
 * \version     1.0.0
 * \date        2012年06月27日
 * \author      James Deng <csjamesdeng@allwinnertech.com>
 *
 * Copyright (c) 2012 Allwinner Technology. All Rights Reserved.
 *
 */
 
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
 
 
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <asm-generic/ioctl.h>
 
#if defined _SUN9IW1P
#include "ion.h"
#endif
 
#if defined (_SUN8IW6P) || (_SUN50IW1P) || (_SUN50IW3P) \
   || (_SUN50IW6P) || (_SUN8IW7P)
#include "sun8iw6p_display.h"
#elif defined (_SUN8IW5P) || (_SUN9IW1P)
#include "sun8iw5p_display.h"
#elif defined (_SUN8IW15P) || (_SUN50IW10P)
#include "sunxi_display2.h"
#else
/* Universal implement */
#include "universal_display.h"
#define _UNIVERSAL_IMPLEMENT
#endif
 
#include "dragonboard.h"
#include "script.h"
#include "df_view.h"
 
#if defined (_SUN8IW6P) || (_SUN8IW5P) || (_SUN50IW1P) || (_SUN50IW3P) \
   || (_SUN8IW15P)  || (_SUN50IW6P) || (_SUN8IW7P) || (_SUN50IW10P)
#define ION_IOC_MAGIC        'I'
#define ION_IOC_ALLOC        _IOWR(ION_IOC_MAGIC, 0, struct ion_allocation_data)
#define ION_IOC_FREE        _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
#define ION_IOC_MAP        _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
#define ION_IOC_SHARE        _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
#define ION_IOC_IMPORT        _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
#define ION_IOC_SYNC        _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
#define ION_IOC_CUSTOM        _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
 
#define ION_FLAG_CACHED 1        /* mappings of this buffer should be
                      cached, ion will do cache
                      maintenance when the buffer is
                      mapped for dma */
#define ION_FLAG_CACHED_NEEDS_SYNC 2    /* mappings of this buffer will created
                      at mmap time, if this is set
                      caches must be managed manually */
#else
/* Universal implement */
#define ION_IOC_MAGIC       'I'
#define ION_IOC_ALLOC       _IOWR(ION_IOC_MAGIC, 0, struct ion_allocation_data)
#define ION_IOC_FREE        _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
#define ION_IOC_MAP         _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data)
#define ION_IOC_SHARE       _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data)
#define ION_IOC_IMPORT      _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data)
#define ION_IOC_SYNC        _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data)
#define ION_IOC_CUSTOM      _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
#define ION_FLAG_CACHED             1
#define ION_FLAG_CACHED_NEEDS_SYNC  2
#endif
 
typedef struct {
   long     start;
   long     end;
}sunxi_cache_range;
 
typedef struct {
   void *handle;
   unsigned int phys_addr;
   unsigned int size;
}sunxi_phys_data;
 
#define ION_IOC_SUNXI_FLUSH_RANGE           5
#define ION_IOC_SUNXI_FLUSH_ALL             6
#define ION_IOC_SUNXI_PHYS_ADDR             7
#define ION_IOC_SUNXI_DMA_COPY              8
 
#if defined (_SUN8IW6P) || (_SUN8IW5P) || (_SUN50IW1P) || (_SUN50IW3P) \
   || (_SUN8IW15P) || (_SUN50IW6P) || (_SUN8IW7P) || (_SUN50IW10P)
#define ION_HEAP_SYSTEM_MASK        (1 << ION_HEAP_TYPE_SYSTEM)
#define ION_HEAP_SYSTEM_CONTIG_MASK    (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
#define ION_HEAP_CARVEOUT_MASK        (1 << ION_HEAP_TYPE_CARVEOUT)
#define ION_HEAP_TYPE_DMA_MASK        (1 << ION_HEAP_TYPE_DMA)
 
 
struct ion_allocation_data {
   size_t len;
   size_t align;
   unsigned int heap_id_mask;
   unsigned int flags;
   void *handle;
};
 
struct ion_handle_data {
   void *handle;
};
 
struct ion_fd_data {
   void *handle;
   int fd;
};
 
struct ion_custom_data {
   unsigned int cmd;
   unsigned long arg;
};
 
enum ion_heap_type {
   ION_HEAP_TYPE_SYSTEM,
   ION_HEAP_TYPE_SYSTEM_CONTIG,
   ION_HEAP_TYPE_CARVEOUT,
   ION_HEAP_TYPE_CHUNK,
   ION_HEAP_TYPE_DMA,
   ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
                are at the end of this enum */
   ION_NUM_HEAPS = 16,
};
 
#else
/* Universal implement */
#define ION_HEAP_SYSTEM_MASK        (1 << ION_HEAP_TYPE_SYSTEM)
#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
#define ION_HEAP_CARVEOUT_MASK      (1 << ION_HEAP_TYPE_CARVEOUT)
#define ION_HEAP_TYPE_DMA_MASK      (1 << ION_HEAP_TYPE_DMA)
 
struct ion_allocation_data {
   size_t len;
   size_t align;
   unsigned int heap_id_mask;
   unsigned int flags;
   void *handle;
};
 
struct ion_handle_data {
   void *handle;
};
 
struct ion_fd_data {
   void *handle;
   int fd;
};
 
struct ion_custom_data {
   unsigned int cmd;
   unsigned long arg;
};
 
enum ion_heap_type {
   ION_HEAP_TYPE_SYSTEM,
   ION_HEAP_TYPE_SYSTEM_CONTIG,
   ION_HEAP_TYPE_CARVEOUT,
   ION_HEAP_TYPE_CHUNK,
   ION_HEAP_TYPE_DMA,
   ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
                are at the end of this enum */
   ION_NUM_HEAPS = 16,
};
 
#endif
 
static int disp;
//static unsigned int layer_id;
static int screen_width;
static int screen_height;
//static int fb;
static unsigned char *buffer = NULL;
 
#if defined (_SUN8IW6P) || (_SUN50IW1P) || (_SUN50IW3P)
static disp_layer_config layer_config;
#elif defined (_SUN8IW5P) || (_SUN9IW1P)
static disp_layer_info info;
#elif defined (_SUN8IW15P) || (_SUN50IW6P)  || (_SUN8IW7P) || (_SUN50IW10P)
static disp_layer_config2 layer_config;
#else
/* Universal implement */
static disp_layer_config2 layer_config;
#endif
 
static int draw_type;
static int tp_draw_color_idx;
static unsigned int tp_draw_color;
 
static int pre_x;
static int pre_y;
 
int tp_track_init(void)
{
   struct ion_allocation_data alloc_data;
   struct ion_handle_data handle_data;
   struct ion_fd_data fd_data;
   struct ion_custom_data custom_data;
   sunxi_phys_data phys_data = {0, 0, 0};
   unsigned int arg[3];
   int fd, ret = 0;
   unsigned int args[4];
   (void)phys_data;
   (void)custom_data;
 
    if ((disp = open("/dev/disp", O_RDWR)) == -1) {
        db_error("can't open /dev/disp(%s)\n", strerror(errno));
        return -1;
    }
 
    args[0] = 0;
 
#if defined (_SUN8IW6P) || (_SUN50IW1P) || (_SUN50IW3P) || (_SUN8IW15P) || (_SUN50IW6P) || (_SUN8IW7P) || (_SUN50IW10P)
    screen_width  = ioctl(disp, DISP_GET_SCN_WIDTH, args);
    screen_height = ioctl(disp, DISP_GET_SCN_HEIGHT, args);
#elif defined (_SUN8IW5P) || (_SUN9IW1P)
    screen_width  = ioctl(disp, DISP_CMD_GET_SCN_WIDTH, args);
    screen_height = ioctl(disp, DISP_CMD_GET_SCN_HEIGHT, args);
#else
    /* Universal implement */
    screen_width  = ioctl(disp, DISP_GET_SCN_WIDTH, args);
    screen_height = ioctl(disp, DISP_GET_SCN_HEIGHT, args);
#endif
 
#if 0
    pre_x = screen_width >> 1;
    pre_y = screen_height >> 1;
#else
    pre_x = -1;
    pre_y = -1;
#endif
 
   /* 1. open ion device */
   fd = open("/dev/ion", O_RDONLY);
   if(fd < 0) {
       db_error("####################err open /dev/ion\n");
       return -1;
   }
   /* 2. alloc buffer */
   alloc_data.len = screen_width * screen_height * 4;
   alloc_data.align = 0;
#if defined (_SUN8IW15P)  || (_SUN50IW6P) || (_SUN8IW7P) || (_SUN50IW10P)
   alloc_data.heap_id_mask = ION_HEAP_SYSTEM_MASK;
#else
   alloc_data.heap_id_mask = ION_HEAP_TYPE_DMA_MASK;
#endif
 
   alloc_data.flags = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
   ret = ioctl(fd, ION_IOC_ALLOC, &alloc_data);
   if(ret) {
       db_error("######################ION_IOC_ALLOC err, ret %d, handle 0x%08x\n", ret, (unsigned int)alloc_data.handle);
       goto out1;
   }
   /* 3. get dmabuf fd */
   fd_data.handle = alloc_data.handle;
   ret = ioctl(fd, ION_IOC_MAP, &fd_data);
   if(ret) {
       db_error("##########################ION_IOC_MAP err, ret %d, dmabuf fd 0x%08x\n", ret, (unsigned int)fd_data.fd);
       goto out2;
   }
   /* 4. mmap to user space */
   buffer = mmap(NULL, alloc_data.len, PROT_READ|PROT_WRITE, MAP_SHARED, fd_data.fd, 0);
   if(MAP_FAILED == buffer) {
       db_error("#####################mmap err, ret %d\n", (unsigned int)buffer);
       goto out3;
   }
   memset(buffer, 0, alloc_data.len);
 
#if !defined (_SUN8IW15P) && !defined (_SUN50IW10P) && !defined (_SUN50IW6P)  && !defined (_SUN8IW7P) && !defined(_UNIVERSAL_IMPLEMENT)
   /* optional: get buffer phys_addr */
   custom_data.cmd = ION_IOC_SUNXI_PHYS_ADDR;
   phys_data.handle = alloc_data.handle;
   custom_data.arg = (unsigned long)&phys_data;
   ret = ioctl(fd, ION_IOC_CUSTOM, &custom_data);
   if(ret) {
       db_error("###############################ION_IOC_SUNXI_PHYS_ADDR err, ret %d\n", ret);
       goto out4;
   }
   db_msg("ION_IOC_SUNXI_PHYS_ADDR succes, phys_addr 0x%08x, size 0x%08x\n", phys_data.phys_addr, phys_data.size);
#endif
 
#if defined (_SUN8IW6P) || (_SUN50IW1P) || (_SUN50IW3P)
   //设置图层参数
   memset(&layer_config, 0, sizeof(disp_layer_config));
 
   layer_config.info.mode    = LAYER_MODE_BUFFER;
   layer_config.info.fb.addr[0]       = (__u32)phys_data.phys_addr; //FB地址
   layer_config.info.fb.addr[1]          = (__u32)(layer_config.info.fb.addr[0] + screen_width * screen_height / 3 * 1);
   layer_config.info.fb.addr[2]          = (__u32)(layer_config.info.fb.addr[0] + screen_width * screen_height / 3 * 2);
 
   layer_config.info.fb.format        = DISP_FORMAT_ARGB_8888; //DISP_FORMAT_YUV420_P
   layer_config.info.fb.size[0].width    = screen_width;
   layer_config.info.fb.size[0].height      = screen_height;
 
   layer_config.info.fb.crop.x     = 0;
   layer_config.info.fb.crop.y     = 0;
   layer_config.info.fb.crop.width = (unsigned long long)screen_width << 32;
   layer_config.info.fb.crop.height= (unsigned long long)screen_height << 32;
 
   layer_config.info.screen_win.x    = 0;
   layer_config.info.screen_win.y     = 0;
   layer_config.info.screen_win.width = screen_width;
   layer_config.info.screen_win.height = screen_height;
   db_msg("########screen_width=%d\n",screen_width);
   db_msg("########screen_height=%d\n",screen_height);
 
   layer_config.info.alpha_mode       = 0; //pixel alpha
   layer_config.info.alpha_value      = 0;
   //layer_config.info.pipe             = 1;
   layer_config.channel = 2;
   layer_config.layer_id = 0;
   layer_config.enable = 1;
   layer_config.info.zorder = 2;
 
   arg[0] = 0;//screen_id
   arg[1] = (unsigned int)&layer_config;
   arg[2] = 1;
   ret = ioctl(disp, DISP_LAYER_SET_CONFIG, (void*)arg);
   if (ret != 0) {
           db_error("fail to set layer info\n");
       }
#elif defined (_SUN8IW5P) || (_SUN9IW1P)
   //设置图层参数
   memset(&info, 0, sizeof(disp_layer_info));
 
   info.mode    = DISP_LAYER_WORK_MODE_NORMAL;
   info.fb.addr[0]       = (__u32)phys_data.phys_addr; //FB地址
   info.fb.addr[1]          = (__u32)(info.fb.addr[0] + screen_width * screen_height / 3 * 1);
   info.fb.addr[2]          = (__u32)(info.fb.addr[0] + screen_width * screen_height / 3 * 2);
 
   info.fb.format        = DISP_FORMAT_ARGB_8888; //DISP_FORMAT_YUV420_P
   info.fb.size.width    = screen_width;
   info.fb.size.height      = screen_height;
 
   info.fb.src_win.x     = 0;
   info.fb.src_win.y     = 0;
   info.fb.src_win.width = screen_width;
   info.fb.src_win.height= screen_height;
 
   info.screen_win.x    = 0;
   info.screen_win.y     = 0;
   info.screen_win.width = screen_width;
   info.screen_win.height = screen_height;
 
 
   info.alpha_mode       = 0; //pixel alpha
   info.alpha_value      = 0;
   info.pipe             = 1;
 
   arg[0] = 0;//screen_id
   arg[1] = 3;//layer_id
   arg[2] = (unsigned int)&info;
   ret = ioctl(disp, DISP_CMD_LAYER_SET_INFO, (void*)arg);
   if (ret != 0) {
           db_error("fail to set layer info\n");
       }
 
   arg[0] = 0;//screen_id
   arg[1] = 3;//layer_id
   arg[2] = 0;
   ret = ioctl(disp, DISP_CMD_LAYER_ENABLE, (void*)arg);
   if (ret != 0) {
       db_error("fail to layer enable\n");
   }
#elif defined (_SUN8IW15P)  || (_SUN50IW6P) || (_SUN8IW7P) || (_SUN50IW10P)
   //设置图层参数
   memset(&layer_config, 0, sizeof(disp_layer_config2));
 
   layer_config.info.mode    = LAYER_MODE_BUFFER;
   layer_config.info.fb.fd       = fd_data.fd; //FB地址
 
   layer_config.info.fb.format        = DISP_FORMAT_ARGB_8888; //DISP_FORMAT_YUV420_P
   layer_config.info.fb.size[0].width    = screen_width;
   layer_config.info.fb.size[0].height      = screen_height;
 
   layer_config.info.fb.crop.x     = 0;
   layer_config.info.fb.crop.y     = 0;
   layer_config.info.fb.crop.width = (unsigned long long)screen_width << 32;
   layer_config.info.fb.crop.height= (unsigned long long)screen_height << 32;
 
   layer_config.info.screen_win.x    = 0;
   layer_config.info.screen_win.y     = 0;
   layer_config.info.screen_win.width = screen_width;
   layer_config.info.screen_win.height = screen_height;
   db_msg("########screen_width=%d\n",screen_width);
   db_msg("########screen_height=%d\n",screen_height);
 
   layer_config.info.alpha_mode       = 0; //pixel alpha
   layer_config.info.alpha_value      = 0;
   //layer_config.info.pipe             = 1;
   layer_config.channel = 2;
   layer_config.layer_id = 0;
   layer_config.enable = 1;
   layer_config.info.zorder = 2;
 
   arg[0] = 0;//screen_id
   arg[1] = (unsigned int)&layer_config;
   arg[2] = 1;
   ret = ioctl(disp, DISP_LAYER_SET_CONFIG2, (void*)arg);
   if (ret != 0) {
           db_error("fail to set layer info\n");
       }
#else
   /* Universal implement */
   //设置图层参数
   memset(&layer_config, 0, sizeof(disp_layer_config2));
 
   layer_config.info.mode    = LAYER_MODE_BUFFER;
   layer_config.info.fb.fd       = fd_data.fd; //FB地址
 
   layer_config.info.fb.format        = DISP_FORMAT_ARGB_8888; //DISP_FORMAT_YUV420_P
   layer_config.info.fb.size[0].width    = screen_width;
   layer_config.info.fb.size[0].height      = screen_height;
 
   layer_config.info.fb.crop.x     = 0;
   layer_config.info.fb.crop.y     = 0;
   layer_config.info.fb.crop.width = (unsigned long long)screen_width << 32;
   layer_config.info.fb.crop.height= (unsigned long long)screen_height << 32;
 
   layer_config.info.screen_win.x    = 0;
   layer_config.info.screen_win.y     = 0;
   layer_config.info.screen_win.width = screen_width;
   layer_config.info.screen_win.height = screen_height;
   db_msg("########screen_width=%d\n",screen_width);
   db_msg("########screen_height=%d\n",screen_height);
 
   layer_config.info.alpha_mode       = 0; //pixel alpha
   layer_config.info.alpha_value      = 0;
   //layer_config.info.pipe             = 1;
   layer_config.channel = 2;
   layer_config.layer_id = 0;
   layer_config.enable = 1;
   layer_config.info.zorder = 2;
 
   arg[0] = 0;//screen_id
   arg[1] = (unsigned int)&layer_config;
   arg[2] = 1;
   ret = ioctl(disp, DISP_LAYER_SET_CONFIG2, (void*)arg);
   if (ret != 0) {
       db_error("fail to set layer info\n");
   }
#endif
 
    /* get draw type */
    if (script_fetch("tp", "draw_type", &draw_type, 1) ||
            (draw_type != 0 && draw_type != 1)) {
        draw_type = 0;
    }
 
    if (script_fetch("df_view", "tp_draw_color", &tp_draw_color_idx, 1) ||
            tp_draw_color < COLOR_WHITE_IDX ||
            tp_draw_color > COLOR_BLACK_IDX) {
        tp_draw_color_idx = COLOR_WHITE_IDX;
    }
    tp_draw_color = 0xff << 24 |
                    color_table[tp_draw_color_idx].r << 16 |
                    color_table[tp_draw_color_idx].g << 8  |
                    color_table[tp_draw_color_idx].b;
    db_msg("tp draw color: 0x%x\n", tp_draw_color);
 
    return 0;
 
out4:
   /* unmmap user buffer */
   ret = munmap(buffer, alloc_data.len);
   if(ret)
       db_error("munmap err, ret %d\n", ret);
out3:
   /* close dmabuf fd */
   close(fd_data.fd);
out2:
   /* free buffer */
   handle_data.handle = alloc_data.handle;
   ret = ioctl(fd, ION_IOC_FREE, &handle_data);
   if(ret)
       db_error("ION_IOC_FREE err, ret %d\n", ret);
out1:
   /* close ion device */
   close(fd);
   return ret;
}
 
void tp_track_draw_pixel(int x, int y, unsigned int color)
{
    unsigned int *pixel;
 
    pixel = (unsigned int *)(buffer + screen_width * y * 4 + x * 4);
    *pixel = color;
}
 
void tp_track_draw_line(int x1, int y1, int x2, int y2, unsigned int color)
{
    int dx = x2 - x1;
    int dy = y2 - y1;
    int ux = ((dx > 0) << 1) - 1; // x的增量方向,取或-1
    int uy = ((dy > 0) << 1) - 1; // y的增量方向,取或-1
    int x = x1, y = y1, eps;      // eps为累加误差
 
    eps = 0;
    dx = abs(dx);
    dy = abs(dy);
    if (dx > dy)
    {
        for (x = x1; x != x2; x += ux)
        {
            tp_track_draw_pixel(x, y, color);
            eps += dy;
            if ((eps << 1) >= dx)
            {
                y += uy; eps -= dx;
            }
        }
    }
    else
    {
        for (y = y1; y != y2; y += uy)
        {
            tp_track_draw_pixel(x, y, color);
            eps += dx;
            if ((eps << 1) >= dy)
            {
                x += ux; eps -= dy;
            }
        }
    }
}
 
int tp_track_draw(int x, int y, int press)
{
    if (x < 0 || x > screen_width || y < 0 || y > screen_height)
        return -1;
 
    if (draw_type) {
        tp_track_draw_pixel(x, y, tp_draw_color);
    }
    else {
        if (press == -1) {
            if (pre_x != -1 && pre_y != -1) {
                tp_track_draw_line(pre_x, pre_y, x, y, tp_draw_color);
            }
            pre_x = pre_y = -1;
        }
        else if (press == 0) {
            pre_x = x;
            pre_y = y;
        }
        else if (press == 1) {
            if (pre_x != -1 && pre_y != -1) {
                tp_track_draw_line(pre_x, pre_y, x, y, tp_draw_color);
            }
            pre_x = x;
            pre_y = y;
        }
    }
 
    return 0;
}
 
void tp_track_start(int x, int y)
{
    pre_x = x;
    pre_y = y;
}
 
void tp_track_clear(void)
{
    memset(buffer, 0, screen_width * screen_height * 4);
}