]> O.S.I.I.S - jp/vkvg.git/commitdiff
base implementation of recording infrastructure
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Sat, 8 Jan 2022 15:27:27 +0000 (16:27 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Tue, 11 Jan 2022 15:41:18 +0000 (16:41 +0100)
CMakeLists.txt
include/vkvg.h
src/recording/vkvg_record.c [new file with mode: 0644]
src/recording/vkvg_record_internal.c [new file with mode: 0644]
src/recording/vkvg_record_internal.h [new file with mode: 0644]
src/vkvg_context.c
src/vkvg_context_internal.h
tests/recording.c [new file with mode: 0644]

index a4067fea8b0b56d408af12fa4d21e9eab5823949..4afbcde110b2c36aa5fbe0e10f85e66cfee3d186 100644 (file)
@@ -64,6 +64,11 @@ IF (ENABLE_PROFILING)
        ADD_DEFINITIONS(${CMAKE_CXX_FLAGS} "-falign-loops  -falign-labels")
 ENDIF()
 
+OPTION(VKVG_RECORDING "enable experimental recording functions" ON)
+IF (VKVG_RECORDING)
+       ADD_DEFINITIONS (-DVKVG_RECORDING)
+ENDIF ()
+
 OPTION(VKVG_PREMULT_ALPHA "use premultiplied alpha for internal rendering" ON)
 IF (VKVG_PREMULT_ALPHA)
        ADD_DEFINITIONS (-DVKVG_PREMULT_ALPHA)
@@ -214,6 +219,11 @@ ELSE()
        LIST (APPEND VKVG_OBJ_SRC ${NSVG_SRC})
 ENDIF()
 
+IF (VKVG_RECORDING)
+       FILE(GLOB RECORDING_SRC src/recording/*.c)
+       LIST (APPEND VKVG_SRC ${RECORDING_SRC})
+ENDIF()
+
 CONFIGURE_FILE(vkvg.pc.in vkvg.pc @ONLY)
 INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/vkvg.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
 
index 4557dfbef66edc77cf876292830677354cf76a25..9fc397eb9a98774f8d76224df3900f90e0a5146e 100644 (file)
@@ -1748,6 +1748,19 @@ void vkvg_set_source_color_name (VkvgContext ctx, const char* color);
 
 /*************************************/
 
+#ifdef VKVG_RECORDING
+typedef struct _vkvg_recording_t* VkvgRecording;
+
+vkvg_public
+void                   vkvg_start_recording    (VkvgContext ctx);
+VkvgRecording  vkvg_stop_recording             (VkvgContext ctx);
+void                   vkvg_replay                             (VkvgContext ctx, VkvgRecording rec);
+uint32_t               vkvg_recording_get_count(VkvgRecording rec);
+void                   vkvg_recording_destroy  (VkvgRecording rec);
+
+
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/recording/vkvg_record.c b/src/recording/vkvg_record.c
new file mode 100644 (file)
index 0000000..18fb85a
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2022 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vkvg.h"
+#include "vkvg_context_internal.h"
+#include "vkvg_record_internal.h"
+
+#ifdef VKVG_RECORDING
+void vkvg_start_recording (VkvgContext ctx) {
+       if (ctx->status)
+               return;
+       _start_recording(ctx);
+}
+VkvgRecording vkvg_stop_recording (VkvgContext ctx) {
+       if (ctx->status)
+               return NULL;
+       return _stop_recording (ctx);
+}
+uint32_t vkvg_recording_get_count (VkvgRecording rec) {
+       if (!rec)
+               return 0;
+       return rec->commandsCount;
+}
+void vkvg_replay (VkvgContext ctx, VkvgRecording rec) {
+       if (!rec)
+               return;
+       for (uint32_t i=0; i<rec->commandsCount; i++)
+               _replay_command(ctx, rec, i);
+}
+void vkvg_recording_destroy (VkvgRecording rec) {
+       if (!rec)
+               return;
+       _destroy_recording(rec);
+}
+#endif
diff --git a/src/recording/vkvg_record_internal.c b/src/recording/vkvg_record_internal.c
new file mode 100644 (file)
index 0000000..83a6288
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2018-2022 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vkvg.h"
+#include "vkvg_record_internal.h"
+#include "vkvg_context_internal.h"
+
+#define VKVG_RECORDING_INIT_BUFFER_SIZE_TRESHOLD       64
+#define VKVG_RECORDING_INIT_BUFFER_SIZE                                1024
+#define VKVG_RECORDING_INIT_COMMANDS_COUNT                     64
+
+vkvg_recording_t* _new_recording () {
+
+       vkvg_recording_t* rec = (vkvg_recording_t*)calloc(1,sizeof (vkvg_recording_t));
+
+       rec->commandsReservedCount      = VKVG_RECORDING_INIT_COMMANDS_COUNT;
+       rec->bufferReservedSize         = VKVG_RECORDING_INIT_BUFFER_SIZE;
+       rec->commands = (vkvg_record_t*)malloc(rec->commandsReservedCount * sizeof (vkvg_record_t));
+       rec->buffer = malloc (rec->bufferReservedSize);
+
+       return rec;
+}
+void _destroy_recording (vkvg_recording_t* rec) {
+       free(rec->commands);
+       free(rec->buffer);
+       free(rec);
+}
+void _start_recording (VkvgContext ctx) {
+       if (ctx->recording)
+               _destroy_recording(ctx->recording);
+       ctx->recording = _new_recording();
+}
+vkvg_recording_t* _stop_recording (VkvgContext ctx) {
+       vkvg_recording_t* rec = ctx->recording;
+       if (!rec)
+               return NULL;
+       if (!rec->commandsCount) {
+               _destroy_recording(rec);
+               ctx->recording = NULL;
+               return NULL;
+       }
+       /*rec->buffer = realloc(rec->buffer, rec->bufferSize);
+       rec->commands = (vkvg_record_t*)realloc(rec->commands, rec->commandsCount * sizeof (vkvg_record_t));*/
+       ctx->recording = NULL;
+       return rec;
+}
+void* _ensure_recording_buffer (vkvg_recording_t* rec, size_t size) {
+       if (rec->bufferReservedSize >= rec->bufferSize - VKVG_RECORDING_INIT_BUFFER_SIZE_TRESHOLD - size) {
+               rec->bufferReservedSize += VKVG_RECORDING_INIT_BUFFER_SIZE;
+               rec->buffer = realloc(rec->buffer, rec->bufferReservedSize);
+       }
+       return rec->buffer + rec->bufferSize;
+}
+void* _advance_recording_buffer_unchecked (vkvg_recording_t* rec, size_t size) {
+       rec->bufferSize += size;
+       return rec->buffer + rec->bufferSize;
+}
+
+#define STORE_FLOATS(floatcount)                                                                               \
+       for (i=0; i<floatcount; i++) {                                                                          \
+               buff = _ensure_recording_buffer (rec, sizeof(float));                   \
+               *(float*)buff = (float)va_arg(args, double);                                    \
+               buff = _advance_recording_buffer_unchecked (rec, sizeof(float));\
+       }
+#define STORE_BOOLS(floatcount)                                                                                        \
+       for (i=0; i<floatcount; i++) {                                                                          \
+               buff = _ensure_recording_buffer (rec, sizeof(bool));                    \
+               *(bool*)buff = (bool)va_arg(args, int);                                                 \
+               buff = _advance_recording_buffer_unchecked (rec, sizeof(bool)); \
+       }
+
+
+void _record (vkvg_recording_t* rec,...) {
+       va_list args;
+       va_start(args, rec);
+
+       uint32_t cmd = va_arg(args, uint32_t);
+
+       if (rec->commandsCount == rec->commandsReservedCount) {
+               rec->commandsReservedCount += VKVG_RECORDING_INIT_COMMANDS_COUNT;
+               rec->commands = (vkvg_record_t*)realloc(rec->commands, rec->commandsReservedCount * sizeof (vkvg_record_t));
+       }
+       vkvg_record_t* r = &rec->commands[rec->commandsCount++];
+       r->cmd = cmd;
+       r->dataOffset = rec->bufferSize;
+
+       void* buff;
+
+
+       int i = 0;
+       switch (cmd) {
+       case VKVG_CMD_MOVE_TO:
+       case VKVG_CMD_LINE_TO:
+       case VKVG_CMD_REL_MOVE_TO:
+       case VKVG_CMD_REL_LINE_TO:
+               STORE_FLOATS(2);
+               break;
+       case VKVG_CMD_SAVE:
+       case VKVG_CMD_RESTORE:
+       case VKVG_CMD_NEW_PATH:
+       case VKVG_CMD_NEW_SUB_PATH:
+       case VKVG_CMD_CLOSE_PATH:
+       case VKVG_CMD_PAINT:
+       case VKVG_CMD_FILL:
+       case VKVG_CMD_STROKE:
+       case VKVG_CMD_CLIP:
+       case VKVG_CMD_CLEAR:
+       case VKVG_CMD_FILL_PRESERVE:
+       case VKVG_CMD_STROKE_PRESERVE:
+       case VKVG_CMD_CLIP_PRESERVE:
+               break;
+       case VKVG_CMD_RECTANGLE:
+       //case VKVG_CMD_ELLIPSE:
+       case VKVG_CMD_SET_SOURCE_RGBA:
+       case VKVG_CMD_QUADRATIC_TO:
+       case VKVG_CMD_REL_QUADRATIC_TO:
+               STORE_FLOATS(4);
+               break;
+       case VKVG_CMD_ARC:
+       case VKVG_CMD_ARC_NEG:
+               STORE_FLOATS(5);
+               break;
+       case VKVG_CMD_CURVE_TO:
+       case VKVG_CMD_REL_CURVE_TO:
+               STORE_FLOATS(6);
+               break;
+       case VKVG_CMD_ELLIPTICAL_ARC_TO:
+               STORE_FLOATS(5);
+               STORE_BOOLS(2);
+               break;
+       case VKVG_CMD_SET_SOURCE_RGB:
+               STORE_FLOATS(3);
+               break;
+       case VKVG_CMD_REL_ELLIPTICAL_ARC_TO:
+               STORE_FLOATS(5);
+               STORE_BOOLS(2);
+               break;
+       case VKVG_CMD_SET_SOURCE:
+               buff = _ensure_recording_buffer (rec, sizeof(VkvgPattern));
+               *(VkvgPattern*)buff = va_arg(args, VkvgPattern);
+               _advance_recording_buffer_unchecked (rec, sizeof(VkvgPattern));
+               break;
+       case VKVG_CMD_SET_SOURCE_SURFACE:
+               STORE_FLOATS(2);
+               buff = _ensure_recording_buffer (rec, sizeof(VkvgSurface));
+               *(VkvgSurface*)buff = va_arg(args, VkvgSurface);
+               _advance_recording_buffer_unchecked (rec, sizeof(VkvgSurface));
+               break;
+       }
+       va_end(args);
+}
+void _replay_command (VkvgContext ctx, VkvgRecording rec, uint32_t index) {
+       vkvg_record_t* r = &rec->commands[index];
+       float* floats = (float*)(rec->buffer + r->dataOffset);
+       switch (r->cmd) {
+       case VKVG_CMD_SAVE:
+               vkvg_save (ctx);
+               break;
+       case VKVG_CMD_RESTORE:
+               vkvg_restore (ctx);
+               break;
+       case VKVG_CMD_NEW_PATH:
+               vkvg_new_path (ctx);
+               break;
+       case VKVG_CMD_NEW_SUB_PATH:
+               vkvg_new_sub_path (ctx);
+               break;
+       case VKVG_CMD_CLOSE_PATH:
+               vkvg_close_path (ctx);
+               break;
+       case VKVG_CMD_PAINT:
+               vkvg_paint (ctx);
+               break;
+       case VKVG_CMD_FILL:
+               vkvg_fill (ctx);
+               break;
+       case VKVG_CMD_STROKE:
+               vkvg_stroke (ctx);
+               break;
+       case VKVG_CMD_CLIP:
+               vkvg_clip (ctx);
+               break;
+       case VKVG_CMD_CLEAR:
+               vkvg_clear (ctx);
+               break;
+       case VKVG_CMD_FILL_PRESERVE:
+               vkvg_fill_preserve (ctx);
+               break;
+       case VKVG_CMD_STROKE_PRESERVE:
+               vkvg_stroke_preserve (ctx);
+               break;
+       case VKVG_CMD_CLIP_PRESERVE:
+               vkvg_clip_preserve (ctx);
+               break;
+       case VKVG_CMD_RECTANGLE:
+               vkvg_rectangle (ctx, floats[0], floats[1], floats[2], floats[3]);
+               break;
+       case VKVG_CMD_ARC:
+               vkvg_arc (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]);
+               break;
+       case VKVG_CMD_ARC_NEG:
+               vkvg_arc (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]);
+               break;
+       /*case VKVG_CMD_ELLIPSE:
+               vkvg_ellipse (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]);
+               break;*/
+       case VKVG_CMD_MOVE_TO:
+               vkvg_move_to(ctx, floats[0], floats[1]);
+               break;
+       case VKVG_CMD_LINE_TO:
+               vkvg_line_to(ctx, floats[0], floats[1]);
+               break;
+       case VKVG_CMD_CURVE_TO:
+               vkvg_curve_to (ctx, floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]);
+               break;
+       case VKVG_CMD_ELLIPTICAL_ARC_TO:
+               {
+                       bool* flags = (bool*)&floats[5];
+                       vkvg_elliptic_arc_to (ctx, floats[0], floats[1], flags[0], flags[1], floats[2], floats[3], floats[4]);
+               }
+               break;
+       case VKVG_CMD_QUADRATIC_TO:
+               vkvg_quadratic_to (ctx, floats[0], floats[1], floats[2], floats[3]);
+               break;
+
+       case VKVG_CMD_REL_MOVE_TO:
+               vkvg_rel_move_to(ctx, floats[0], floats[1]);
+               break;
+       case VKVG_CMD_REL_LINE_TO:
+               vkvg_rel_line_to(ctx, floats[0], floats[1]);
+               break;
+       case VKVG_CMD_REL_CURVE_TO:
+               vkvg_rel_curve_to (ctx, floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]);
+               break;
+       case VKVG_CMD_REL_QUADRATIC_TO:
+               vkvg_rel_quadratic_to (ctx, floats[0], floats[1], floats[2], floats[3]);
+               break;
+       case VKVG_CMD_REL_ELLIPTICAL_ARC_TO:
+               {
+                       bool* flags = (bool*)&floats[5];
+                       vkvg_rel_elliptic_arc_to (ctx, floats[0], floats[1], flags[0], flags[1], floats[2], floats[3], floats[4]);
+               }
+               break;
+       case VKVG_CMD_SET_SOURCE_RGB:
+               vkvg_set_source_rgb (ctx, floats[0], floats[1], floats[2]);
+               break;
+       case VKVG_CMD_SET_SOURCE_RGBA:
+               vkvg_set_source_rgba (ctx, floats[0], floats[1], floats[2], floats[3]);
+               break;
+       case VKVG_CMD_SET_SOURCE:
+               {
+                       VkvgPattern pat = (VkvgPattern)(rec->buffer + r->dataOffset);
+                       vkvg_set_source (ctx, pat);
+               }
+               break;
+       case VKVG_CMD_SET_SOURCE_SURFACE:
+               {
+                       VkvgSurface surf = (VkvgSurface)&floats[2];
+                       vkvg_set_source_surface (ctx, surf, floats[0], floats[1]);
+               }
+               break;
+       }
+}
+
diff --git a/src/recording/vkvg_record_internal.h b/src/recording/vkvg_record_internal.h
new file mode 100644 (file)
index 0000000..64b6ee4
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018-2022 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef VKVG_RECORD_INTERNAL_H
+#define VKVG_RECORD_INTERNAL_H
+
+#include "vkvg.h"
+#include "vkvg_internal.h"
+
+#define VKVG_CMD_SAVE                          0x0001
+#define VKVG_CMD_RESTORE                       0x0002
+
+#define VKVG_CMD_PATH_COMMANDS         0x0100
+#define VKVG_CMD_DRAW_COMMANDS         0x0200
+#define VKVG_CMD_RELATIVE_COMMANDS     0x0400|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_PRESERVE_COMMANDS     0x0400|VKVG_CMD_DRAW_COMMANDS
+#define VKVG_CMD_PATTERN_COMMANDS      0x0800
+#define VKVG_CMD_TRANSFORM_COMMANDS    0x2000
+#define VKVG_CMD_TEXT_COMMANDS         0x4000
+
+#define VKVG_CMD_NEW_PATH                      0x0001|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_NEW_SUB_PATH          0x0002|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_CLOSE_PATH                    0x0003|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_MOVE_TO                       0x0004|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_LINE_TO                       0x0005|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_RECTANGLE                     0x0006|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_ARC                           0x0007|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_ARC_NEG                       0x0008|VKVG_CMD_PATH_COMMANDS
+//#define VKVG_CMD_ELLIPSE                     0x0009|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_CURVE_TO                      0x000A|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_QUADRATIC_TO          0x000B|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_ELLIPTICAL_ARC_TO     0x000C|VKVG_CMD_PATH_COMMANDS
+
+#define VKVG_CMD_SET_LINE_WIDTH                0x1001|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_SET_LINE_JOIN         0x1002|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_SET_LINE_CAP          0x1003|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_SET_OPERATOR          0x1004|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_SET_FILL_RULE         0x1005|VKVG_CMD_PATH_COMMANDS
+#define VKVG_CMD_SET_DASH                      0x1006|VKVG_CMD_PATH_COMMANDS
+
+#define VKVG_CMD_TRANSLATE                     0x0001|VKVG_CMD_TRANSFORM_COMMANDS
+#define VKVG_CMD_ROTATE                                0x0002|VKVG_CMD_TRANSFORM_COMMANDS
+#define VKVG_CMD_SCALE                         0x0003|VKVG_CMD_TRANSFORM_COMMANDS
+#define VKVG_CMD_TRANSFORM                     0x0004|VKVG_CMD_TRANSFORM_COMMANDS
+#define VKVG_CMD_IDENTITY_MATRIX       0x0005|VKVG_CMD_TRANSFORM_COMMANDS
+
+#define VKVG_CMD_SET_MATRIX                    0x0006|VKVG_CMD_TRANSFORM_COMMANDS
+
+#define VKVG_CMD_SET_FONT_SIZE         0x0001|VKVG_CMD_TEXT_COMMANDS
+#define VKVG_CMD_SET_FONT_FACE         0x0002|VKVG_CMD_TEXT_COMMANDS
+#define VKVG_CMD_SET_FONT_PATH         0x0003|VKVG_CMD_TEXT_COMMANDS
+#define VKVG_CMD_SHOW_TEXT                     0x0004|VKVG_CMD_TEXT_COMMANDS
+
+#define VKVG_CMD_REL_MOVE_TO                   VKVG_CMD_MOVE_TO                |VKVG_CMD_RELATIVE_COMMANDS
+#define VKVG_CMD_REL_LINE_TO                   VKVG_CMD_LINE_TO                |VKVG_CMD_RELATIVE_COMMANDS
+#define VKVG_CMD_REL_CURVE_TO                  VKVG_CMD_CURVE_TO               |VKVG_CMD_RELATIVE_COMMANDS
+#define VKVG_CMD_REL_QUADRATIC_TO              VKVG_CMD_QUADRATIC_TO   |VKVG_CMD_RELATIVE_COMMANDS
+#define VKVG_CMD_REL_ELLIPTICAL_ARC_TO VKVG_CMD_ELLIPTICAL_ARC_TO      |VKVG_CMD_RELATIVE_COMMANDS
+
+#define VKVG_CMD_PAINT                         0x0001|VKVG_CMD_DRAW_COMMANDS
+#define VKVG_CMD_FILL                          0x0002|VKVG_CMD_DRAW_COMMANDS
+#define VKVG_CMD_STROKE                                0x0003|VKVG_CMD_DRAW_COMMANDS
+#define VKVG_CMD_CLIP                          0x0004|VKVG_CMD_DRAW_COMMANDS
+#define VKVG_CMD_CLEAR                         0x0005|VKVG_CMD_DRAW_COMMANDS
+
+#define VKVG_CMD_FILL_PRESERVE         VKVG_CMD_FILL   |VKVG_CMD_PRESERVE_COMMANDS
+#define VKVG_CMD_STROKE_PRESERVE       VKVG_CMD_STROKE |VKVG_CMD_PRESERVE_COMMANDS
+#define VKVG_CMD_CLIP_PRESERVE         VKVG_CMD_CLIP   |VKVG_CMD_PRESERVE_COMMANDS
+
+#define VKVG_CMD_SET_SOURCE_RGB                0x0001|VKVG_CMD_PATTERN_COMMANDS
+#define VKVG_CMD_SET_SOURCE_RGBA       0x0002|VKVG_CMD_PATTERN_COMMANDS
+#define VKVG_CMD_SET_SOURCE                    0x0003|VKVG_CMD_PATTERN_COMMANDS
+#define VKVG_CMD_SET_SOURCE_SURFACE    0x0004|VKVG_CMD_PATTERN_COMMANDS
+
+
+
+typedef struct _vkvg_record_t{
+       uint16_t        cmd;
+       size_t          dataOffset;
+}vkvg_record_t;
+
+typedef struct _vkvg_recording_t{
+       vkvg_record_t*  commands;
+       uint32_t                commandsCount;
+       uint32_t                commandsReservedCount;
+       size_t                  bufferSize;
+       size_t                  bufferReservedSize;
+       void*                   buffer;
+}vkvg_recording_t;
+
+
+void                           _start_recording        (VkvgContext ctx);
+vkvg_recording_t*      _stop_recording         (VkvgContext ctx);
+void                           _destroy_recording      (vkvg_recording_t* rec);
+void                           _replay_command         (VkvgContext ctx, VkvgRecording rec, uint32_t index);
+void                           _record                         (vkvg_recording_t* rec,...);
+
+#define RECORD(ctx,...) {\
+       if (ctx->recording)             \
+               _record (ctx->recording,__VA_ARGS__);\
+}
+
+
+#endif
index 7f7936bb288c5da1122a18382936db7fd0d11865..aaa39499928ebf754f76dd523e3a2544ca19cc77 100644 (file)
@@ -35,7 +35,6 @@ const float DBG_LAB_COLOR_CLIP[4] = {0,1,1,1};
 #endif
 #endif
 
