/**************************************************************************** ** Authors: Matteo Muratori, Michele Fabbri. ** ** Official website: http://www.amanithvg.com ** ** Copyright (C) 2004-2009 Mazatech S.r.l. All rights reserved. ** ** This file is part of AmanithVG library. ** Khronos and OpenVG are trademarks of The Khronos Group Inc. ** OpenGL is a registered trademark and OpenGL ES is a trademark of ** Silicon Graphics, Inc. ** ** This file is distributed under the terms of Mazatech End-User License ** Agreement for Evaluation Purposes only as defined by Mazatech S.r.l. of ** Italy and appearing in the file LICENSE.TXT included in the packaging ** of this file. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** For any informations, please contact info@mazatech.com ** ****************************************************************************/ #include #include #include "tiger.h" #include "tiger_data.h" #include typedef enum { VG_PAINT_NONE = 0, VG_FILL_PATH = 1, VG_STROKE_PATH = 2, VG_FILLSTROKE_PATH = 3 } VGPaintMode; #define VG_TRUE 1 #define VG_FALSE 0 #define VG_NON_ZERO CAIRO_FILL_RULE_WINDING #define VG_EVEN_ODD CAIRO_FILL_RULE_EVEN_ODD #define VG_CAP_BUTT CAIRO_LINE_CAP_BUTT #define VG_CAP_ROUND CAIRO_LINE_CAP_ROUND #define VG_CAP_SQUARE CAIRO_LINE_CAP_SQUARE #define VG_JOIN_MITER CAIRO_LINE_JOIN_MITER #define VG_JOIN_ROUND CAIRO_LINE_JOIN_ROUND #define VG_JOIN_BEVEL CAIRO_LINE_JOIN_BEVEL typedef cairo_fill_rule_t VGFillRule; typedef cairo_line_cap_t VGCapStyle; typedef cairo_line_join_t VGJoinStyle; typedef float VGfloat; typedef cairo_pattern_t *VGPaint; typedef cairo_path_t *VGPath; typedef cairo_bool_t VGboolean; typedef int VGint; typedef struct { VGFillRule m_fillRule; VGPaintMode m_paintMode; VGCapStyle m_capStyle; VGJoinStyle m_joinStyle; VGfloat m_miterLimit; VGfloat m_strokeWidth; VGPaint m_fillPaint; VGPaint m_strokePaint; VGPath m_path; } PathData; typedef struct { PathData* m_paths; VGint m_numPaths; } PS; static VGboolean animationActive; static PS* tiger = NULL; static VGfloat translation[2]; static VGfloat zoomFactor, zoomSpeed; static VGfloat rotation, rotationSpeed; static VGint oldMouseX, oldMouseY; static VGint mouseButtonState; static cairo_surface_t *surface; static void resetParameters(void); #define printf(...) static PS * PS_construct(const char *commands, int commandCount, const float *points, int pointCount) { PS *ps = (PS*)calloc(sizeof(PS), 1); int p = 0; int c = 0; int i = 0; int paths = 0; int maxElements = 0; unsigned char *cmd; cairo_surface_t *dummy_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); cairo_t *cr = cairo_create(dummy_surface); (void)pointCount; while (c < commandCount) { int elements, e; c += 4; p += 8; elements = (int)points[p++]; if (elements > maxElements) maxElements = elements; for (e = 0; e < elements ; e++) { switch (commands[c]) { case 'M': p += 2; break; case 'L': p += 2; break; case 'C': p += 6; break; case 'E': break; } c++; } paths++; } ps->m_numPaths = paths; ps->m_paths = (PathData *)malloc(paths * sizeof(PathData)); cmd = (unsigned char *)malloc(maxElements); i = 0; p = 0; c = 0; while (c < commandCount) { int elements, startp, e; float color[4]; int paintMode = 0; // fill type ps->m_paths[i].m_fillRule = VG_NON_ZERO; switch (commands[c]) { case 'N': break; case 'F': ps->m_paths[i].m_fillRule = VG_NON_ZERO; paintMode |= VG_FILL_PATH; break; case 'E': ps->m_paths[i].m_fillRule = VG_EVEN_ODD; paintMode |= VG_FILL_PATH; break; } c++; // stroke switch (commands[c]) { case 'N': break; case 'S': paintMode |= VG_STROKE_PATH; break; } ps->m_paths[i].m_paintMode = (VGPaintMode)paintMode; c++; // line cap switch (commands[c]) { case 'B': ps->m_paths[i].m_capStyle = VG_CAP_BUTT; break; case 'R': ps->m_paths[i].m_capStyle = VG_CAP_ROUND; break; case 'S': ps->m_paths[i].m_capStyle = VG_CAP_SQUARE; break; } c++; // line join switch (commands[c]) { case 'M': ps->m_paths[i].m_joinStyle = VG_JOIN_MITER; break; case 'R': ps->m_paths[i].m_joinStyle = VG_JOIN_ROUND; break; case 'B': ps->m_paths[i].m_joinStyle = VG_JOIN_BEVEL; break; } c++; // the rest of stroke attributes ps->m_paths[i].m_miterLimit = points[p++]; ps->m_paths[i].m_strokeWidth = points[p++]; // paints color[0] = points[p++]; color[1] = points[p++]; color[2] = points[p++]; color[3] = 1.0f; ps->m_paths[i].m_strokePaint = cairo_pattern_create_rgb( 0.96 * color[0] + 0.02, 0.96 * color[1] + 0.02, 0.96 * color[2] + 0.02); printf("stroke-colour = %f,%f,%f\n", (double)color[0], (double)color[1], (double)color[2]); color[0] = points[p++]; color[1] = points[p++]; color[2] = points[p++]; color[3] = 1.0f; ps->m_paths[i].m_fillPaint = cairo_pattern_create_rgb( 0.96 * color[0] + 0.02, 0.96 * color[1] + 0.02, 0.96 * color[2] + 0.02); printf("fill-colour = %f,%f,%f\n", (double)color[0], (double)color[1], (double)color[2]); // read number of elements elements = (int)points[p++]; startp = p; cairo_new_path(cr); for (e = 0 ; e < elements; e++) { float const *q = points + p; switch (commands[c]) { case 'M': printf("\tM %f %f\n", q[0], q[1]); cairo_move_to(cr, q[0], q[1]); p += 2; break; case 'L': printf("\tL %f %f\n", q[0], q[1]); cairo_line_to(cr, q[0], q[1]); p += 2; break; case 'C': printf("\tC %f %f %f %f %f %f\n", q[0], q[1], q[2], q[3], q[4], q[5]); cairo_curve_to(cr, q[0], q[1], q[2], q[3], q[4], q[5]); p += 6; break; case 'E': printf("\tE\n"); cairo_close_path(cr); break; } c++; } ps->m_paths[i].m_path = cairo_copy_path(cr); i++; } cairo_destroy(cr); cairo_surface_destroy(dummy_surface); free(cmd); return ps; } static void PS_destruct(PS* ps) { int i; for (i = 0; i < ps->m_numPaths; i++) { cairo_pattern_destroy(ps->m_paths[i].m_fillPaint); cairo_pattern_destroy(ps->m_paths[i].m_strokePaint); cairo_path_destroy(ps->m_paths[i].m_path); } free(ps->m_paths); free(ps); } static void PS_render(cairo_t *cr, PS* ps) { int i; for (i = 0; i < ps->m_numPaths; i++) { cairo_set_fill_rule(cr, ps->m_paths[i].m_fillRule); cairo_new_path(cr); cairo_append_path(cr, ps->m_paths[i].m_path); if (ps->m_paths[i].m_paintMode & VG_FILL_PATH) { cairo_set_source(cr, ps->m_paths[i].m_fillPaint); cairo_fill_preserve(cr); } if (ps->m_paths[i].m_paintMode & VG_STROKE_PATH) { cairo_set_line_width(cr, ps->m_paths[i].m_strokeWidth); cairo_set_line_cap(cr, ps->m_paths[i].m_capStyle); cairo_set_line_join(cr, ps->m_paths[i].m_joinStyle); cairo_set_miter_limit(cr, ps->m_paths[i].m_miterLimit); cairo_set_source(cr, ps->m_paths[i].m_strokePaint); cairo_stroke(cr); } } } static void initApp(int windowWidth, int windowHeight) { (void)windowWidth; (void)windowHeight; resetParameters(); tiger = PS_construct(tigerCommands, tigerCommandCount, tigerPoints, tigerPointCount); mouseButtonState = 0; //vgSeti(VG_SCISSORING, VG_FALSE); //vgSeti(VG_MASKING, VG_FALSE); //vgSetfv(VG_CLEAR_COLOR, 4, clearColor); //vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); //vgLoadIdentity(); surface = cairo_image_surface_create( CAIRO_FORMAT_RGB24, windowWidth, windowHeight); } static void killApp(void) { if (tiger) PS_destruct(tiger); #if 0 cairo_surface_write_to_png(surface, "tiger.png"); #endif cairo_surface_destroy(surface); } static void changeQuality(void) {} static void toggleAnimation(void) { if (animationActive == VG_TRUE) animationActive = VG_FALSE; else animationActive = VG_TRUE; } static void resetParameters(void) { rotation = 0.0f; rotationSpeed = 0.25f; zoomFactor = 1.0f; zoomSpeed = 0.1f; translation[0] = 0.0f; translation[1] = 0.0f; animationActive = VG_FALSE; } static void deltaZoom(const VGfloat delta) { zoomFactor += delta * zoomFactor; if (zoomFactor < 0.005f) zoomFactor = 0.005f; if (zoomFactor > 650.000f) zoomFactor = 650.000f; } static void deltaTranslation(const VGfloat deltaX, const VGfloat deltaY) { translation[0] += deltaX; translation[1] += deltaY; } static void mouseLeftButtonDown(int x, int y) { oldMouseX = x; oldMouseY = y; mouseButtonState = 1; } static void mouseLeftButtonUp(int x, int y) { (void)x; (void)y; mouseButtonState = 0; } static void mouseRightButtonDown(int x, int y) { oldMouseX = x; oldMouseY = y; mouseButtonState = 2; } static void mouseRightButtonUp(int x, int y) { (void)x; (void)y; mouseButtonState = 0; } static void mouseMove(int x, int y) { if (mouseButtonState == 1) { deltaTranslation((VGfloat)(x - oldMouseX), (VGfloat)(-(y - oldMouseY))); oldMouseX = x; oldMouseY = y; } else if (mouseButtonState == 2) { VGint deltaX = x - oldMouseX; VGint deltaY = y - oldMouseY; VGint delta = (abs(deltaX) > abs(deltaY)) ? deltaX : -deltaY; oldMouseX = x; oldMouseY = y; deltaZoom(delta * 0.003f); } } static void drawScene(int windowWidth, int windowHeight) { VGfloat scale = windowHeight / tigerMaxY; cairo_t *cr = cairo_create(surface); #if 0 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); #endif if (animationActive) rotation += rotationSpeed; cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgb(cr, 0.8,0.8,0.8); cairo_paint(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); /* or SOURCE */ cairo_scale(cr, 1, -1); cairo_translate(cr, 0, -windowHeight); cairo_translate(cr, translation[0], translation[1]); cairo_translate(cr, 0.5f * (windowWidth - tigerMaxX * scale), -(VGfloat)windowHeight / 12.0f); cairo_scale(cr, scale, scale); cairo_translate(cr, tigerMaxX * 0.5f, tigerMaxY * 0.5f + 65.0f); cairo_scale(cr, zoomFactor, zoomFactor); cairo_rotate(cr, rotation); cairo_translate(cr, -tigerMaxX * 0.5f, (-tigerMaxY * 0.5f - 65.0f)); PS_render(cr, tiger); cairo_destroy(cr); } struct app cairo_tiger_app = { initApp, killApp, drawScene, mouseLeftButtonDown, mouseLeftButtonUp, mouseRightButtonDown, mouseRightButtonUp, mouseMove, changeQuality, toggleAnimation, resetParameters }; int main (int argc, char **argv) { int i; int n; if (argc > 1) n = atoi (argv[1]); else n = 100; for (i = 0; i < n; ++i) { initApp (800, 800); drawScene (800, 800); killApp (); } return 0; }