zirafa
This commit is contained in:
@@ -0,0 +1,232 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2022/11/12.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "user_interface.h"
|
||||||
|
#include "framebuffer.h"
|
||||||
|
#include "ssd1306.h"
|
||||||
|
|
||||||
|
/* Tiny framebuffer */
|
||||||
|
#define FBW DISPLAY_W
|
||||||
|
#define FBH DISPLAY_H
|
||||||
|
|
||||||
|
#define MIN(a,b) ((a)>(b)?(b):(a))
|
||||||
|
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||||
|
|
||||||
|
static uint8_t fb[(FBH/8)*FBW];
|
||||||
|
|
||||||
|
/** Fill with a vertical pattern, 1 byte */
|
||||||
|
void fb_fill(uint8_t pattern) {
|
||||||
|
memset(fb, pattern, sizeof(fb));
|
||||||
|
}
|
||||||
|
|
||||||
|
void fb_clear() {
|
||||||
|
fb_fill(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fb_px(uint8_t x, uint8_t y, uint8_t color) {
|
||||||
|
if (x >= FBW || y >= FBH) return;
|
||||||
|
const uint8_t row = y / 8;
|
||||||
|
const uint8_t rowrem = y % 8;
|
||||||
|
const uint16_t cell = (uint16_t) x + (uint16_t) row * FBW;
|
||||||
|
if (color) {
|
||||||
|
fb[cell] |= (1 << rowrem);
|
||||||
|
} else {
|
||||||
|
fb[cell] &= ~(1 << rowrem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fb_hline(uint8_t x, uint8_t y, uint8_t w, uint8_t color) {
|
||||||
|
if (x >= FBW || y >= FBH) return;
|
||||||
|
w = MIN(FBW - x, w);
|
||||||
|
const uint8_t row = y / 8;
|
||||||
|
const uint8_t rowrem = y % 8;
|
||||||
|
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW;
|
||||||
|
for(uint8_t i = 0; i < w; i++) {
|
||||||
|
if (color) {
|
||||||
|
fb[cell] |= (1 << rowrem);
|
||||||
|
} else {
|
||||||
|
fb[cell] &= ~(1 << rowrem);
|
||||||
|
}
|
||||||
|
cell++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fb_vline(uint8_t x, uint8_t y, uint8_t h, uint8_t color) {
|
||||||
|
if (x >= FBW || y >= FBH) return;
|
||||||
|
h = MIN(FBH - y - 1, h);
|
||||||
|
const uint8_t row = y / 8;
|
||||||
|
const uint8_t rowrem = y % 8;
|
||||||
|
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW;
|
||||||
|
|
||||||
|
if (rowrem + h < 8) {
|
||||||
|
// all within one cell
|
||||||
|
uint8_t mask = (0xFF << rowrem) & (0xFF >> (h-rowrem));
|
||||||
|
if (color) {
|
||||||
|
fb[cell] |= mask;
|
||||||
|
} else {
|
||||||
|
fb[cell] &= ~mask;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// First
|
||||||
|
uint8_t mask = (0xFF << rowrem);
|
||||||
|
if (color) {
|
||||||
|
fb[cell] |= mask;
|
||||||
|
} else {
|
||||||
|
fb[cell] &= ~mask;
|
||||||
|
}
|
||||||
|
h -= rowrem;
|
||||||
|
|
||||||
|
uint8_t whole_cells = h / 8;
|
||||||
|
h -= whole_cells * 8;
|
||||||
|
for(uint8_t i = 0; i < whole_cells; i++) {
|
||||||
|
cell += FBW;
|
||||||
|
if (color) {
|
||||||
|
fb[cell] = 0xFF;
|
||||||
|
} else {
|
||||||
|
fb[cell] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// last
|
||||||
|
mask = (0xFF >> (8-h));
|
||||||
|
if (color) {
|
||||||
|
fb[cell] |= mask;
|
||||||
|
} else {
|
||||||
|
fb[cell] &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fb_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color) {
|
||||||
|
if (x >= FBW || y >= FBH) return;
|
||||||
|
w = MIN(FBW - x - 1, w);
|
||||||
|
h = MIN(FBH - y - 1, h);
|
||||||
|
const uint8_t row = y / 8;
|
||||||
|
const uint8_t rowrem = y % 8;
|
||||||
|
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW;
|
||||||
|
|
||||||
|
if (rowrem + h <= 8) {
|
||||||
|
// all within one cell
|
||||||
|
uint8_t mask = (0xFF << rowrem) & (0xFF >> (8 - (h - rowrem)));
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < w; i++) {
|
||||||
|
if (color) {
|
||||||
|
fb[cell + i] |= mask;
|
||||||
|
} else {
|
||||||
|
fb[cell + i] &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// First
|
||||||
|
uint8_t mask = (0xFF << rowrem);
|
||||||
|
for(uint8_t i = 0; i < w; i++) {
|
||||||
|
if (color) {
|
||||||
|
fb[cell + i] |= mask;
|
||||||
|
} else {
|
||||||
|
fb[cell + i] &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h -= 8 - rowrem;
|
||||||
|
|
||||||
|
uint8_t whole_cells = h / 8;
|
||||||
|
h -= whole_cells * 8;
|
||||||
|
for(uint8_t j = 0; j < whole_cells; j++) {
|
||||||
|
cell += FBW;
|
||||||
|
for(uint8_t i = 0; i < w; i++) {
|
||||||
|
if (color) {
|
||||||
|
fb[cell + i] = 0xFF;
|
||||||
|
} else {
|
||||||
|
fb[cell + i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cell += FBW;
|
||||||
|
|
||||||
|
// last
|
||||||
|
mask = (0xFF >> (8-h));
|
||||||
|
for(uint8_t i = 0; i < w; i++) {
|
||||||
|
if (color) {
|
||||||
|
fb[cell + i] |= mask;
|
||||||
|
} else {
|
||||||
|
fb[cell + i] &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fb_bitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t color) {
|
||||||
|
if (x >= FBW || y >= FBH) return;
|
||||||
|
const uint8_t w0 = w;
|
||||||
|
const uint8_t h0 = h;
|
||||||
|
w = MIN(FBW - x - 1, w);
|
||||||
|
h = MIN(FBH - y - 1, h);
|
||||||
|
const uint8_t row = y / 8;
|
||||||
|
const uint8_t rowrem = y % 8;
|
||||||
|
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW;
|
||||||
|
|
||||||
|
if (rowrem + h <= 8) {
|
||||||
|
for(uint8_t i = 0; i < w; i++) {
|
||||||
|
// all within one cell
|
||||||
|
uint8_t mask = (map[i] & (0xFF >> (8-h))) << rowrem;
|
||||||
|
if (color) {
|
||||||
|
fb[cell + i] |= mask;
|
||||||
|
} else {
|
||||||
|
fb[cell + i] &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (rowrem == 0) {
|
||||||
|
// Optimization
|
||||||
|
|
||||||
|
// First
|
||||||
|
for(uint8_t i = 0; i < w; i++) {
|
||||||
|
uint8_t mask = map[i];
|
||||||
|
if (color) {
|
||||||
|
fb[cell + i] |= mask;
|
||||||
|
} else {
|
||||||
|
fb[cell + i] &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h -= 8;
|
||||||
|
|
||||||
|
// Middle
|
||||||
|
uint8_t whole_cells = h / 8;
|
||||||
|
h -= whole_cells * 8;
|
||||||
|
for(uint8_t j = 0; j < whole_cells; j++) {
|
||||||
|
cell += FBW;
|
||||||
|
for(uint8_t i = 0; i < w; i++) {
|
||||||
|
uint8_t mask = map[i + (j+1)*w0];
|
||||||
|
if (color) {
|
||||||
|
fb[cell + i] |= mask;
|
||||||
|
} else {
|
||||||
|
fb[cell + i] &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// last
|
||||||
|
cell += FBW;
|
||||||
|
|
||||||
|
// last
|
||||||
|
for(uint8_t i = 0; i < w; i++) {
|
||||||
|
uint8_t mask = map[i + (whole_cells+1)*w0] & (0xFF >> (8-h));
|
||||||
|
if (color) {
|
||||||
|
fb[cell + i] |= mask;
|
||||||
|
} else {
|
||||||
|
fb[cell + i] &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// TODO wild combination, unaligned multi-row
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fb_blit() {
|
||||||
|
ssd1306_drawBuffer(0, 0, FBW, FBH, fb);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2022/11/12.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef FRAMEBUFFER_H
|
||||||
|
#define FRAMEBUFFER_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void fb_fill(uint8_t pattern);
|
||||||
|
void fb_clear(void);
|
||||||
|
void fb_px(uint8_t x, uint8_t y, uint8_t color);
|
||||||
|
void fb_hline(uint8_t x, uint8_t y, uint8_t w, uint8_t color);
|
||||||
|
void fb_vline(uint8_t x, uint8_t y, uint8_t h, uint8_t color);
|
||||||
|
void fb_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color);
|
||||||
|
void fb_bitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t color);
|
||||||
|
void fb_blit(void);
|
||||||
|
|
||||||
|
#endif //FRAMEBUFFER_H
|
||||||
+92
-165
@@ -6,175 +6,104 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "ssd1306.h"
|
#include "ssd1306.h"
|
||||||
#include "user_interface.h"
|
#include "user_interface.h"
|
||||||
|
#include "framebuffer.h"
|
||||||
|
|
||||||
/* Tiny framebuffer */
|
void show_loading_screen(uint8_t progress_percent, bool clear) {
|
||||||
#define FBW DISPLAY_W
|
|
||||||
#define FBH DISPLAY_H
|
|
||||||
|
|
||||||
#define MIN(a,b) ((a)>(b)?(b):(a))
|
|
||||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
|
||||||
|
|
||||||
static uint8_t fb[(FBH/8)*FBW];
|
|
||||||
|
|
||||||
/** Fill with a vertical pattern, 1 byte */
|
|
||||||
void fb_fill(uint8_t pattern) {
|
|
||||||
memset(fb, pattern, sizeof(fb));
|
|
||||||
}
|
|
||||||
|
|
||||||
void fb_clear() {
|
|
||||||
fb_fill(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fb_px(uint8_t x, uint8_t y, uint8_t color) {
|
|
||||||
if (x >= FBW || y >= FBH) return;
|
|
||||||
const uint8_t row = y / 8;
|
|
||||||
const uint8_t rowrem = y % 8;
|
|
||||||
const uint16_t cell = (uint16_t) x + (uint16_t) row * FBW;
|
|
||||||
if (color) {
|
|
||||||
fb[cell] |= (1 << rowrem);
|
|
||||||
} else {
|
|
||||||
fb[cell] &= ~(1 << rowrem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void fb_hline(uint8_t x, uint8_t y, uint8_t w, uint8_t color) {
|
|
||||||
if (x >= FBW || y >= FBH) return;
|
|
||||||
w = MIN(FBW - x, w);
|
|
||||||
const uint8_t row = y / 8;
|
|
||||||
const uint8_t rowrem = y % 8;
|
|
||||||
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW;
|
|
||||||
for(uint8_t i = 0; i < w; i++) {
|
|
||||||
if (color) {
|
|
||||||
fb[cell] |= (1 << rowrem);
|
|
||||||
} else {
|
|
||||||
fb[cell] &= ~(1 << rowrem);
|
|
||||||
}
|
|
||||||
cell++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void fb_vline(uint8_t x, uint8_t y, uint8_t h, uint8_t color) {
|
|
||||||
if (x >= FBW || y >= FBH) return;
|
|
||||||
h = MIN(FBH - y - 1, h);
|
|
||||||
const uint8_t row = y / 8;
|
|
||||||
const uint8_t rowrem = y % 8;
|
|
||||||
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW;
|
|
||||||
|
|
||||||
if (rowrem + h < 8) {
|
|
||||||
// all within one cell
|
|
||||||
uint8_t mask = (0xFF << rowrem) & (0xFF >> (h-rowrem));
|
|
||||||
if (color) {
|
|
||||||
fb[cell] |= mask;
|
|
||||||
} else {
|
|
||||||
fb[cell] &= ~mask;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// First
|
|
||||||
uint8_t mask = (0xFF << rowrem);
|
|
||||||
if (color) {
|
|
||||||
fb[cell] |= mask;
|
|
||||||
} else {
|
|
||||||
fb[cell] &= ~mask;
|
|
||||||
}
|
|
||||||
h -= rowrem;
|
|
||||||
|
|
||||||
uint8_t whole_cells = h / 8;
|
|
||||||
h -= whole_cells * 8;
|
|
||||||
for(uint8_t i = 0; i < whole_cells; i++) {
|
|
||||||
cell += FBW;
|
|
||||||
if (color) {
|
|
||||||
fb[cell] = 0xFF;
|
|
||||||
} else {
|
|
||||||
fb[cell] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// last
|
|
||||||
mask = (0xFF >> (8-h));
|
|
||||||
if (color) {
|
|
||||||
fb[cell] |= mask;
|
|
||||||
} else {
|
|
||||||
fb[cell] &= ~mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void fb_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color) {
|
|
||||||
if (x >= FBW || y >= FBH) return;
|
|
||||||
w = MIN(FBW - x - 1, w);
|
|
||||||
h = MIN(FBH - y - 1, h);
|
|
||||||
const uint8_t row = y / 8;
|
|
||||||
const uint8_t rowrem = y % 8;
|
|
||||||
uint16_t cell = (uint16_t) x + (uint16_t) row * FBW;
|
|
||||||
|
|
||||||
if (rowrem + h < 8) {
|
|
||||||
// all within one cell
|
|
||||||
uint8_t mask = (0xFF << rowrem) & (0xFF >> (8 - (h - rowrem)));
|
|
||||||
|
|
||||||
for(uint8_t i = 0; i < w; i++) {
|
|
||||||
if (color) {
|
|
||||||
fb[cell + i] |= mask;
|
|
||||||
} else {
|
|
||||||
fb[cell + i] &= ~mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// First
|
|
||||||
uint8_t mask = (0xFF << rowrem);
|
|
||||||
for(uint8_t i = 0; i < w; i++) {
|
|
||||||
if (color) {
|
|
||||||
fb[cell + i] |= mask;
|
|
||||||
} else {
|
|
||||||
fb[cell + i] &= ~mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h -= 8 - rowrem;
|
|
||||||
|
|
||||||
uint8_t whole_cells = h / 8;
|
|
||||||
h -= whole_cells * 8;
|
|
||||||
for(uint8_t j = 0; j < whole_cells; j++) {
|
|
||||||
cell += FBW;
|
|
||||||
for(uint8_t i = 0; i < w; i++) {
|
|
||||||
if (color) {
|
|
||||||
fb[cell + i] = 0xFF;
|
|
||||||
} else {
|
|
||||||
fb[cell + i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cell += FBW;
|
|
||||||
|
|
||||||
// last
|
|
||||||
mask = (0xFF >> (8-h));
|
|
||||||
for(uint8_t i = 0; i < w; i++) {
|
|
||||||
if (color) {
|
|
||||||
fb[cell + i] |= mask;
|
|
||||||
} else {
|
|
||||||
fb[cell + i] &= ~mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void fb_bitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *map, uint8_t color) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void fb_blit() {
|
|
||||||
ssd1306_drawBuffer(0, 0, FBW, FBH, fb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void show_loading_screen(uint8_t progress_percent, bool clear)
|
|
||||||
{
|
|
||||||
// HACKS - GUI dev here
|
// HACKS - GUI dev here
|
||||||
|
|
||||||
fb_clear();
|
fb_clear();
|
||||||
fb_blit();
|
fb_blit();
|
||||||
|
|
||||||
|
const uint8_t icon[14] = {
|
||||||
|
0b11000011,
|
||||||
|
0b01100110,
|
||||||
|
0b01111110,
|
||||||
|
0b00111100,
|
||||||
|
0b00011000,
|
||||||
|
0b00111100,
|
||||||
|
0b01111110,
|
||||||
|
0b11111111,
|
||||||
|
0b11111111,
|
||||||
|
0b11111011,
|
||||||
|
0b11111111,
|
||||||
|
0b01111110,
|
||||||
|
0b00111100,
|
||||||
|
0b00011000,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ZIR_W 12
|
||||||
|
#define ZIR_H 3
|
||||||
|
const uint8_t zirafa[ZIR_H * ZIR_W] = {
|
||||||
|
// levo
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000, // vrsek
|
||||||
|
0b00011000,
|
||||||
|
0b00011111,
|
||||||
|
0b11111000,
|
||||||
|
0b00011111,
|
||||||
|
0b00001000,
|
||||||
|
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
0b11111111,
|
||||||
|
0b00000000,
|
||||||
|
0b00000000,
|
||||||
|
|
||||||
|
0b00010000,
|
||||||
|
0b00001000,
|
||||||
|
0b11111000,
|
||||||
|
0b00011000,
|
||||||
|
0b11111000, // spodek
|
||||||
|
0b00011000,
|
||||||
|
0b00011000,
|
||||||
|
0b00011000,
|
||||||
|
0b11111000,
|
||||||
|
0b00011111,
|
||||||
|
0b11111000,
|
||||||
|
0b00000000,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
int a = 10;
|
||||||
|
int b = 40;
|
||||||
|
for (;;) {
|
||||||
|
fb_bitmap(a, 0, ZIR_W, ZIR_H*8, zirafa, 0);
|
||||||
|
fb_bitmap(b, 16, 14, 8, icon, 0);
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
if(a>127) {
|
||||||
|
a = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b>127) {
|
||||||
|
b = 0;
|
||||||
|
}
|
||||||
|
fb_bitmap(a, 0, ZIR_W, ZIR_H*8, zirafa, 1);
|
||||||
|
fb_bitmap(b, 16, 14, 8, icon, 1);
|
||||||
|
|
||||||
|
fb_blit();
|
||||||
|
_delay_ms(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for(;;) {}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
int a = 0, b = 0, ai = 1, bi = 1;
|
int a = 0, b = 0, ai = 1, bi = 1;
|
||||||
int c = 50, d = 5, ci = -1, di = 1;
|
int c = 50, d = 5, ci = -1, di = 1;
|
||||||
@@ -220,8 +149,6 @@ void show_loading_screen(uint8_t progress_percent, bool clear)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(;;) {}
|
|
||||||
|
|
||||||
|
|
||||||
if (clear) {
|
if (clear) {
|
||||||
ssd1306_clearScreen();
|
ssd1306_clearScreen();
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ void __attribute__((noreturn)) main()
|
|||||||
init_user_interface();
|
init_user_interface();
|
||||||
|
|
||||||
show_loading_screen(0, true);
|
show_loading_screen(0, true);
|
||||||
|
while(1){}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
init_timebase();
|
init_timebase();
|
||||||
init_radiation();
|
init_radiation();
|
||||||
@@ -48,6 +51,8 @@ void __attribute__((noreturn)) main()
|
|||||||
shutdown_due_to_weak_battery();
|
shutdown_due_to_weak_battery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user