|
|
@ -4,6 +4,8 @@ |
|
|
|
#include <string.h> |
|
|
|
#include <string.h> |
|
|
|
#include <stdbool.h> |
|
|
|
#include <stdbool.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <wchar.h> |
|
|
|
|
|
|
|
|
|
|
|
#include <assert.h> |
|
|
|
#include <assert.h> |
|
|
|
|
|
|
|
|
|
|
|
#include <unistd.h> |
|
|
|
#include <unistd.h> |
|
|
@ -24,8 +26,6 @@ |
|
|
|
#define F32EPS 1e-5f |
|
|
|
#define F32EPS 1e-5f |
|
|
|
#define MAX_CONTOURS 16 |
|
|
|
#define MAX_CONTOURS 16 |
|
|
|
|
|
|
|
|
|
|
|
#define PER_PIXEL 0 |
|
|
|
|
|
|
|
#define PER_ROW 0 |
|
|
|
|
|
|
|
#define DEBUG_SHOW_POINTS 0 |
|
|
|
#define DEBUG_SHOW_POINTS 0 |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
@ -82,6 +82,17 @@ struct line_contour { |
|
|
|
struct line *data; |
|
|
|
struct line *data; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct intersection { |
|
|
|
|
|
|
|
f32 x; |
|
|
|
|
|
|
|
int dir; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum rgb_channel { |
|
|
|
|
|
|
|
RED = 0x000000FF, |
|
|
|
|
|
|
|
GREEN = 0x0000FF00, |
|
|
|
|
|
|
|
BLUE = 0x00FF0000, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct font_buffer { |
|
|
|
struct font_buffer { |
|
|
|
u8 *data; |
|
|
|
u8 *data; |
|
|
|
u64 offset; |
|
|
|
u64 offset; |
|
|
@ -139,6 +150,8 @@ struct head_table { |
|
|
|
struct hhea_table { |
|
|
|
struct hhea_table { |
|
|
|
int ascent; |
|
|
|
int ascent; |
|
|
|
int descent; |
|
|
|
int descent; |
|
|
|
|
|
|
|
int line_gap; |
|
|
|
|
|
|
|
int max_advance; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct glyph_point { |
|
|
|
struct glyph_point { |
|
|
@ -218,28 +231,26 @@ round_f32(f32 v) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
static int |
|
|
|
scanline_intersects_line(f32 x, f32 y, struct v2f p0, struct v2f p1, f32 lasty) |
|
|
|
scanline_intersects_line(f32 y, struct v2f p0, struct v2f p1, f32 lasty, f32 *vx) |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool goes_up = (p0.y > p1.y); |
|
|
|
bool goes_up = (p0.y > p1.y); |
|
|
|
f32 t1 = (y - p0.y) / (p1.y - p0.y); /* NOTE(aolo2): no horizontal lines by design */ |
|
|
|
f32 t1 = (y - p0.y) / (p1.y - p0.y); /* NOTE(aolo2): no horizontal lines by design */ |
|
|
|
|
|
|
|
|
|
|
|
if (t1 == 0) { |
|
|
|
if (t1 == 0) { |
|
|
|
f32 x1 = p0.x + (p1.x - p0.x) * t1; |
|
|
|
f32 x1 = p0.x + (p1.x - p0.x) * t1; |
|
|
|
if (x1 > x) { |
|
|
|
|
|
|
|
if ((lasty < p0.y) && (p0.y > p1.y)) return(0); |
|
|
|
if ((lasty < p0.y) && (p0.y > p1.y)) return(0); |
|
|
|
if ((lasty > p0.y) && (p0.y < p1.y)) return(0); |
|
|
|
if ((lasty > p0.y) && (p0.y < p1.y)) return(0); |
|
|
|
int result = (goes_up ? 1 : -1); |
|
|
|
int result = (goes_up ? 1 : -1); |
|
|
|
|
|
|
|
*vx = x1; |
|
|
|
return(result); |
|
|
|
return(result); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (0 < t1 && t1 < 1.0f) { |
|
|
|
if (0 < t1 && t1 < 1.0f) { |
|
|
|
f32 x1 = p0.x + (p1.x - p0.x) * t1; |
|
|
|
f32 x1 = p0.x + (p1.x - p0.x) * t1; |
|
|
|
if (x1 > x) { |
|
|
|
*vx = x1; |
|
|
|
int result = (goes_up ? 1 : -1); |
|
|
|
int result = (goes_up ? 1 : -1); |
|
|
|
return(result); |
|
|
|
return(result); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return(0); |
|
|
|
return(0); |
|
|
|
} |
|
|
|
} |
|
|
@ -341,9 +352,9 @@ render_grid(int x_step, int y_step, u32 *pixels, int width, int height) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
static int |
|
|
|
intersect_glyph(struct line_contour *lines, f32 x, f32 y) |
|
|
|
intersect_glyph(struct line_contour *lines, f32 y, struct intersection *intersections) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int result = 0; |
|
|
|
int nints = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (int c = 0; c < lines->ncontours; ++c) { |
|
|
|
for (int c = 0; c < lines->ncontours; ++c) { |
|
|
|
int from = lines->from[c]; |
|
|
|
int from = lines->from[c]; |
|
|
@ -352,12 +363,18 @@ intersect_glyph(struct line_contour *lines, f32 x, f32 y) |
|
|
|
for (int i = from; i < to; ++i) { |
|
|
|
for (int i = from; i < to; ++i) { |
|
|
|
int lasti = (i > from ? i - 1 : to - 1); |
|
|
|
int lasti = (i > from ? i - 1 : to - 1); |
|
|
|
f32 lasty = lines->data[lasti].a.y; |
|
|
|
f32 lasty = lines->data[lasti].a.y; |
|
|
|
int r = scanline_intersects_line(x, y, lines->data[i].a, lines->data[i].b, lasty); |
|
|
|
f32 vx; |
|
|
|
result += r; |
|
|
|
int r = scanline_intersects_line(y, lines->data[i].a, lines->data[i].b, lasty, &vx); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (r) { |
|
|
|
|
|
|
|
intersections[nints].x = vx; |
|
|
|
|
|
|
|
intersections[nints].dir = r; |
|
|
|
|
|
|
|
++nints; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return(result); |
|
|
|
return(nints); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
static void |
|
|
@ -396,83 +413,64 @@ _D_render_glyph_points(struct glyph g, f32 scale, u32 *pixels, int width, int he |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
static void |
|
|
|
render_glyph(struct glyph g, struct line_contour *lines, |
|
|
|
sort_intersections(struct intersection *intersections, int size) |
|
|
|
struct ttf_font font, int px_size, u32 *pixels, int width, int height) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
f32 scale = (f32) px_size / ((f32) (font.hhea.ascent - font.hhea.descent)); |
|
|
|
bool swapped = true; |
|
|
|
//int npoints = g.end_pts_of_contours[g.ncontours - 1] + 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (g.advance < 0) { |
|
|
|
while (swapped) { |
|
|
|
g.advance *= -1; |
|
|
|
swapped = false; |
|
|
|
|
|
|
|
for (int i = 0; i < size - 1; ++i) { |
|
|
|
|
|
|
|
f32 x1 = intersections[i].x; |
|
|
|
|
|
|
|
f32 x2 = intersections[i + 1].x; |
|
|
|
|
|
|
|
if (x1 > x2) { |
|
|
|
|
|
|
|
struct intersection tmp = intersections[i]; |
|
|
|
|
|
|
|
intersections[i] = intersections[i + 1]; |
|
|
|
|
|
|
|
intersections[i + 1] = tmp; |
|
|
|
|
|
|
|
swapped = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int x0 = 0; // g.xmin * scale;
|
|
|
|
static void |
|
|
|
|
|
|
|
render_glyph(struct glyph g, struct line_contour *lines, |
|
|
|
int gwidth = (g.xmax - g.xmin) * scale; |
|
|
|
f32 scale, u32 *pixels, int width, int height, int at_x, int at_y) |
|
|
|
int gheight = (g.ymax - g.ymin) * scale + 1; |
|
|
|
{ |
|
|
|
|
|
|
|
int gwidth = round_f32((g.xmax - g.xmin) * scale) + 1; |
|
|
|
pixels = pixels + width * 100 + 100; |
|
|
|
int gheight = round_f32((g.ymax - g.ymin) * scale) + 1; |
|
|
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
|
|
|
|
|
for (int y = 0; y < gheight; ++y) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//u32 ncross = intersect_glyph(g, scale, x0 - 999.0f, y + 0.5f, width, intersections, &nints);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//if (ncross) {
|
|
|
|
struct intersection *intersections = malloc(lines->from[lines->ncontours] * sizeof(struct intersection)); |
|
|
|
//continue;
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int x = x0; x < x0 + gwidth; ++x) { |
|
|
|
for (int y = 0; y < gheight && (at_y + y < height); ++y) { |
|
|
|
u32 ncross = intersect_glyph(lines, x + 0.5f, y + 0.5f); |
|
|
|
u32 ncross = intersect_glyph(lines, y, intersections); |
|
|
|
if (ncross) { |
|
|
|
if (ncross) { |
|
|
|
pixels[y * width + x] = 0x00; |
|
|
|
sort_intersections(intersections, ncross); |
|
|
|
} else { |
|
|
|
|
|
|
|
pixels[y * width + x] = 0xFFFF0000; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if PER_PIXEL |
|
|
|
int state = 0; |
|
|
|
XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if PER_ROW |
|
|
|
for (int i = 0; i < ncross - 1; ++i) { |
|
|
|
XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height); |
|
|
|
struct intersection inter = intersections[i]; |
|
|
|
#endif |
|
|
|
struct intersection next_inter = intersections[i + 1]; |
|
|
|
} |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
int oversample_x = 4; |
|
|
|
|
|
|
|
int oversample_y = 4; |
|
|
|
|
|
|
|
f32 norm_x = 1.0f / (oversample_x + 1); |
|
|
|
|
|
|
|
f32 norm_y = 1.0f / (oversample_y + 1); |
|
|
|
|
|
|
|
int nints; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int y = 0; y < gheight; ++y) { |
|
|
|
state += inter.dir; |
|
|
|
for (int x = x0; x < x0 + gwidth; ++x) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int total_hits = 0; |
|
|
|
if (state != 0) { |
|
|
|
|
|
|
|
f32 x0 = inter.x; |
|
|
|
|
|
|
|
f32 x1 = next_inter.x; |
|
|
|
|
|
|
|
|
|
|
|
for (int yy = 1; yy <= oversample_y; ++yy) { |
|
|
|
for (int x = x0; x < x1; ++x) { |
|
|
|
for (int xx = 1; xx <= oversample_x; ++xx) { |
|
|
|
pixels[(y + at_y) * width + (at_x + x)] = 0x00; |
|
|
|
u32 ncross = intersect_glyph(lines, nlines, x + norm_x * xx , y + norm_y * yy); |
|
|
|
|
|
|
|
if (ncross) { |
|
|
|
|
|
|
|
++total_hits; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (total_hits) { |
|
|
|
|
|
|
|
u32 brightness = (256 - total_hits * 256 / (oversample_x * oversample_y)) * 0.99f; |
|
|
|
|
|
|
|
pixels[y * width + x] = 0xFF000000 | brightness << 16 | brightness << 8 | brightness; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
//pixels[y * width + x - 1] = 0xFFFF0000;
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if DEBUG_SHOW_POINTS |
|
|
|
#if DEBUG_SHOW_POINTS |
|
|
|
_D_render_glyph_points(g, scale, pixels, width, height); |
|
|
|
_D_render_glyph_points(g, scale, pixels, width, height); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
free(intersections); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
static void |
|
|
@ -493,11 +491,11 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
f32 x1 = (gp.x - g.xmin) * scale; |
|
|
|
f32 x1 = round_f32((gp.x - g.xmin) * scale); |
|
|
|
f32 y1 = gp.y * scale; |
|
|
|
f32 y1 = round_f32(gp.y * scale); |
|
|
|
|
|
|
|
|
|
|
|
f32 x2 = (nextgp.x - g.xmin) * scale; |
|
|
|
f32 x2 = round_f32((nextgp.x - g.xmin) * scale); |
|
|
|
f32 y2 = nextgp.y * scale; |
|
|
|
f32 y2 = round_f32(nextgp.y * scale); |
|
|
|
|
|
|
|
|
|
|
|
if (nextgp.on_curve) { |
|
|
|
if (nextgp.on_curve) { |
|
|
|
if (gp.y != nextgp.y) { |
|
|
|
if (gp.y != nextgp.y) { |
|
|
@ -511,8 +509,8 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt) |
|
|
|
int nextnexti = (nexti + 1 < g.end_pts_of_contours[c] + 1 ? nexti + 1 : points_from); |
|
|
|
int nextnexti = (nexti + 1 < g.end_pts_of_contours[c] + 1 ? nexti + 1 : points_from); |
|
|
|
struct glyph_point nextnextgp = g.points[nextnexti]; |
|
|
|
struct glyph_point nextnextgp = g.points[nextnexti]; |
|
|
|
|
|
|
|
|
|
|
|
f32 x3 = (nextnextgp.x - g.xmin) * scale; |
|
|
|
f32 x3 = round_f32((nextnextgp.x - g.xmin) * scale); |
|
|
|
f32 y3 = nextnextgp.y * scale; |
|
|
|
f32 y3 = round_f32(nextnextgp.y * scale); |
|
|
|
|
|
|
|
|
|
|
|
/* P(t) = P0*t^2 + P1*2*t*(1-t) + P2*(1-t)^2 */ |
|
|
|
/* P(t) = P0*t^2 + P1*2*t*(1-t) + P2*(1-t)^2 */ |
|
|
|
f32 t_step = 1.0f / curve_segments; |
|
|
|
f32 t_step = 1.0f / curve_segments; |
|
|
@ -567,6 +565,40 @@ outline_to_lines(struct glyph g, f32 scale, struct line_contour *dest, int *cnt) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
|
|
|
render_utf_string(struct ttf_font font, int px_size, u32 *pixels, u32 width, u32 height, wchar_t *string, int at_x, int at_y) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
u32 offset_x = at_x; |
|
|
|
|
|
|
|
u32 offset_y = at_y; |
|
|
|
|
|
|
|
f32 scale = (f32) px_size / ((f32) (font.hhea.ascent - font.hhea.descent)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
u32 len = wcslen(string); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0; i < len; ++i) { |
|
|
|
|
|
|
|
u16 codepoint = string[i]; |
|
|
|
|
|
|
|
if (codepoint != ' ') { |
|
|
|
|
|
|
|
struct glyph g = get_outline(&font, codepoint); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct line_contour lines = { 0 }; |
|
|
|
|
|
|
|
int nlines = 0; |
|
|
|
|
|
|
|
outline_to_lines(g, scale, &lines, &nlines); |
|
|
|
|
|
|
|
lines.data = malloc(nlines * sizeof(struct line)); |
|
|
|
|
|
|
|
outline_to_lines(g, scale, &lines, 0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int baseline_correction = round_f32(scale * g.ymax); |
|
|
|
|
|
|
|
render_glyph(g, &lines, scale, pixels, width, height, offset_x + g.lsb * scale, offset_y - baseline_correction); |
|
|
|
|
|
|
|
offset_x += scale * g.advance; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
free(lines.data); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
offset_x += px_size / 3; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height);
|
|
|
|
|
|
|
|
//sleep(1);
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int |
|
|
|
int |
|
|
|
main(int argc, char **argv) |
|
|
|
main(int argc, char **argv) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -625,50 +657,16 @@ main(int argc, char **argv) |
|
|
|
struct ttf_font font = parse_ttf_file(argv[1], "Inter"); |
|
|
|
struct ttf_font font = parse_ttf_file(argv[1], "Inter"); |
|
|
|
printf("Loaded font\n"); |
|
|
|
printf("Loaded font\n"); |
|
|
|
|
|
|
|
|
|
|
|
//struct glyph g = get_outline(&font, 0x046C);
|
|
|
|
|
|
|
|
int codepoint = 0x0020; |
|
|
|
|
|
|
|
struct glyph g = get_outline(&font, codepoint); |
|
|
|
|
|
|
|
int nlines = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
u32 px_size = 20; |
|
|
|
|
|
|
|
u32 *pixels = hc_vram; |
|
|
|
u32 *pixels = hc_vram; |
|
|
|
int t = 0; |
|
|
|
int t = 0; |
|
|
|
|
|
|
|
|
|
|
|
f32 scale = (f32) px_size / ((f32) (font.hhea.ascent - font.hhea.descent)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct line_contour lines = { 0 }; |
|
|
|
|
|
|
|
outline_to_lines(g, scale, &lines, &nlines); |
|
|
|
|
|
|
|
lines.data = malloc(nlines * sizeof(struct line)); |
|
|
|
|
|
|
|
outline_to_lines(g, scale, &lines, 0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memset(pixels, 0xFFFFFFFF, width * height * 4); |
|
|
|
|
|
|
|
render_grid(10, 10, pixels, width, height); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (;;) { |
|
|
|
for (;;) { |
|
|
|
|
|
|
|
|
|
|
|
memset(pixels, 0xFFFFFFFF, width * height * 4); |
|
|
|
memset(pixels, 0xFFFFFFFF, width * height * 4); |
|
|
|
render_grid(10, 10, pixels, width, height); |
|
|
|
render_utf_string(font, 32, pixels, width, height, L"Привет, батя! Как поживаешь? Hello, Batya. Wazzaaap", 100, 100); |
|
|
|
render_glyph(g, &lines, font, px_size, pixels, width, height); |
|
|
|
render_utf_string(font, 32, pixels, width, height, L"QQQQqqqqq", 100, 200); |
|
|
|
XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
|
|
|
|
|
//printf("%d\n", px_size);
|
|
|
|
|
|
|
|
++px_size; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scale = (f32) px_size / ((f32) (font.hhea.ascent - font.hhea.descent)); |
|
|
|
XPutImage(display, window, default_gc, xwindow_buffer, 0, 0, 0, 0, width, height); |
|
|
|
free(lines.data); |
|
|
|
|
|
|
|
lines.data = 0; |
|
|
|
|
|
|
|
outline_to_lines(g, scale, &lines, &nlines); |
|
|
|
|
|
|
|
lines.data = malloc(nlines * sizeof(struct line)); |
|
|
|
|
|
|
|
outline_to_lines(g, scale, &lines, 0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (px_size > 200) { |
|
|
|
|
|
|
|
++codepoint; |
|
|
|
|
|
|
|
g = get_outline(&font, codepoint); |
|
|
|
|
|
|
|
printf("Loaded codepoint %#x\n", codepoint); |
|
|
|
|
|
|
|
px_size = 20; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//sleep(1);
|
|
|
|
//sleep(1);
|
|
|
|
|
|
|
|
|
|
|
|