-
 //todo:this could be used to define a default background
 static VkClearValue clearValues[3] = {
        { .color.float32 = {0,0,0,0} },
@@ -314,6 +313,7 @@ void vkvg_new_sub_path (VkvgContext ctx){
        if (ctx->status)
                return;
 
+       RECORD(ctx, VKVG_CMD_NEW_SUB_PATH);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: new_sub_path:\n");
 
        _finish_path(ctx);
@@ -322,6 +322,7 @@ void vkvg_new_path (VkvgContext ctx){
        if (ctx->status)
                return;
 
+       RECORD(ctx, VKVG_CMD_NEW_PATH);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: new_path:\n");
 
        _clear_path(ctx);
@@ -330,6 +331,7 @@ void vkvg_close_path (VkvgContext ctx){
        if (ctx->status)
                return;
 
+       RECORD(ctx, VKVG_CMD_CLOSE_PATH);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: close_path:\n");
 
        if (ctx->pathes[ctx->pathPtr] & PATH_CLOSED_BIT) //already closed
@@ -350,36 +352,41 @@ void vkvg_close_path (VkvgContext ctx){
 
        _finish_path(ctx);
 }
+void _line_to (VkvgContext ctx, float x, float y) {
+       vec2 p = {x,y};
+       if (!_current_path_is_empty (ctx)){
+               //prevent adding the same point
+               if (vec2_equ (_get_current_position (ctx), p))
+                       return;
+       }
+       _add_point (ctx, x, y);
+}
 void vkvg_rel_line_to (VkvgContext ctx, float dx, float dy){
        if (ctx->status)
                return;
 
+       RECORD(ctx, VKVG_CMD_REL_LINE_TO, dx, dy);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_line_to:\n");
 
        if (_current_path_is_empty(ctx))
                _add_point(ctx, 0, 0);
        vec2 cp = _get_current_position(ctx);
-       vkvg_line_to(ctx, cp.x + dx, cp.y + dy);
+       _line_to(ctx, cp.x + dx, cp.y + dy);
 }
 void vkvg_line_to (VkvgContext ctx, float x, float y)
 {
        if (ctx->status)
                return;
 
+       RECORD(ctx, VKVG_CMD_LINE_TO, x, y);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: line_to:\n");
-
-       vec2 p = {x,y};
-       if (!_current_path_is_empty (ctx)){
-               //prevent adding the same point
-               if (vec2_equ (_get_current_position (ctx), p))
-                       return;
-       }
-       _add_point (ctx, x, y);
+       _line_to(ctx, x, y);
 }
 void vkvg_arc (VkvgContext ctx, float xc, float yc, float radius, float a1, float a2){
        if (ctx->status)
                return;
 
+       RECORD(ctx, VKVG_CMD_ARC, xc, yc, radius, a1, a2);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: arc:\n");
 
        while (a2 < a1)//positive arc must have a1<a2
@@ -429,6 +436,7 @@ void vkvg_arc (VkvgContext ctx, float xc, float yc, float radius, float a1, floa
 void vkvg_arc_negative (VkvgContext ctx, float xc, float yc, float radius, float a1, float a2) {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_ARC_NEG, xc, yc, radius, a1, a2);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: arc_neg:\n");
        while (a2 > a1)
                a2 -= 2.f*M_PIF;
@@ -478,6 +486,7 @@ void vkvg_rel_move_to (VkvgContext ctx, float x, float y)
 {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_REL_MOVE_TO, x, y);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_mote_to:\n");
        if (_current_path_is_empty(ctx))
                _add_point(ctx, 0, 0);
@@ -488,6 +497,7 @@ void vkvg_move_to (VkvgContext ctx, float x, float y)
 {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_MOVE_TO, x, y);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: move_to:\n");
        _finish_path(ctx);
        _add_point (ctx, x, y);
@@ -504,6 +514,7 @@ void vkvg_get_current_point (VkvgContext ctx, float* x, float* y) {
 void vkvg_rel_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2) {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_REL_QUADRATIC_TO, x1, y1, x2, y2);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_quadratic_to:\n");
        vec2 cp = _get_current_position(ctx);
        vkvg_quadratic_to (ctx, cp.x + x1, cp.y + y1, cp.x + x2, cp.y + y2);
@@ -512,6 +523,7 @@ const double quadraticFact = 2.0/3.0;
 void vkvg_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2) {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_QUADRATIC_TO, x1, y1, x2, y2);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: quadratic_to:\n");
 
        float x0, y0;
@@ -530,6 +542,7 @@ void vkvg_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2)
 void vkvg_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_CURVE_TO, x1, y1, x2, y2, x3, y3);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: curve_to:\n");
        //prevent running _recursive_bezier when all 4 curve points are equal
        if (EQUF(x1,x2) && EQUF(x2,x3) && EQUF(y1,y2) && EQUF(y2,y3)) {
@@ -557,6 +570,7 @@ void vkvg_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, flo
 void vkvg_rel_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_REL_CURVE_TO, x1, y1, x2, y2, x3, y3);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_curve_to:\n");
        vec2 cp = _get_current_position(ctx);
        vkvg_curve_to (ctx, cp.x + x1, cp.y + y1, cp.x + x2, cp.y + y2, cp.x + x3, cp.y + y3);
@@ -572,6 +586,7 @@ void vkvg_fill_rectangle (VkvgContext ctx, float x, float y, float w, float h){
 vkvg_status_t vkvg_rectangle (VkvgContext ctx, float x, float y, float w, float h){
        if (ctx->status)
                return ctx->status;
+       RECORD(ctx, VKVG_CMD_RECTANGLE, x, y, w, h);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: rectangle:\n");
        _finish_path (ctx);
 
@@ -632,6 +647,20 @@ void vkvg_rounded_rectangle2 (VkvgContext ctx, float x, float y, float w, float
 
        vkvg_close_path(ctx);
 }
+void vkvg_path_extents (VkvgContext ctx, float *x1, float *y1, float *x2, float *y2) {
+       if (ctx->status)
+               return;
+
+       _finish_path(ctx);
+
+       if (!ctx->pathPtr) {//no path
+               *x1 = *x2 = *y1 = *y2 = 0;
+               return;
+       }
+
+       _vkvg_path_extents(ctx, false, x1, y1, x2, y2);
+}
+
 
 static const VkClearAttachment clearStencil               = {VK_IMAGE_ASPECT_STENCIL_BIT, 1, {{{0}}}};
 static const VkClearAttachment clearColorAttach           = {VK_IMAGE_ASPECT_COLOR_BIT,   0, {{{0}}}};
@@ -653,6 +682,7 @@ void vkvg_reset_clip (VkvgContext ctx){
 void vkvg_clear (VkvgContext ctx){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_CLEAR);
        _emit_draw_cmd_undrawn_vertices(ctx);
        if (!ctx->cmdStarted) {
                ctx->renderPassBeginInfo.renderPass = ctx->pSurf->dev->renderPass_ClearAll;
@@ -662,24 +692,7 @@ void vkvg_clear (VkvgContext ctx){
        VkClearAttachment ca[2] = {clearColorAttach, clearStencil};
        vkCmdClearAttachments(ctx->cmd, 2, ca, 1, &ctx->clearRect);
 }
-
-void vkvg_clip (VkvgContext ctx){
-       vkvg_clip_preserve(ctx);
-       _clear_path(ctx);
-}
-void vkvg_stroke (VkvgContext ctx)
-{
-       vkvg_stroke_preserve(ctx);
-       _clear_path(ctx);
-}
-void vkvg_fill (VkvgContext ctx){
-       vkvg_fill_preserve(ctx);
-       _clear_path(ctx);
-}
-void vkvg_clip_preserve (VkvgContext ctx){
-       if (ctx->status)
-               return;
-
+void _clip_preserve (VkvgContext ctx){
        _finish_path(ctx);
 
        if (!ctx->pathPtr)//nothing to clip
@@ -719,25 +732,7 @@ void vkvg_clip_preserve (VkvgContext ctx){
        vkh_cmd_label_end (ctx->cmd);
 #endif
 }
-
-
-void vkvg_path_extents (VkvgContext ctx, float *x1, float *y1, float *x2, float *y2) {
-       if (ctx->status)
-               return;
-
-       _finish_path(ctx);
-
-       if (!ctx->pathPtr) {//no path
-               *x1 = *x2 = *y1 = *y2 = 0;
-               return;
-       }
-
-       _vkvg_path_extents(ctx, false, x1, y1, x2, y2);
-}
-void vkvg_fill_preserve (VkvgContext ctx){
-       if (ctx->status)
-               return;
-
+void _fill_preserve (VkvgContext ctx){
        _finish_path(ctx);
 
        if (!ctx->pathPtr)//nothing to fill
@@ -763,12 +758,8 @@ void vkvg_fill_preserve (VkvgContext ctx){
                _ensure_renderpass_is_started(ctx);
        _fill_non_zero(ctx);
 }
-
-void vkvg_stroke_preserve (VkvgContext ctx)
+void _stroke_preserve (VkvgContext ctx)
 {
-       if (ctx->status)
-               return;
-
        _finish_path(ctx);
 
        if (!ctx->pathPtr)//nothing to stroke
@@ -889,10 +880,52 @@ void vkvg_stroke_preserve (VkvgContext ctx)
        }
 
 }
-void vkvg_paint (VkvgContext ctx){
+
+void vkvg_clip (VkvgContext ctx){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_CLIP);
+       _clip_preserve(ctx);
+       _clear_path(ctx);
+}
+void vkvg_stroke (VkvgContext ctx)
+{
+       if (ctx->status)
+               return;
+       RECORD(ctx, VKVG_CMD_STROKE);
+       _stroke_preserve(ctx);
+       _clear_path(ctx);
+}
+void vkvg_fill (VkvgContext ctx){
+       if (ctx->status)
+               return;
+       RECORD(ctx, VKVG_CMD_FILL);
+       _fill_preserve(ctx);
+       _clear_path(ctx);
+}
+void vkvg_clip_preserve (VkvgContext ctx) {
+       if (ctx->status)
+               return;
+       RECORD(ctx, VKVG_CMD_CLIP_PRESERVE);
+       _clip_preserve (ctx);
+}
+void vkvg_fill_preserve (VkvgContext ctx) {
+       if (ctx->status)
+               return;
+       RECORD(ctx, VKVG_CMD_FILL_PRESERVE);
+       _fill_preserve (ctx);
+}
+void vkvg_stroke_preserve (VkvgContext ctx) {
+       if (ctx->status)
+               return;
+       RECORD(ctx, VKVG_CMD_STROKE_PRESERVE);
+       _stroke_preserve (ctx);
+}
 
+void vkvg_paint (VkvgContext ctx){
+       if (ctx->status)
+               return;
+       RECORD(ctx, VKVG_CMD_PAINT);
        _finish_path (ctx);
 
        if (ctx->pathPtr) {
@@ -910,18 +943,24 @@ void vkvg_set_source_color (VkvgContext ctx, uint32_t c) {
        _update_cur_pattern (ctx, NULL);
 }
 void vkvg_set_source_rgb (VkvgContext ctx, float r, float g, float b) {
-       vkvg_set_source_rgba (ctx, r, g, b, 1);
+       if (ctx->status)
+               return;
+       RECORD(ctx, VKVG_CMD_SET_SOURCE_RGB, r, g, b);
+       ctx->curColor = CreateRgbaf(r,g,b,1);
+       _update_cur_pattern (ctx, NULL);
 }
 void vkvg_set_source_rgba (VkvgContext ctx, float r, float g, float b, float a)
 {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SET_SOURCE_RGBA, r, g, b, a);
        ctx->curColor = CreateRgbaf(r,g,b,a);
        _update_cur_pattern (ctx, NULL);
 }
 void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SET_SOURCE_SURFACE, x, y, surf);
        ctx->pushConsts.source.x = x;
        ctx->pushConsts.source.y = y;
        _update_cur_pattern (ctx, vkvg_pattern_create_for_surface(surf));
@@ -930,21 +969,26 @@ void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y
 void vkvg_set_source (VkvgContext ctx, VkvgPattern pat){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SET_SOURCE, pat);
        _update_cur_pattern (ctx, pat);
        vkvg_pattern_reference  (pat);
 }
 void vkvg_set_line_width (VkvgContext ctx, float width){
+       RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, width);
        ctx->lineWidth = width;
 }
 void vkvg_set_line_cap (VkvgContext ctx, vkvg_line_cap_t cap){
+       RECORD(ctx, VKVG_CMD_SET_LINE_CAP, cap);
        ctx->lineCap = cap;
 }
 void vkvg_set_line_join (VkvgContext ctx, vkvg_line_join_t join){
+       RECORD(ctx, VKVG_CMD_SET_LINE_JOIN, join);
        ctx->lineJoin = join;
 }
 void vkvg_set_operator (VkvgContext ctx, vkvg_operator_t op){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SET_OPERATOR, op);
        if (op == ctx->curOperator)
                return;
 
@@ -957,6 +1001,7 @@ void vkvg_set_operator (VkvgContext ctx, vkvg_operator_t op){
 }
 void vkvg_set_fill_rule (VkvgContext ctx, vkvg_fill_rule_t fr){
 #ifndef __APPLE__
+       RECORD(ctx, VKVG_CMD_SET_FILL_RULE, fr);
        ctx->curFillRule = fr;
 #endif
 }
@@ -971,6 +1016,7 @@ void vkvg_set_dash (VkvgContext ctx, const float* dashes, uint32_t num_dashes, f
                return;
        if (ctx->dashCount > 0)
                free (ctx->dashes);
+       RECORD(ctx, VKVG_CMD_SET_DASH, num_dashes, offset, dashes);
        ctx->dashCount = num_dashes;
        ctx->dashOffset = offset;
        if (ctx->dashCount == 0)
@@ -1004,17 +1050,20 @@ VkvgPattern vkvg_get_source (VkvgContext ctx){
 void vkvg_select_font_face (VkvgContext ctx, const char* name){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SET_FONT_FACE, name);
        _select_font_face (ctx, name);
 }
 void vkvg_load_font_from_path (VkvgContext ctx, const char* path, const char* name){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SET_FONT_PATH, name);
        _add_new_font_identity(ctx, path, name);
        _select_font_face (ctx, name);
 }
 void vkvg_set_font_size (VkvgContext ctx, uint32_t size){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SET_FONT_SIZE, size);
 #ifdef VKVG_USE_FREETYPE
        long newSize = size << 6;
 #else
@@ -1034,6 +1083,7 @@ void vkvg_set_text_direction (vkvg_context* ctx, vkvg_direction_t direction){
 void vkvg_show_text (VkvgContext ctx, const char* text){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SHOW_TEXT, text);
        LOG(VKVG_LOG_INFO_CMD, "CMD: show_text:\n");
        //_ensure_renderpass_is_started(ctx);
        _show_text (ctx, text);
@@ -1074,6 +1124,7 @@ void vkvg_font_extents (VkvgContext ctx, vkvg_font_extents_t* extents) {
 void vkvg_save (VkvgContext ctx){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SAVE);
        LOG(VKVG_LOG_INFO, "SAVE CONTEXT: ctx = %p\n", ctx);
 
        _flush_cmd_buff (ctx);
@@ -1185,6 +1236,7 @@ void vkvg_save (VkvgContext ctx){
 void vkvg_restore (VkvgContext ctx){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_RESTORE);
 
        if (ctx->pSavedCtxs == NULL){
                ctx->status = VKVG_STATUS_INVALID_RESTORE;
@@ -1301,6 +1353,7 @@ void vkvg_restore (VkvgContext ctx){
 void vkvg_translate (VkvgContext ctx, float dx, float dy){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_TRANSLATE, dx, dy);
        LOG(VKVG_LOG_INFO_CMD, "CMD: translate:\n");
        _emit_draw_cmd_undrawn_vertices(ctx);
        vkvg_matrix_translate (&ctx->pushConsts.mat, dx, dy);
@@ -1309,6 +1362,7 @@ void vkvg_translate (VkvgContext ctx, float dx, float dy){
 void vkvg_scale (VkvgContext ctx, float sx, float sy){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SCALE, sx, sy);
        LOG(VKVG_LOG_INFO_CMD, "CMD: scale:\n");
        _emit_draw_cmd_undrawn_vertices(ctx);
        vkvg_matrix_scale (&ctx->pushConsts.mat, sx, sy);
@@ -1317,6 +1371,7 @@ void vkvg_scale (VkvgContext ctx, float sx, float sy){
 void vkvg_rotate (VkvgContext ctx, float radians){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_ROTATE, radians);
        LOG(VKVG_LOG_INFO_CMD, "CMD: rotate:\n");
        _emit_draw_cmd_undrawn_vertices(ctx);
        vkvg_matrix_rotate (&ctx->pushConsts.mat, radians);
@@ -1325,6 +1380,7 @@ void vkvg_rotate (VkvgContext ctx, float radians){
 void vkvg_transform (VkvgContext ctx, const vkvg_matrix_t* matrix) {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_TRANSFORM, matrix);
        LOG(VKVG_LOG_INFO_CMD, "CMD: transform:\n");
        _emit_draw_cmd_undrawn_vertices(ctx);
        vkvg_matrix_t res;
@@ -1335,6 +1391,7 @@ void vkvg_transform (VkvgContext ctx, const vkvg_matrix_t* matrix) {
 void vkvg_identity_matrix (VkvgContext ctx) {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_IDENTITY_MATRIX);
        LOG(VKVG_LOG_INFO_CMD, "CMD: identity_matrix:\n");
        _emit_draw_cmd_undrawn_vertices(ctx);
        vkvg_matrix_t im = VKVG_IDENTITY_MATRIX;
@@ -1344,6 +1401,7 @@ void vkvg_identity_matrix (VkvgContext ctx) {
 void vkvg_set_matrix (VkvgContext ctx, const vkvg_matrix_t* matrix){
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_SET_MATRIX, matrix);
        LOG(VKVG_LOG_INFO_CMD, "CMD: set_matrix:\n");
        _emit_draw_cmd_undrawn_vertices(ctx);
        ctx->pushConsts.mat = (*matrix);
@@ -1353,22 +1411,24 @@ void vkvg_get_matrix (VkvgContext ctx, const vkvg_matrix_t* matrix){
        memcpy ((void*)matrix, &ctx->pushConsts.mat, sizeof(vkvg_matrix_t));
 }
 
-void vkvg_elliptic_arc_to (VkvgContext ctx, float x2, float y2, bool largeArc, bool counterClockWise, float rx, float ry, float phi) {
+void vkvg_elliptic_arc_to (VkvgContext ctx, float x2, float y2, bool largeArc, bool sweepFlag, float rx, float ry, float phi) {
        if (ctx->status)
                return;
+       RECORD(ctx, VKVG_CMD_ELLIPTICAL_ARC_TO, x2, y2, rx, ry, phi, largeArc, sweepFlag);
        LOG(VKVG_LOG_INFO_CMD, "\tCMD: elliptic_arc_to:\n");
        float x1, y1;
        vkvg_get_current_point(ctx, &x1, &y1);
-       _elliptic_arc(ctx, x1, y1, x2, y2, largeArc, counterClockWise, rx, ry, phi);
+       _elliptic_arc(ctx, x1, y1, x2, y2, largeArc, sweepFlag, rx, ry, phi);
 }
-void vkvg_rel_elliptic_arc_to (VkvgContext ctx, float x2, float y2, bool largeArc, bool counterClockWise, float rx, float ry, float phi) {
+void vkvg_rel_elliptic_arc_to (VkvgContext ctx, float x2, float y2, bool largeArc, bool sweepFlag, float rx, float ry, float phi) {
        if (ctx->status)
                return;
-       LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_elliptic_arc_to: x2:%10.5f y2:%10.5f large:%d sweep:%d rx:%10.5f ry:%10.5f phi:%10.5f \n", x2,y2,largeArc,counterClockWise,rx,ry,phi);
+       RECORD(ctx, VKVG_CMD_REL_ELLIPTICAL_ARC_TO, x2, y2, rx, ry, phi, largeArc, sweepFlag);
+       LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_elliptic_arc_to: x2:%10.5f y2:%10.5f large:%d sweep:%d rx:%10.5f ry:%10.5f phi:%10.5f \n", x2,y2,largeArc,sweepFlag,rx,ry,phi);
 
        float x1, y1;
        vkvg_get_current_point(ctx, &x1, &y1);
-       _elliptic_arc(ctx, x1, y1, x2+x1, y2+y1, largeArc, counterClockWise, rx, ry, phi);
+       _elliptic_arc(ctx, x1, y1, x2+x1, y2+y1, largeArc, sweepFlag, rx, ry, phi);
 }
 
 void vkvg_ellipse (VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle) {
index 3183cdae12e10173e9818bedc81c96cc92813cbe..de0a56b4054616ab51b09d7e4195348c229b324c 100644 (file)
 #include "vkh.h"
 #include "vkvg_fonts.h"
 
+#if VKVG_RECORDING
+#include "vkvg_record_internal.h"
+#else
+#define RECORD(ctx,cmd,...)
+#endif
+
 #define VKVG_PTS_SIZE                          1024
 #define VKVG_VBO_SIZE                          (VKVG_PTS_SIZE * 4)
 #define VKVG_IBO_SIZE                          (VKVG_VBO_SIZE * 6)
@@ -131,6 +137,10 @@ typedef struct _vkvg_context_t {
        uint32_t tesselator_idx_counter;
 #endif
 
+#if VKVG_RECORDING
+       vkvg_recording_t*       recording;
+#endif
+
        vkvg_buff       uboGrad;                //uniform buff obj holdings gradient infos
 
        //vk buffers, holds data until flush
diff --git a/tests/recording.c b/tests/recording.c
new file mode 100644 (file)
index 0000000..495ec4a
--- /dev/null
@@ -0,0 +1,48 @@
+#include "test.h"
+
+#if VKVG_RECORDING
+void test(){
+       VkvgContext ctx = _initCtx(surf);
+
+       vkvg_scale(ctx,0.5,0.5);
+       vkvg_start_recording(ctx);
+
+       vkvg_set_source_rgba(ctx,0.1f,0.9f,0.1f,1.0f);
+       vkvg_move_to(ctx,100,100);
+       vkvg_rel_line_to(ctx,50,200);
+       vkvg_rel_line_to(ctx,150,-100);
+       vkvg_rel_line_to(ctx,100,200);
+       vkvg_rel_line_to(ctx,-100,100);
+       vkvg_rel_line_to(ctx,-10,-100);
+       vkvg_rel_line_to(ctx,-190,-50);
+       vkvg_rel_line_to(ctx,300,50);
+       vkvg_rel_line_to(ctx,50,0);
+       vkvg_rel_line_to(ctx,0, 50);
+       vkvg_rel_line_to(ctx,50,0);
+       vkvg_rel_line_to(ctx,0, 50);
+       vkvg_rel_line_to(ctx,50,0);
+       vkvg_rel_line_to(ctx,0, 50);
+       vkvg_rel_line_to(ctx,50,0);
+       vkvg_rel_line_to(ctx,0, 50);
+       vkvg_close_path(ctx);
+
+       vkvg_stroke_preserve(ctx);
+       vkvg_fill(ctx);
+
+       VkvgRecording rec = vkvg_stop_recording(ctx);
+
+       vkvg_translate(ctx,400,0);
+       vkvg_replay(ctx, rec);
+
+       vkvg_destroy(ctx);
+       vkvg_recording_destroy(rec);
+}
+#endif
+int main(int argc, char *argv[]) {
+       no_test_size = true;
+#if VKVG_RECORDING
+       PERFORM_TEST (test, argc, argv);
+#endif
+       return 0;
+}
+