From 650f358ec1a1500bdace344ecf0682282a8d3643 Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Mar 15 2020 10:20:56 +0000 Subject: tint --- diff --git a/helianthus/drawing.c b/helianthus/drawing.c index 89cf385..ba5e348 100644 --- a/helianthus/drawing.c +++ b/helianthus/drawing.c @@ -175,16 +175,18 @@ void text(const char *text, double x, double y) { cairo_restore(cr); } -void heliDrawingPrepareFrame() { - resetPath(); - cairo_t *cr = heliCairo; - if (!cr) return; +void heliDrawingClearFrame(cairo_t *cr) { cairo_save(cr); cairo_set_source_rgba(cr, colorBack[0], colorBack[1], colorBack[2], 1); cairo_paint(cr); cairo_restore(cr); } +void heliDrawingPrepareFrame() { + resetPath(); + if (heliCairo) heliDrawingClearFrame(heliCairo); +} + void heliDrawingFinish() { resetPath(); free(path); diff --git a/helianthus/main.c b/helianthus/main.c index c287d2c..d7c4f64 100644 --- a/helianthus/main.c +++ b/helianthus/main.c @@ -12,9 +12,11 @@ void init() { brick1 = createSpriteEx(200-32, 200+64, 64, 64); spriteSetAnimation(brick1, "data/sprite/bricks.png"); + spriteSetTintColor(brick1, rgb(0, 0, 1)); brick2 = createSpriteEx(200+32, 200+64, 64, 64); spriteSetAnimation(brick2, "data/sprite/bricks.png"); + spriteSetTintColor(brick2, rgba(1, 0, 1, 0.5)); beep = createSound("data/sound/beep.ogg"); } @@ -32,7 +34,7 @@ void draw() { if (keyDown("up")) spriteSetY(ball, y - speed*dt); if (keyDown("down")) spriteSetY(ball, y + speed*dt); - spriteSetSpeedAndDirection(ball, speed, spriteGetRotation(ball)); + spriteSetSpeedAndDirection(ball, speed/2, spriteGetRotation(ball)); if (mouseWentDown("left")) soundPlay(beep, FALSE); diff --git a/helianthus/private.h b/helianthus/private.h index 95f5c0a..34b7d47 100644 --- a/helianthus/private.h +++ b/helianthus/private.h @@ -103,6 +103,7 @@ void heliSpriteFinish(); // drawing +void heliDrawingClearFrame(cairo_t *cr); void heliDrawingPrepareFrame(); void heliDrawingFinish(); diff --git a/helianthus/sprite.c b/helianthus/sprite.c index 48513dc..eb14663 100644 --- a/helianthus/sprite.c +++ b/helianthus/sprite.c @@ -306,46 +306,52 @@ static void drawSprite(cairo_t *cr, Sprite s) { cairo_surface_t *frame = s->animation ? (cairo_surface_t*)heliArrayGetValue(&s->animation->frames, s->frame) : NULL; - cairo_push_group(cr); + double a = s->tintColor[3]; + int tint = fabs(s->tintColor[0] - 1) > 1e-5 + || fabs(s->tintColor[1] - 1) > 1e-5 + || fabs(s->tintColor[2] - 1) > 1e-5; + int alpha = fabs(a) > 1e-5; + int visible = fabs(a) > 1e-5; - if (frame) { - // image - double ihw = cairo_image_surface_get_width(frame)*0.5; - double ihh = cairo_image_surface_get_height(frame)*0.5; - if (ihw > 1e-6 && ihh > 1e-6) { - cairo_save(cr); - cairo_scale(cr, hw/ihw, hh/ihh); - cairo_set_source_surface(cr, frame, -ihw, -ihh); + if (visible) { + if (tint) cairo_push_group(cr); + + if (frame) { + // image + double ihw = cairo_image_surface_get_width(frame)*0.5; + double ihh = cairo_image_surface_get_height(frame)*0.5; + if (ihw > 1e-6 && ihh > 1e-6) { + cairo_save(cr); + cairo_scale(cr, hw/ihw, hh/ihh); + cairo_set_source_surface(cr, frame, -ihw, -ihh); + if (alpha) cairo_paint_with_alpha(cr, a); else cairo_paint(cr); + cairo_restore(cr); + } + } else { + // rectangle + cairo_set_source_rgba(cr, s->shapeColor[0], s->shapeColor[1], s->shapeColor[2], s->shapeColor[3]*a); + cairo_move_to(cr, -hw, -hh); + cairo_line_to(cr, hw, -hh); + cairo_line_to(cr, hw, hh); + cairo_line_to(cr, -hw, hh); + cairo_close_path(cr); + cairo_fill(cr); + } + + if (tint) { + cairo_pattern_t *spriteGroup = cairo_pop_group(cr); + cairo_push_group(cr); + cairo_set_source(cr, spriteGroup); cairo_paint(cr); - cairo_restore(cr); + cairo_set_source_rgba(cr, s->tintColor[0], s->tintColor[1], s->tintColor[2], 1); + cairo_set_operator(cr, CAIRO_OPERATOR_MULTIPLY); + cairo_mask(cr, spriteGroup); + cairo_pop_group_to_source(cr); + cairo_paint(cr); + cairo_pattern_destroy(spriteGroup); } - } else { - // rectangle - cairo_set_source_rgba(cr, s->shapeColor[0], s->shapeColor[1], s->shapeColor[2], s->shapeColor[3]); - cairo_move_to(cr, -hw, -hh); - cairo_line_to(cr, hw, -hh); - cairo_line_to(cr, hw, hh); - cairo_line_to(cr, -hw, hh); - cairo_close_path(cr); - cairo_fill(cr); } - // tint - #warning "TODO: tint was not implemented yet" - cairo_save(cr); - cairo_set_source_rgba(cr, s->tintColor[0], s->tintColor[1], s->tintColor[2], s->tintColor[3]); - cairo_set_operator(cr, CAIRO_OPERATOR_OUT); - cairo_move_to(cr, -hw, -hh); - cairo_line_to(cr, hw, -hh); - cairo_line_to(cr, hw, hh); - cairo_line_to(cr, -hw, hh); - cairo_close_path(cr); - //cairo_fill(cr); - cairo_restore(cr); - - cairo_pop_group_to_source(cr); - cairo_paint(cr); - cairo_restore(cr); } diff --git a/helianthus/world.c b/helianthus/world.c index 68e34aa..a7b9896 100644 --- a/helianthus/world.c +++ b/helianthus/world.c @@ -15,11 +15,11 @@ static int stopped; static unsigned long long frameCount; static gint64 startTime; static gint64 currentTime; -static guint timerInterval; static Callback initCallback; static Callback drawCallback; +static cairo_surface_t *cairoSurface; static int width = 400; static int height = 400; static double frameRate = 30; @@ -140,48 +140,81 @@ double cameraGetZoom() void cameraSetZoom(double x) { cameraZoom = x > 1e-6 ? x : 1e-6; } - -static gboolean timeout(gpointer data G_GNUC_UNUSED) { - gtk_widget_queue_draw(window); +static gboolean idle(gpointer data G_GNUC_UNUSED) { if (stopped) { - gtk_window_close(GTK_WINDOW(window)); - return FALSE; - } - guint interval = (guint)round(1000/frameRate); - if (interval != timerInterval) { - timerInterval = interval; - g_timeout_add_full(G_PRIORITY_LOW, timerInterval, timeout, NULL, NULL); + if (window) { + gtk_window_close(GTK_WINDOW(window)); + window = NULL; + } return FALSE; } + gtk_widget_queue_draw(window); return TRUE; } static gboolean draw(GtkWidget *widget G_GNUC_UNUSED, cairo_t *cr, gpointer data G_GNUC_UNUSED) { - guint64 newTime = g_get_monotonic_time(); - heliCairo = cr; - - if (frameCount == 0) heliDoTests(); + int doFrame = FALSE; + if ( cairoSurface + && cairo_image_surface_get_width(cairoSurface) != width + && cairo_image_surface_get_height(cairoSurface) != height ) + { cairo_surface_destroy(cairoSurface); cairoSurface = NULL; } + if (!cairoSurface) { + cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + doFrame = TRUE; + } + + if (frameCount == 0) { + currentTime = startTime = g_get_monotonic_time(); + doFrame = TRUE; + } + double dt = 1/frameRate; - guint64 timeStep = (guint64)round(dt*1e6); - while(currentTime < newTime) { - cairo_save(cr); + gint64 timeStep = (gint64)round(dt*1e6); + gint64 newTime = g_get_monotonic_time(); + if (currentTime < newTime) + doFrame = TRUE; + + if (doFrame) { + if (frameCount == 0) heliDoTests(); + + heliCairo = cairo_create(cairoSurface); heliDrawingPrepareFrame(); if (drawCallback) drawCallback(); - cairo_restore(cr); - + cairo_surface_flush(cairoSurface); + cairo_destroy(heliCairo); + heliCairo = NULL; + currentTime += timeStep; ++frameCount; heliSpriteUpdate(dt); heliSoundUpdate(); - + heliArrayClear(&keysPressedInFrame); heliArrayClear(&keysReleasedInFrame); heliArrayClear(&buttonsPressedInFrame); heliArrayClear(&buttonsReleasedInFrame); + + if (stopped) g_idle_add_full(G_PRIORITY_DEFAULT, idle, NULL, NULL); } - - heliCairo = NULL; + + gint64 delta = newTime - currentTime - 2000000; + if (delta > 0) { + startTime += delta; + currentTime += delta; + } + + heliDrawingClearFrame(cr); + cairo_save(cr); + cairo_set_source_surface(cr, cairoSurface, 0, 0); + cairo_paint(cr); + cairo_restore(cr); + + if (!stopped) gtk_widget_queue_draw(window); + + delta = currentTime - g_get_monotonic_time(); + if (delta > 100) g_usleep(delta - 100); + return TRUE; } @@ -226,6 +259,10 @@ static gboolean handleEvent(GtkWidget *widget G_GNUC_UNUSED, GdkEvent *event, gp _mouseX = event->motion.x; _mouseY = event->motion.y; return TRUE; + case GDK_DELETE: + stopped = TRUE; + window = NULL; + break; default: break; } @@ -247,11 +284,9 @@ static void activate(GtkApplication* app, gpointer data G_GNUC_UNUSED) { gtk_widget_set_size_request(window, width, height); gtk_widget_show(window); + currentTime = startTime = 0; if (initCallback) initCallback(); - - currentTime = g_get_monotonic_time(); - timerInterval = (guint)round(1000/frameRate); - g_timeout_add_full(G_PRIORITY_LOW, timerInterval, timeout, NULL, NULL); + g_idle_add(idle, NULL); } void worldRun() { @@ -271,7 +306,10 @@ void worldRun() { heliDrawingFinish(); heliAnimationFinish(); heliSoundFinish(); - + + if (cairoSurface) cairo_surface_destroy(cairoSurface); + cairoSurface = NULL; + heliArrayDestroy(&keysPressed); heliArrayDestroy(&keysPressed); heliArrayDestroy(&keysPressedInFrame);