[cairo-commit] [cairo-www] src/cookbook

Carl Worth cworth at freedesktop.org
Tue Oct 19 10:18:13 PDT 2010


 src/cookbook/emboss.c.mdwn |  156 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 156 insertions(+)

New commits:
commit 0426278275cc36128fe89b33dceb1a0ed69f4493
Author: cubicool <cubicool at web>
Date:   Tue Oct 19 10:18:12 2010 -0700

    Adding emboss.c as a psuedo-example of Embossing (BumpMapping) in Cairo.

diff --git a/src/cookbook/emboss.c.mdwn b/src/cookbook/emboss.c.mdwn
new file mode 100644
index 0000000..bd0b858
--- /dev/null
+++ b/src/cookbook/emboss.c.mdwn
@@ -0,0 +1,156 @@
+/*
+Adapted from "Fast Embossing Effects on Raster Image Data"
+	
+	Original code by: John Schlag, <jfs at kerner.com>
+	Adapted code by: Jeremy Moles, <cubicool at gmail.com>
+
+Found in the publication "Graphics Gems IV", Academic Press, 1994
+*/
+
+
+#include <cairo.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define PIXEL_SCALE 255
+#define WIDTH_45    1
+
+/* This function will use an exisiting surface's data and create and NEW surface copy
+// of that data which has the emboss lighting algorightm applied to it. */
+static cairo_surface_t* _create_embossed_surface_from_surface(
+	cairo_surface_t* surface,
+	double           azimuth,
+	double           elevation
+) {
+	unsigned char* src    = cairo_image_surface_get_data(surface);
+	unsigned int   width  = cairo_image_surface_get_width(surface);
+	unsigned int   stride = cairo_image_surface_get_stride(surface);
+	unsigned int   height = cairo_image_surface_get_height(surface);
+	
+	cairo_surface_t* dstSurface = cairo_image_surface_create(CAIRO_FORMAT_A8, width, height);
+
+	unsigned char* dst = cairo_image_surface_get_data(dstSurface);
+
+	/* Compute the light vector from the input parameters.
+	// Normalize the length to PIXEL_SCALE for fast shading calculation. */
+	long Lx   = cos(azimuth) * cos(elevation) * PIXEL_SCALE;
+	long Ly   = sin(azimuth) * cos(elevation) * PIXEL_SCALE;
+	long Lz   = sin(elevation) * PIXEL_SCALE;
+	long Nz   = (6 * 255) / WIDTH_45;
+	long Nz2  = Nz * Nz;
+	long NzLz = Nz * Lz;
+
+	unsigned int y = 1;
+	unsigned int x = 1;
+
+	/* TODO: Would it be better to fill DST with SRC instead of the Lz value?
+	// memcpy(dst, src, stride * height); */
+	memset(dst, Lz, stride * height);
+
+	for(y = 1; y < height - 2; y++) {
+		for(x = 1; x < stride - 1; x++) {
+			unsigned int   offset = (y * stride) + x;
+			unsigned char* s1     = src + offset;
+			unsigned char* s2     = s1 + stride;
+			unsigned char* s3     = s2 + stride;
+			unsigned char  shade  = 0;
+
+			/* Compute the normal from the source. The type of the expression
+			// before the cast is compiler dependent. In some cases the sum is
+			// unsigned, in others it is signed. Ergo, cast to signed. */
+			long Nx = (long)(s1[-1] + s2[-1] + s3[-1] - s1[1] - s2[1] - s3[1]);
+			long Ny = (long)(s3[-1] + s3[0] + s3[1] - s1[-1] - s1[0] - s1[1]);
+			
+			long NdotL = Nx * Lx + Ny * Ly + NzLz;
+
+			/* Shade with distant light source. */
+			if(!Nx && !Ny) shade = Lz;
+
+			else if(NdotL < 0) shade = 0;
+
+			else shade = NdotL / sqrt(Nx * Nx + Ny * Ny + Nz2);
+			
+			*(dst + offset) = shade;
+		}
+	}
+
+	return dstSurface;
+}
+
+/* This function only supports A8 surfaces at the moment, and delegates work to the
+// similarly named function above. */
+static cairo_surface_t* create_embossed_surface_from_surface(
+	cairo_surface_t* surface,
+	double           azimuth,
+	double           elevation
+) {
+	if(cairo_image_surface_get_format(surface) != CAIRO_FORMAT_A8) {
+		printf("This example only supports embossing A8 surfaces.\n");
+		printf("It shouldn't be too wildy hard to add other format types.\n");
+
+		return 0;
+	}
+
+	else return _create_embossed_surface_from_surface(surface, azimuth, elevation);
+}
+
+int main(int argc, char** argv) {
+	unsigned int w        = 400;
+	unsigned int h        = 50;
+	unsigned int textSize = 35;
+	const char*  text     = "Cairo Emboss!!!";
+
+	cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
+	cairo_t*         cr      = cairo_create(surface);
+
+	cairo_text_extents_t extents;
+
+	if(argc != 3) {
+		printf(
+			"usage: %s <int> <int>\nThe two integral arguments passed in are "
+			"the light azimuth and elevation values, in angles.\n",
+			argv[0]
+		);
+
+		goto cleanup;
+	}
+
+	cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+	cairo_set_font_size(cr, textSize);
+	cairo_text_extents(cr, text, &extents);
+
+	cairo_move_to(
+		cr,
+		((double)(w - extents.width) / 2.0f) - extents.x_bearing,
+		(double)(h - extents.y_bearing) / 2.0f
+	);
+
+	cairo_show_text(cr, text);
+
+	cairo_surface_t* emboss = create_embossed_surface_from_surface(
+		surface, 
+		atoi(argv[1]) * (M_PI / 180.0f),
+		atoi(argv[2]) * (M_PI / 180.0f)
+	);
+
+	if(!emboss) {
+		printf("Calling the emboss function failed; cleaning up and leaving.\n");
+
+		goto cleanup;
+	}
+
+	cairo_surface_write_to_png(surface, "cairo_emboss_normal.png");
+	cairo_surface_write_to_png(emboss, "cairo_emboss_embossed.png");
+
+	printf("Wrote cairo_emboss_{normal,embossed}.png to your local directory.\n");
+
+	cairo_surface_destroy(emboss);
+
+cleanup:
+	cairo_surface_destroy(surface);
+	cairo_destroy(cr);
+	
+	return 0;
+}


More information about the cairo-commit mailing list