summaryrefslogtreecommitdiff
path: root/src/sim
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim')
-rw-r--r--src/sim/cd_truetype.c181
-rw-r--r--src/sim/cd_truetype.h46
-rw-r--r--src/sim/cdfontex.c669
-rw-r--r--src/sim/sim.c328
-rw-r--r--src/sim/sim.h58
-rw-r--r--src/sim/sim_linepolyfill.c1000
-rw-r--r--src/sim/sim_other.c411
-rw-r--r--src/sim/sim_primitives.c524
-rw-r--r--src/sim/sim_text.c371
-rw-r--r--src/sim/truetype.h46
10 files changed, 3634 insertions, 0 deletions
diff --git a/src/sim/cd_truetype.c b/src/sim/cd_truetype.c
new file mode 100644
index 0000000..71593c0
--- /dev/null
+++ b/src/sim/cd_truetype.c
@@ -0,0 +1,181 @@
+/** \file
+ * \brief Text and Font Simulation using FreeType library.
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <stdio.h>
+
+#include "cd_truetype.h"
+
+/*******************************************
+ Inicializa o Rasterizador
+********************************************/
+static char *getCdDir(void)
+{
+ static char *env = NULL;
+ if (env) return env;
+ env = getenv("CDDIR");
+ if (!env) env = ".";
+ return env;
+}
+
+#ifdef WIN32
+#include <windows.h>
+static int ReadStringKey(HKEY base_key, char* key_name, char* value_name, char* value)
+{
+ HKEY key;
+ DWORD max_size = 512;
+
+ if (RegOpenKeyEx(base_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS)
+ return 0;
+
+ if (RegQueryValueEx(key, value_name, NULL, NULL, (LPBYTE)value, &max_size) != ERROR_SUCCESS)
+ {
+ RegCloseKey(key);
+ return 0;
+ }
+
+ RegCloseKey(key);
+ return 1;
+}
+
+char* GetFontDir(void)
+{
+ static char font_dir[512];
+ if (!ReadStringKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", "Fonts", font_dir))
+ return "";
+ else
+ {
+ int i, size = (int)strlen(font_dir);
+ for(i = 0; i < size; i++)
+ {
+ if (font_dir[i] == '\\')
+ font_dir[i] = '/';
+ }
+ return font_dir;
+ }
+}
+#endif
+
+int cdTT_load(cdTT_Text * tt_text, const char *font, int size, double xres, double yres)
+{
+ char filename[10240];
+ FILE *file; /* usado apenas para procurar pelo arquivo */
+ FT_Error error;
+ FT_Face face;
+
+ /* abre arq. no dir. corrente */
+ sprintf(filename, "%s.ttf", font);
+ file = fopen(filename, "r");
+
+ if (file)
+ fclose(file);
+ else
+ {
+ /* se nao conseguiu, abre arq. no dir. do cd, */
+ sprintf(filename, "%s/%s.ttf", getCdDir(), font);
+ file = fopen(filename, "r");
+
+ if (file)
+ fclose(file);
+ else
+ {
+#ifdef WIN32
+ /* no caso do Windows procura no seu diretorio de fontes. */
+ sprintf(filename, "%s/%s.ttf", GetFontDir(), font);
+ file = fopen(filename, "r");
+
+ if (file)
+ fclose(file);
+ else
+ return 0;
+#else
+ return 0;
+#endif
+ }
+ }
+
+ error = FT_New_Face(tt_text->library, filename, 0, &face );
+ if (error)
+ return 0;
+
+ /* char_height is 1/64th of points */
+ error = FT_Set_Char_Size(face, 0, size*64, (int)(xres*25.4), (int)(yres*25.4));
+ if (error)
+ {
+ FT_Done_Face(face);
+ return 0;
+ }
+
+ if (tt_text->face && tt_text->face != face)
+ FT_Done_Face(tt_text->face);
+
+ tt_text->face = face;
+
+ tt_text->ascent = face->size->metrics.ascender >> 6;
+ tt_text->descent = abs(face->size->metrics.descender >> 6);
+ tt_text->max_height = face->size->metrics.height >> 6;
+ tt_text->max_width = face->size->metrics.max_advance >> 6;
+
+ if (!face->charmap)
+ FT_Set_Charmap(face, face->charmaps[0]);
+
+ return 1;
+}
+
+static void cdTT_checkversion(cdTT_Text* tt_text)
+{
+ FT_Int major, minor, patch;
+ FT_Library_Version(tt_text->library, &major, &minor, &patch);
+ if (major != FREETYPE_MAJOR ||
+ minor != FREETYPE_MINOR ||
+ patch != FREETYPE_PATCH)
+ {
+ printf("CD - Canvas Draw: Warning - Different FreeType library used!\n"
+ " Compiled = %d.%d.%d\n"
+ " RunTime = %d.%d.%d\n",
+ FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH, major, minor, patch);
+ }
+}
+
+/*******************************************
+ Inicializaccao
+********************************************/
+cdTT_Text* cdTT_create(void)
+{
+ cdTT_Text * tt_text = malloc(sizeof(cdTT_Text));
+ memset(tt_text, 0, sizeof(cdTT_Text));
+
+ FT_Init_FreeType(&tt_text->library);
+
+ cdTT_checkversion(tt_text);
+
+ return tt_text;
+}
+
+/*******************************************
+ Desaloca Recursos
+********************************************/
+void cdTT_free(cdTT_Text * tt_text)
+{
+ if (tt_text->rgba_data)
+ free(tt_text->rgba_data);
+
+ if (tt_text->face)
+ FT_Done_Face(tt_text->face);
+
+ FT_Done_FreeType(tt_text->library);
+
+ free(tt_text);
+}
+
+#ifdef SunOS_OLD
+void *memmove( void *dest, const void *src, size_t count )
+{
+ return memcpy(dest, src, count);
+}
+#endif
diff --git a/src/sim/cd_truetype.h b/src/sim/cd_truetype.h
new file mode 100644
index 0000000..5675998
--- /dev/null
+++ b/src/sim/cd_truetype.h
@@ -0,0 +1,46 @@
+/** \file
+ * \brief Text and Font Simulation using FreeType library.
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#ifndef __TRUETYPE_H
+#define __TRUETYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ft2build.h"
+#include FT_FREETYPE_H
+
+/*
+ In CD version 4.4 we start to use FreeType 2.
+ Only TrueType font support is enabled.
+*/
+
+typedef struct _cdTT_Text
+{
+ FT_Library library;
+ FT_Face face;
+
+ unsigned char* rgba_data;
+ int rgba_data_size;
+
+ int max_height;
+ int max_width;
+ int descent;
+ int ascent;
+
+}cdTT_Text;
+
+cdTT_Text* cdTT_create(void);
+void cdTT_free(cdTT_Text * tt_text);
+int cdTT_load(cdTT_Text * tt_text, const char *font,int size, double xres, double yres);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef _CD_TRUETYPE_ */
+
diff --git a/src/sim/cdfontex.c b/src/sim/cdfontex.c
new file mode 100644
index 0000000..699b06f
--- /dev/null
+++ b/src/sim/cdfontex.c
@@ -0,0 +1,669 @@
+/** \file
+ * \brief Font Properties Estimation
+ *
+ * See Copyright Notice in cd.h
+ */
+
+
+#include "cd.h"
+#include "cd_private.h"
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct _cd_font_styles
+{
+ unsigned char s[4];
+}cd_font_styles;
+
+static cd_font_styles helv[256] = {
+{0, 0, 0, 0},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{30, 30, 30, 30},
+{30, 30, 30, 35},
+{35, 50, 35, 50},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{90, 85, 90, 90},
+{70, 75, 70, 75},
+{20, 25, 20, 25},
+{35, 35, 35, 35},
+{35, 35, 35, 35},
+{40, 40, 40, 40},
+{60, 60, 60, 60},
+{30, 30, 30, 30},
+{35, 35, 35, 35},
+{30, 30, 30, 30},
+{30, 30, 30, 30},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{30, 35, 30, 35},
+{30, 35, 30, 35},
+{60, 60, 60, 60},
+{60, 60, 60, 60},
+{60, 60, 60, 60},
+{55, 65, 55, 60},
+{100, 100, 100, 100},
+{65, 70, 70, 75},
+{70, 70, 70, 70},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{70, 65, 70, 70},
+{60, 60, 65, 65},
+{80, 80, 80, 80},
+{70, 70, 75, 75},
+{25, 30, 30, 30},
+{50, 55, 55, 55},
+{70, 75, 70, 75},
+{55, 65, 55, 65},
+{80, 85, 85, 90},
+{70, 70, 75, 75},
+{80, 80, 80, 80},
+{65, 70, 70, 70},
+{80, 80, 80, 80},
+{75, 70, 75, 75},
+{70, 70, 70, 70},
+{60, 65, 65, 65},
+{70, 70, 75, 75},
+{65, 70, 70, 70},
+{100, 95, 100, 95},
+{65, 70, 70, 70},
+{65, 65, 70, 65},
+{60, 60, 65, 65},
+{30, 35, 30, 35},
+{30, 30, 30, 30},
+{30, 35, 30, 35},
+{45, 60, 50, 60},
+{55, 55, 55, 55},
+{35, 35, 35, 35},
+{55, 60, 55, 60},
+{55, 65, 60, 65},
+{55, 55, 55, 55},
+{55, 65, 55, 60},
+{55, 60, 55, 55},
+{30, 35, 30, 35},
+{55, 65, 55, 60},
+{55, 65, 55, 65},
+{25, 30, 25, 30},
+{25, 30, 25, 30},
+{50, 60, 55, 60},
+{25, 30, 25, 30},
+{85, 90, 85, 90},
+{55, 65, 55, 65},
+{55, 65, 55, 65},
+{55, 65, 55, 60},
+{55, 65, 55, 65},
+{35, 40, 35, 40},
+{55, 55, 55, 55},
+{30, 35, 30, 35},
+{55, 65, 55, 60},
+{50, 55, 50, 55},
+{75, 80, 70, 80},
+{50, 60, 50, 55},
+{50, 55, 50, 55},
+{50, 55, 50, 50},
+{35, 40, 35, 40},
+{25, 30, 25, 30},
+{35, 40, 35, 40},
+{60, 60, 60, 60},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{25, 30, 25, 30},
+{55, 55, 55, 55},
+{35, 55, 30, 55},
+{100, 100, 100, 100},
+{55, 55, 55, 55},
+{55, 55, 55, 55},
+{35, 35, 35, 35},
+{100, 105, 100, 100},
+{70, 70, 70, 70},
+{35, 35, 35, 35},
+{100, 105, 100, 100},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{25, 30, 20, 30},
+{25, 30, 20, 30},
+{35, 55, 35, 55},
+{35, 55, 30, 55},
+{35, 35, 35, 35},
+{55, 55, 55, 55},
+{100, 100, 100, 100},
+{30, 35, 30, 35},
+{100, 100, 100, 100},
+{55, 55, 55, 55},
+{35, 35, 35, 35},
+{95, 95, 95, 95},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{65, 65, 70, 65},
+{30, 30, 30, 30},
+{30, 30, 35, 35},
+{55, 55, 55, 60},
+{55, 55, 55, 55},
+{60, 55, 60, 55},
+{55, 55, 55, 55},
+{25, 30, 25, 30},
+{55, 55, 55, 55},
+{35, 35, 35, 35},
+{75, 75, 75, 80},
+{35, 40, 40, 40},
+{55, 55, 55, 55},
+{60, 60, 60, 60},
+{35, 35, 35, 35},
+{75, 75, 75, 80},
+{55, 55, 55, 55},
+{40, 40, 40, 40},
+{55, 55, 55, 60},
+{35, 35, 35, 35},
+{35, 35, 35, 35},
+{35, 35, 35, 35},
+{60, 60, 55, 60},
+{55, 55, 55, 55},
+{30, 30, 30, 30},
+{35, 35, 35, 35},
+{35, 35, 35, 35},
+{40, 40, 40, 40},
+{55, 55, 55, 55},
+{85, 85, 85, 85},
+{85, 85, 85, 85},
+{85, 85, 85, 85},
+{60, 65, 65, 60},
+{65, 70, 70, 75},
+{65, 70, 70, 75},
+{65, 70, 70, 75},
+{65, 70, 70, 75},
+{65, 70, 70, 75},
+{65, 70, 70, 75},
+{100, 100, 100, 100},
+{75, 75, 75, 75},
+{70, 65, 70, 70},
+{70, 65, 70, 70},
+{70, 65, 70, 70},
+{70, 65, 70, 70},
+{25, 30, 30, 30},
+{25, 30, 30, 30},
+{25, 30, 30, 30},
+{25, 30, 30, 30},
+{75, 75, 75, 75},
+{70, 70, 75, 75},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{60, 60, 60, 60},
+{80, 80, 80, 80},
+{70, 70, 75, 75},
+{70, 70, 75, 75},
+{70, 70, 75, 75},
+{70, 70, 75, 75},
+{65, 65, 70, 65},
+{70, 70, 70, 70},
+{65, 65, 65, 65},
+{55, 60, 55, 60},
+{55, 60, 55, 60},
+{55, 60, 55, 60},
+{55, 60, 55, 60},
+{55, 60, 55, 60},
+{55, 60, 55, 60},
+{90, 90, 90, 90},
+{55, 55, 55, 55},
+{55, 60, 55, 55},
+{55, 60, 55, 55},
+{55, 60, 55, 55},
+{55, 60, 55, 55},
+{25, 30, 25, 30},
+{25, 30, 25, 30},
+{25, 30, 25, 30},
+{25, 30, 25, 30},
+{55, 65, 55, 60},
+{55, 65, 55, 65},
+{55, 65, 55, 65},
+{55, 65, 55, 65},
+{55, 65, 55, 65},
+{55, 65, 55, 65},
+{55, 65, 55, 65},
+{55, 55, 55, 55},
+{60, 65, 65, 60},
+{55, 65, 55, 60},
+{55, 65, 55, 60},
+{55, 65, 55, 60},
+{55, 65, 55, 60},
+{50, 55, 50, 55},
+{55, 65, 55, 65},
+{50, 55, 50, 55}
+};
+
+static cd_font_styles times[256] = {
+{0, 0, 0, 0},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{25, 25, 25, 25},
+{35, 35, 30, 35},
+{40, 55, 45, 55},
+{55, 55, 55, 50},
+{50, 55, 55, 55},
+{85, 100, 85, 85},
+{80, 85, 75, 80},
+{20, 30, 25, 30},
+{35, 35, 35, 35},
+{35, 35, 35, 35},
+{50, 55, 55, 55},
+{60, 60, 70, 60},
+{25, 25, 25, 25},
+{35, 35, 35, 35},
+{25, 25, 25, 25},
+{30, 30, 30, 30},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{25, 35, 35, 35},
+{30, 35, 35, 35},
+{60, 60, 70, 60},
+{60, 60, 70, 60},
+{60, 60, 70, 60},
+{45, 55, 55, 55},
+{95, 95, 95, 85},
+{70, 70, 60, 70},
+{65, 70, 65, 70},
+{70, 75, 70, 70},
+{75, 75, 75, 75},
+{60, 65, 65, 70},
+{55, 60, 60, 70},
+{70, 80, 75, 75},
+{75, 80, 75, 80},
+{35, 40, 35, 40},
+{40, 55, 45, 50},
+{75, 80, 65, 70},
+{60, 65, 55, 65},
+{90, 95, 85, 90},
+{75, 75, 70, 75},
+{75, 80, 75, 75},
+{60, 65, 60, 65},
+{75, 80, 75, 75},
+{65, 75, 65, 70},
+{55, 60, 55, 55},
+{65, 65, 55, 65},
+{70, 70, 75, 75},
+{70, 70, 60, 65},
+{95, 100, 80, 90},
+{70, 70, 65, 70},
+{70, 70, 55, 65},
+{60, 65, 55, 65},
+{35, 35, 40, 35},
+{30, 30, 30, 30},
+{35, 35, 45, 35},
+{45, 60, 45, 60},
+{55, 55, 55, 55},
+{35, 35, 35, 35},
+{45, 50, 55, 55},
+{50, 55, 55, 50},
+{45, 45, 45, 45},
+{50, 55, 55, 55},
+{45, 50, 45, 45},
+{35, 35, 30, 35},
+{50, 55, 55, 50},
+{50, 55, 55, 55},
+{25, 30, 30, 30},
+{25, 35, 30, 30},
+{50, 55, 50, 55},
+{25, 30, 30, 30},
+{75, 85, 75, 80},
+{50, 55, 55, 55},
+{50, 50, 55, 50},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{35, 45, 40, 40},
+{40, 40, 40, 40},
+{30, 35, 30, 30},
+{50, 55, 55, 55},
+{50, 50, 45, 45},
+{70, 70, 65, 70},
+{50, 50, 45, 55},
+{50, 50, 45, 45},
+{45, 45, 40, 40},
+{50, 40, 40, 35},
+{20, 25, 30, 25},
+{50, 40, 40, 35},
+{55, 55, 55, 60},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{35, 35, 35, 35},
+{50, 55, 50, 55},
+{45, 55, 55, 55},
+{100, 100, 90, 100},
+{50, 50, 55, 55},
+{50, 55, 55, 55},
+{35, 35, 35, 35},
+{100, 100, 100, 105},
+{55, 60, 55, 55},
+{35, 35, 35, 35},
+{90, 100, 95, 95},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{35, 35, 35, 35},
+{35, 35, 35, 35},
+{45, 55, 55, 55},
+{45, 55, 55, 55},
+{35, 40, 35, 35},
+{55, 55, 55, 55},
+{100, 100, 90, 100},
+{35, 35, 35, 35},
+{100, 105, 100, 100},
+{40, 40, 40, 40},
+{35, 35, 35, 35},
+{75, 75, 70, 75},
+{80, 80, 80, 80},
+{80, 80, 80, 80},
+{70, 70, 55, 65},
+{25, 25, 25, 25},
+{35, 30, 40, 35},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{55, 55, 50, 50},
+{55, 55, 55, 55},
+{20, 25, 30, 25},
+{50, 55, 55, 55},
+{35, 40, 30, 35},
+{75, 75, 75, 75},
+{30, 30, 30, 30},
+{50, 55, 55, 55},
+{60, 60, 70, 60},
+{35, 35, 35, 35},
+{75, 75, 80, 75},
+{55, 55, 55, 55},
+{40, 40, 40, 40},
+{55, 55, 55, 55},
+{30, 30, 30, 30},
+{30, 30, 30, 30},
+{30, 35, 35, 35},
+{55, 60, 60, 60},
+{45, 55, 55, 55},
+{25, 25, 25, 25},
+{30, 35, 35, 35},
+{30, 30, 30, 30},
+{30, 35, 35, 30},
+{50, 55, 55, 55},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{75, 75, 75, 75},
+{45, 55, 50, 55},
+{70, 70, 60, 70},
+{70, 70, 60, 70},
+{70, 70, 60, 70},
+{70, 70, 60, 70},
+{70, 70, 60, 70},
+{70, 70, 60, 70},
+{90, 100, 90, 95},
+{70, 75, 70, 70},
+{60, 65, 65, 70},
+{60, 65, 65, 70},
+{60, 65, 65, 70},
+{60, 65, 65, 70},
+{35, 40, 35, 40},
+{35, 40, 35, 40},
+{35, 40, 35, 40},
+{35, 40, 35, 40},
+{75, 75, 75, 75},
+{75, 75, 70, 75},
+{75, 80, 75, 75},
+{75, 80, 75, 75},
+{75, 80, 75, 75},
+{75, 80, 75, 75},
+{75, 80, 75, 75},
+{60, 60, 70, 60},
+{75, 80, 75, 75},
+{75, 70, 75, 75},
+{75, 70, 75, 75},
+{75, 70, 75, 75},
+{75, 70, 75, 75},
+{70, 70, 55, 65},
+{60, 65, 65, 65},
+{50, 55, 55, 55},
+{45, 50, 55, 55},
+{45, 50, 55, 55},
+{45, 50, 55, 55},
+{45, 50, 55, 55},
+{45, 50, 55, 55},
+{45, 50, 55, 55},
+{70, 75, 70, 75},
+{45, 45, 45, 45},
+{45, 50, 45, 45},
+{45, 50, 45, 45},
+{45, 50, 45, 45},
+{45, 50, 45, 45},
+{30, 30, 30, 30},
+{30, 30, 30, 30},
+{30, 30, 30, 30},
+{30, 30, 30, 30},
+{55, 50, 55, 55},
+{50, 55, 55, 55},
+{50, 50, 55, 50},
+{50, 50, 55, 50},
+{50, 50, 55, 50},
+{50, 50, 55, 50},
+{50, 50, 55, 50},
+{55, 55, 55, 55},
+{55, 50, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 55, 55, 55},
+{50, 50, 45, 45},
+{55, 55, 50, 50},
+{50, 50, 45, 45}
+};
+
+
+typedef struct _cdFontType
+{
+ int max_width, line_height, ascent, descent, style, size;
+ double sizex;
+ int (*CharWidth)(char c);
+}cdFontType;
+
+
+static cdFontType font;
+
+
+static int CharWidthCourier(char c)
+{
+ (void)c;
+ return (int)(0.60 * font.sizex + 0.5);
+}
+
+
+static int CharWidthTimesRoman(char c)
+{
+ return (int)(times[(int)c].s[font.style] * font.sizex / 100 + 0.5);
+}
+
+
+static int CharWidthHelvetica(char c)
+{
+ return (int)(helv[(int)c].s[font.style] * font.sizex / 100 + 0.5);
+}
+
+
+static void cdFontEx(cdCanvas* canvas, const char* type_face, int style, int size)
+{
+ double mm_dx, mm_dy;
+ double sizey, sizex;
+
+ font.style = style;
+
+ if (size < 0)
+ {
+ double size_mm;
+ cdCanvasPixel2MM(canvas, -size, 0, &size_mm, NULL);
+ size = (int)(size_mm * CD_MM2PT + 0.5);
+ }
+
+ font.size = size;
+
+ cdCanvasPixel2MM(canvas, 1, 1, &mm_dx, &mm_dy);
+
+ sizey = ((25.4 / 72) / mm_dy) * size;
+ sizex = ((25.4 / 72) / mm_dx) * size;
+
+ font.sizex = sizex;
+
+ font.line_height = (int)(1.2 * sizey + 0.5);
+ font.ascent = (int)(0.75 * font.line_height + 0.5);
+ font.descent = (int)(0.20 * font.line_height + 0.5);
+
+ if (strcmp(type_face, "Times")==0)
+ {
+ if (style == CD_PLAIN || style == CD_BOLD)
+ font.max_width = (int)(1.05 * sizex + 0.5);
+ else
+ font.max_width = (int)(1.15 * sizex + 0.5);
+
+ font.CharWidth = CharWidthTimesRoman;
+ }
+ else if (strcmp(type_face, "Helvetica")==0)
+ {
+ if (style == CD_PLAIN || style == CD_BOLD)
+ font.max_width = (int)(1.05 * sizex + 0.5);
+ else
+ font.max_width = (int)(1.15 * sizex + 0.5);
+
+ font.CharWidth = CharWidthHelvetica;
+ }
+ else
+ {
+ if (style == CD_PLAIN || style == CD_ITALIC)
+ font.max_width = (int)(0.65 * sizex + 0.5);
+ else
+ font.max_width = (int)(0.80 * sizex + 0.5);
+
+ font.CharWidth = CharWidthCourier;
+ }
+}
+
+static void cdGetFontDimEx(int *max_width, int *line_height, int *ascent, int *descent)
+{
+ if (line_height) *line_height = font.line_height;
+ if (max_width) *max_width = font.max_width;
+ if (ascent) *ascent = font.ascent;
+ if (descent) *descent = font.descent;
+}
+
+static void cdGetTextSizeEx(const char *s, int *width, int *height)
+{
+ int i = 0, numlin = 1, max_line_width = 0, line_width = 0;
+
+ while (s[i] != '\0')
+ {
+ if (s[i] == '\n')
+ {
+ numlin++;
+ line_width = 0;
+ }
+ else
+ {
+ line_width += font.CharWidth(s[i]);
+ }
+
+ if (line_width > max_line_width)
+ max_line_width = line_width;
+
+ i++;
+ }
+
+ if (height) *height = numlin * font.line_height;
+ if (width) *width = max_line_width;
+}
+
+void cdgetfontdimEX(cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ cdFontEx(canvas, canvas->font_type_face, canvas->font_style, canvas->font_size);
+ cdGetFontDimEx(max_width, height, ascent, descent);
+}
+
+void cdgettextsizeEX(cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ cdFontEx(canvas, canvas->font_type_face, canvas->font_style, canvas->font_size);
+ cdGetTextSizeEx(s, width, height);
+}
diff --git a/src/sim/sim.c b/src/sim/sim.c
new file mode 100644
index 0000000..0c657fa
--- /dev/null
+++ b/src/sim/sim.c
@@ -0,0 +1,328 @@
+/** \file
+ * \brief Simulation Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <memory.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cd_truetype.h"
+#include "sim.h"
+
+
+static unsigned char SimHatchBits[6][8] = { /* [style][y] (8x8) */
+ {0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, /* CD_HORIZONTAL */
+ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /* CD_VERTICAL */
+ {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, /* CD_BDIAGONAL */
+ {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, /* CD_FDIAGONAL */
+ {0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10}, /* CD_CROSS */
+ {0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81}};/* CD_DIAGCROSS */
+
+#define CalcYPat(y, h) (canvas->invert_yaxis? h-1-(y%h): y%h)
+#define CalcYHatch(y, h) (canvas->invert_yaxis? h-(y&h): y&h)
+
+void simFillDrawAAPixel(cdCanvas *canvas, int x, int y, unsigned short alpha_weigth)
+{
+ unsigned char aa_alpha;
+ long color, aa_color;
+
+ switch(canvas->interior_style)
+ {
+ default: /* CD_SOLID */
+ {
+ color = canvas->foreground;
+ break;
+ }
+ case CD_PATTERN:
+ {
+ long *pattern = canvas->pattern;
+ int yp = CalcYPat(y, canvas->pattern_h);
+ int xp = x % canvas->pattern_w;
+ color = pattern[canvas->pattern_w*yp + xp];
+ break;
+ }
+ case CD_HATCH:
+ {
+ unsigned char hatch = SimHatchBits[canvas->hatch_style][CalcYHatch(y, 7)];
+ unsigned char n = (unsigned char)(x&7);
+ simRotateHatchN(hatch, n);
+ if (hatch & 0x80)
+ color = canvas->foreground;
+ else if (canvas->back_opacity == CD_OPAQUE)
+ color = canvas->background;
+ else
+ return;
+ break;
+ }
+ case CD_STIPPLE:
+ {
+ unsigned char *stipple = canvas->stipple;
+ int yp = CalcYPat(y, canvas->stipple_h);
+ int xp = x % canvas->stipple_w;
+ if(stipple[canvas->stipple_w*yp + xp])
+ color = canvas->foreground;
+ else if (canvas->back_opacity == CD_OPAQUE)
+ color = canvas->background;
+ else
+ return;
+ break;
+ }
+ }
+
+ aa_alpha = (unsigned char)((alpha_weigth * cdAlpha(color)) / 255);
+ aa_color = cdEncodeAlpha(color, aa_alpha);
+ canvas->cxPixel(canvas->ctxcanvas, x, y, aa_color);
+}
+
+void simFillHorizLine(cdSimulation* simulation, int xmin, int y, int xmax)
+{
+ cdCanvas* canvas = simulation->canvas;
+
+ if(xmin > xmax)
+ _cdSwapInt(xmin, xmax);
+
+ switch(canvas->interior_style)
+ {
+ case CD_SOLID:
+ simulation->SolidLine(canvas, xmin,y,xmax);
+ break;
+ case CD_PATTERN:
+ simulation->PatternLine(canvas, xmin,xmax,y,canvas->pattern_w,
+ canvas->pattern +
+ canvas->pattern_w*CalcYPat(y, canvas->pattern_h));
+ break;
+ case CD_HATCH:
+ simulation->HatchLine(canvas, xmin,xmax,y,SimHatchBits[canvas->hatch_style][CalcYHatch(y, 7)]);
+ break;
+ case CD_STIPPLE:
+ simulation->StippleLine(canvas, xmin, xmax, y,
+ canvas->stipple_w,
+ canvas->stipple +
+ canvas->stipple_w*CalcYPat(y, canvas->stipple_h));
+ }
+}
+
+static void simSolidLine(cdCanvas* canvas, int xmin, int y, int xmax)
+{
+ /* cdpolySIM and cdboxSIM will set line attributes so this can work */
+ canvas->cxLine(canvas->ctxcanvas, xmin, y, xmax, y);
+}
+
+static void simPatternLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const long *pattern)
+{
+ cdSimulation* simulation = canvas->simulation;
+ int x,i;
+ int xb;
+ long curColor, old_color;
+
+ i = xmin % pw;
+
+ old_color = canvas->foreground;
+
+ for (x = xmin; x <= xmax;)
+ {
+ if (i == pw)
+ i = 0;
+
+ curColor=pattern[i];
+ xb=x;
+
+ while(pattern[i]==curColor && (x <= xmax))
+ {
+ i++;
+ if (i == pw)
+ i = 0;
+ x++;
+ }
+
+ if(xb==x-1)
+ canvas->cxPixel(canvas->ctxcanvas, xb,y,curColor);
+ else
+ {
+ cdCanvasSetForeground(canvas, curColor);
+ simulation->SolidLine(canvas, xb,y,x-1);
+ }
+ }
+
+ cdCanvasSetForeground(canvas, old_color);
+}
+
+static void simStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const unsigned char *stipple)
+{
+ cdSimulation* simulation = canvas->simulation;
+ int x,xb,i;
+ long fgColor,bgColor;
+ int opacity;
+ int curCase;
+
+ fgColor = canvas->foreground;
+ opacity=canvas->back_opacity;
+
+ if(opacity==CD_OPAQUE)
+ {
+ bgColor=canvas->background;
+ cdCanvasSetForeground(canvas, fgColor);
+ for (x = xmin, i=xmin%pw ; x <= xmax;)
+ {
+ if(i==pw)
+ i=0;
+ xb=x;
+ curCase=stipple[i];
+ while (stipple[i]==curCase && (x<=xmax))
+ {
+ x++;
+ i++;
+ if(i==pw)
+ i=0;
+ }
+ if (curCase)
+ {
+ if(xb==x-1)
+ canvas->cxPixel(canvas->ctxcanvas, xb,y,fgColor);
+ else
+ simulation->SolidLine(canvas, xb,y,x-1);
+ }
+ }
+ cdCanvasSetForeground(canvas, bgColor);
+ for (x = xmin, i=xmin%pw ; x <= xmax;)
+ {
+ if(i==pw)
+ i=0;
+ xb=x;
+ curCase=stipple[i];
+ while (stipple[i]==curCase && (x<=xmax))
+ {
+ x++;
+ i++;
+ if(i==pw)
+ i=0;
+ }
+ if (!curCase)
+ {
+ if(xb==x-1)
+ canvas->cxPixel(canvas->ctxcanvas, xb,y,bgColor);
+ else
+ simulation->SolidLine(canvas, xb,y,x-1);
+ }
+ }
+ }
+ else
+ {
+ cdCanvasSetForeground(canvas, fgColor);
+ for (x = xmin,i=xmin%pw; x <= xmax;)
+ {
+ xb=x;
+ curCase=stipple[i];
+ while (stipple[i]==curCase && (x<=xmax))
+ {
+ i++;
+ x++;
+ if(i==pw)
+ i=0;
+ }
+ if(curCase)
+ {
+ if(xb==x-1)
+ canvas->cxPixel(canvas->ctxcanvas, xb,y,fgColor);
+ else
+ simulation->SolidLine(canvas, xb,y,x-1);
+ }
+ }
+ }
+ cdCanvasSetForeground(canvas, fgColor);
+}
+
+static void simHatchLine(cdCanvas* canvas, int xmin, int xmax, int y, unsigned char hatch)
+{
+ cdSimulation* simulation = canvas->simulation;
+ int x,xb;
+ int opacity, mask;
+ unsigned char startp, n;
+ long curColor, fgColor, bgColor;
+
+ n = (unsigned char)(xmin&7);
+ simRotateHatchN(hatch,n);
+ fgColor=canvas->foreground;
+ opacity=canvas->back_opacity;
+
+ if(opacity==CD_OPAQUE)
+ {
+ bgColor=canvas->background;
+ for (x = xmin; x <= xmax; x++)
+ {
+ curColor=(hatch&0x80)?fgColor:bgColor;
+
+ xb=x;
+ startp = hatch&0x80? 1: 0;
+ _cdRotateHatch(hatch);
+ while (startp == (hatch&0x80? 1: 0) && x <= xmax)
+ {
+ x++;
+ _cdRotateHatch(hatch);
+ }
+
+ if(xb==x)
+ canvas->cxPixel(canvas->ctxcanvas, xb,y,curColor);
+ else
+ {
+ cdCanvasSetForeground(canvas, curColor);
+ simulation->SolidLine(canvas, xb,y,x);
+ }
+ }
+ }
+ else
+ {
+ cdCanvasSetForeground(canvas, fgColor);
+ for (x = xmin; x <= xmax; x++)
+ {
+ mask=(hatch&0x80)?1:0;
+
+ xb=x;
+ startp = hatch&0x80? 1: 0;
+ _cdRotateHatch(hatch);
+ while (startp == (hatch&0x80? 1: 0) && x <= xmax)
+ {
+ x++;
+ _cdRotateHatch(hatch);
+ }
+
+ if(mask)
+ {
+ if(xb==x)
+ canvas->cxPixel(canvas->ctxcanvas, xb,y,fgColor);
+ else
+ simulation->SolidLine(canvas, xb,y,x);
+ }
+ }
+ }
+
+ cdCanvasSetForeground(canvas, fgColor);
+}
+
+cdSimulation* cdCreateSimulation(cdCanvas* canvas)
+{
+ cdSimulation* simulation = (cdSimulation*)malloc(sizeof(cdSimulation));
+ memset(simulation, 0, sizeof(cdSimulation));
+
+ simulation->canvas = canvas;
+
+ simulation->SolidLine = simSolidLine;
+ simulation->PatternLine = simPatternLine;
+ simulation->StippleLine = simStippleLine;
+ simulation->HatchLine = simHatchLine;
+
+ return simulation;
+}
+
+void cdKillSimulation(cdSimulation* simulation)
+{
+ if (simulation->tt_text) cdTT_free(simulation->tt_text);
+
+ memset(simulation, 0, sizeof(cdSimulation));
+ free(simulation);
+}
diff --git a/src/sim/sim.h b/src/sim/sim.h
new file mode 100644
index 0000000..16189a1
--- /dev/null
+++ b/src/sim/sim.h
@@ -0,0 +1,58 @@
+/** \file
+ * \brief Simulation Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#ifndef __SIM_H
+#define __SIM_H
+
+
+struct _cdSimulation
+{
+ cdTT_Text* tt_text; /* TrueType Font Simulation using FreeType library */
+
+ int antialias;
+
+ cdCanvas *canvas;
+
+ const char* font_map[100];
+ int font_map_n;
+
+ /* horizontal line draw functions */
+ void (*SolidLine)(cdCanvas* canvas, int xmin, int y, int xmax);
+ void (*PatternLine)(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const long *pattern);
+ void (*StippleLine)(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const unsigned char *stipple);
+ void (*HatchLine)(cdCanvas* canvas, int xmin, int xmax, int y, unsigned char hatch);
+};
+
+#define simRotateHatchN(_x,_n) ((_x) = ((_x) << (_n)) | ((_x) >> (8-(_n))))
+
+void simFillDrawAAPixel(cdCanvas *canvas, int x, int y, unsigned short alpha_weigth);
+void simFillHorizLine(cdSimulation* simulation, int xmin, int y, int xmax);
+void simGetPenPos(cdCanvas* canvas, int x, int y, const char* s, FT_Matrix *matrix, FT_Vector *pen);
+int simIsPointInPolyWind(cdPoint* poly, int n, int x, int y);
+
+/* list of non-horizontal line segments */
+typedef struct _simLineSegment
+{
+ int x1, y1; /* always y1 < y2 */
+ int x2, y2; /* (x2,y2) is not included in the segment to avoid duplicated intersections */
+ int x; /* incremental x from x2 to x1 */
+ int DeltaX, DeltaY, XDir;
+ unsigned short ErrorInc, ErrorAcc;
+} simLineSegment;
+
+void simAddSegment(simLineSegment* segment, int x1, int y1, int x2, int y2, int *y_max, int *y_min);
+int simSegmentInc(simLineSegment* segment, cdCanvas* canvas, int y);
+
+void simPolyFill(cdSimulation* simulation, cdPoint* poly, int n);
+void simLineThin(cdCanvas* canvas, int x1, int y1, int x2, int y2);
+void simLineThick(cdCanvas* canvas, int x1, int y1, int x2, int y2);
+void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, int *last_xi_a, int *last_yi_a, int *last_xi_b, int *last_yi_b);
+extern int simLineStyleNoReset;
+
+int simCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height);
+
+#endif
+
diff --git a/src/sim/sim_linepolyfill.c b/src/sim/sim_linepolyfill.c
new file mode 100644
index 0000000..1a20907
--- /dev/null
+++ b/src/sim/sim_linepolyfill.c
@@ -0,0 +1,1000 @@
+/** \file
+ * \brief Primitives of the Simulation Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <memory.h>
+#include <assert.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cd_truetype.h"
+#include "sim.h"
+
+
+/* para estilos de linha usando rotacao de bits */
+static const unsigned short int simLineStyleBitTable[5]=
+{
+ 0xFFFF, /* CD_CONTINUOUS */
+ 0xFF00, /* CD_DASHED */
+ 0x1111, /* CD_DOTTED */
+ 0xFE10, /* CD_DASH_DOT */
+ 0xFF24, /* CD_DASH_DOT_DOT*/
+};
+int simLineStyleNoReset = 0;
+static unsigned short int simLineStyleLastBits = 0;
+
+#define simRotateLineStyle(_x) (((_x) & 0x8000)? ((_x) << 1)|(0x0001): ((_x) << 1))
+
+#define INTENSITYSHIFT 8 /* # of bits by which to shift ErrorAcc to get intensity level */
+
+
+/* Point in Polygon was obtained from:
+ www.geometryalgorithms.com/Archive/algorithm_0103/algorithm_0103.htm
+
+ Copyright 2001, softSurfer (www.softsurfer.com)
+ This code may be freely used and modified for any purpose
+ providing that this copyright notice is included with it.
+ SoftSurfer makes no warranty for this code, and cannot be held
+ liable for any real or imagined damage resulting from its use.
+*/
+
+#define isLeft( _P0, _P1, _x, _y ) ((_P1.x - _P0.x)*(_y - _P0.y) - (_x - _P0.x)*(_P1.y - _P0.y))
+
+int simIsPointInPolyWind(cdPoint* poly, int n, int x, int y)
+{
+ int i, i1,
+ wn = 0; /* the winding number counter */
+
+ for (i = 0; i < n; i++)
+ {
+ i1 = (i+1)%n; /* next point(i+1), next of last(n-1) is first(0) */
+
+ if (poly[i].y <= y)
+ {
+ if (poly[i1].y > y) /* an upward crossing */
+ if (isLeft(poly[i], poly[i1], x, y) > 0) /* P left of edge */
+ ++wn; /* have a valid up intersect */
+ }
+ else
+ {
+ if (poly[i1].y <= y) /* a downward crossing */
+ if (isLeft(poly[i], poly[i1], x, y) < 0) /* P right of edge */
+ --wn; /* have a valid down intersect */
+ }
+ }
+
+ return wn;
+}
+
+static int compare_int(const int* xx1, const int* xx2)
+{
+ return *xx1 - *xx2;
+}
+
+void simAddSegment(simLineSegment* segment, int x1, int y1, int x2, int y2, int *y_max, int *y_min)
+{
+ /* Make sure p2.y > p1.y */
+ if (y1 > y2)
+ {
+ _cdSwapInt(y1, y2);
+ _cdSwapInt(x1, x2);
+ }
+
+ segment->x1 = x1;
+ segment->y1 = y1;
+ segment->x2 = x2;
+ segment->y2 = y2;
+
+ segment->x = x2; /* initial value */
+
+ segment->DeltaY = y2 - y1;
+ segment->DeltaX = x2 - x1;
+ if (segment->DeltaX >= 0)
+ segment->XDir = -1; /* inverted from simLineThin since here is from p2 to p1 */
+ else
+ {
+ segment->XDir = 1;
+ segment->DeltaX = -segment->DeltaX; /* make DeltaX positive */
+ }
+
+ segment->ErrorAcc = 0; /* initialize the line error accumulator to 0 */
+
+ /* Is this an X-major or Y-major line? */
+ if (segment->DeltaY > segment->DeltaX)
+ {
+ if (segment->DeltaY==0) /* do not compute for horizontal segments */
+ return;
+
+ /* Y-major line; calculate 16-bit fixed-point fractional part of a
+ pixel that X advances each time Y advances 1 pixel, truncating the
+ result so that we won't overrun the endpoint along the X axis */
+ segment->ErrorInc = (unsigned short)(((unsigned long)segment->DeltaX << 16) / (unsigned long)segment->DeltaY);
+ }
+ else
+ {
+ if (segment->DeltaX==0) /* do not compute for vertical segments */
+ return;
+
+ /* It's an X-major line; calculate 16-bit fixed-point fractional part of a
+ pixel that Y advances each time X advances 1 pixel, truncating the
+ result to avoid overrunning the endpoint along the X axis */
+ segment->ErrorInc = (unsigned short)(((unsigned long)segment->DeltaY << 16) / (unsigned long)segment->DeltaX);
+ }
+
+ /* also calculates y_max and y_min of the polygon */
+ if (y2 > *y_max)
+ *y_max = y2;
+ if (y1 < *y_min)
+ *y_min = y1;
+}
+
+int simSegmentInc(simLineSegment* segment, cdCanvas* canvas, int y)
+{
+ unsigned short ErrorAccTemp, Weighting;
+
+ if (segment->DeltaY == 0)
+ {
+ /* Horizontal line */
+ while (segment->DeltaX-- != 0)
+ segment->x += segment->XDir;
+ return segment->x;
+ }
+
+ if (segment->DeltaX == 0)
+ {
+ /* Vertical line */
+ segment->DeltaY--;
+ return segment->x;
+ }
+
+ if (segment->DeltaX == segment->DeltaY)
+ {
+ /* Perfect Diagonal line */
+ segment->x += segment->XDir;
+ segment->DeltaY--;
+ return segment->x;
+ }
+
+ /* Is this an X-major or Y-major line? */
+ if (segment->DeltaY > segment->DeltaX)
+ {
+ /* Increment pixels other than the first and last */
+ ErrorAccTemp = segment->ErrorAcc; /* remember currrent accumulated error */
+ segment->ErrorAcc += segment->ErrorInc; /* calculate error for next pixel */
+ if (segment->ErrorAcc <= ErrorAccTemp)
+ {
+ /* The error accumulator turned over, so advance the X coord */
+ segment->x += segment->XDir;
+ }
+
+ Weighting = segment->ErrorAcc >> INTENSITYSHIFT;
+
+ if (Weighting < 128)
+ return segment->x;
+ else
+ return segment->x + segment->XDir;
+ }
+ else
+ {
+ /* Increment all pixels other than the first and last */
+ int hline_end = 0;
+ while (!hline_end)
+ {
+ ErrorAccTemp = segment->ErrorAcc; /* remember currrent accumulated error */
+ segment->ErrorAcc += segment->ErrorInc; /* calculate error for next pixel */
+ if (segment->ErrorAcc <= ErrorAccTemp)
+ {
+ /* The error accumulator turned over, so advance the Y coord */
+ hline_end = 1;
+ }
+
+ segment->x += segment->XDir; /* X-major, so always advance X */
+ }
+
+ return segment->x;
+ }
+}
+
+typedef struct _simIntervalList
+{
+ int* xx;
+ int n, count;
+} simIntervalList;
+
+static int simFillCheckAAPixel(simIntervalList* line_int_list, int x)
+{
+ int i, *xx = line_int_list->xx;
+ for (i = 0; i < line_int_list->n; i+=2)
+ {
+ if (xx[i] <= x && x <= xx[i+1])
+ return 0; /* inside, already drawn, do not draw */
+ }
+ return 1;
+}
+
+static void simPolyAAPixels(cdCanvas *canvas, simIntervalList* line_int_list, int y_min, int y_max, int x1, int y1, int x2, int y2)
+{
+ unsigned short ErrorInc, ErrorAcc;
+ unsigned short ErrorAccTemp, Weighting;
+ int DeltaX, DeltaY, XDir;
+ int no_antialias = !(canvas->simulation->antialias);
+
+ /* Make sure p2.y > p1.y */
+ if (y1 > y2)
+ {
+ _cdSwapInt(y1, y2);
+ _cdSwapInt(x1, x2);
+ }
+
+ DeltaX = x2 - x1;
+ if (DeltaX >= 0)
+ XDir = 1;
+ else
+ {
+ XDir = -1;
+ DeltaX = -DeltaX; /* make DeltaX positive */
+ }
+
+ /* Special-case horizontal, vertical, and diagonal lines, which
+ require no weighting because they go right through the center of
+ every pixel */
+ DeltaY = y2 - y1;
+ if (DeltaY == 0 || DeltaX == 0 || DeltaX == DeltaY) return;
+
+ /* Line is not horizontal, diagonal, or vertical */
+
+ /* start and end pixels are not necessary
+ since they are always drawn in the previous step. */
+
+ ErrorAcc = 0; /* initialize the line error accumulator to 0 */
+
+ /* Is this an X-major or Y-major line? */
+ if (DeltaY > DeltaX)
+ {
+ ErrorInc = (unsigned short)(((unsigned long)DeltaX << 16) / (unsigned long)DeltaY);
+
+ /* Draw all pixels other than the first and last */
+ while (--DeltaY)
+ {
+ ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
+ ErrorAcc += ErrorInc; /* calculate error for next pixel */
+ if (ErrorAcc <= ErrorAccTemp)
+ x1 += XDir;
+
+ y1++; /* Y-major, so always advance Y */
+
+ Weighting = ErrorAcc >> INTENSITYSHIFT;
+
+ if (y1 < y_min || y1 > y_max) continue;
+
+ if (no_antialias)
+ {
+ if (Weighting < 128)
+ {
+ if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1))
+ simFillDrawAAPixel(canvas, x1, y1, 255);
+ }
+ else
+ {
+ if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1 + XDir))
+ simFillDrawAAPixel(canvas, x1 + XDir, y1, 255);
+ }
+ }
+ else
+ {
+ if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1))
+ simFillDrawAAPixel(canvas, x1, y1, 255-Weighting);
+
+ if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1 + XDir))
+ simFillDrawAAPixel(canvas, x1 + XDir, y1, Weighting);
+ }
+ }
+ }
+ else
+ {
+ ErrorInc = (unsigned short)(((unsigned long)DeltaY << 16) / (unsigned long)DeltaX);
+
+ /* Draw all pixels other than the first and last */
+ while (--DeltaX)
+ {
+ ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
+ ErrorAcc += ErrorInc; /* calculate error for next pixel */
+ if (ErrorAcc <= ErrorAccTemp)
+ y1++;
+
+ x1 += XDir; /* X-major, so always advance X */
+
+ Weighting = ErrorAcc >> INTENSITYSHIFT;
+
+ if (y1 < y_min || y1 > y_max) continue;
+
+ if (no_antialias)
+ {
+ if (Weighting < 128)
+ {
+ if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1))
+ simFillDrawAAPixel(canvas, x1, y1, 255);
+ }
+ else
+ {
+ if (y1+1 < y_min || y1+1 > y_max) continue;
+
+ if (simFillCheckAAPixel(line_int_list+(y1+1-y_min), x1))
+ simFillDrawAAPixel(canvas, x1, y1+1, 255);
+ }
+ }
+ else
+ {
+ if (simFillCheckAAPixel(line_int_list+(y1-y_min), x1))
+ simFillDrawAAPixel(canvas, x1, y1, 255-Weighting);
+
+ if (y1+1 < y_min || y1+1 > y_max) continue;
+
+ if (simFillCheckAAPixel(line_int_list+(y1+1-y_min), x1))
+ simFillDrawAAPixel(canvas, x1, y1+1, Weighting);
+ }
+ }
+ }
+}
+
+static void simLineIntervallInit(simIntervalList* line_int_list, int count)
+{
+ line_int_list->xx = malloc(sizeof(int)*count);
+ line_int_list->n = 0;
+ line_int_list->count = count;
+}
+
+static void simLineIntervallAdd(simIntervalList* line_int_list, int x1, int x2)
+{
+ int i = line_int_list->n;
+ line_int_list->xx[i] = x1;
+ line_int_list->xx[i+1] = x2;
+ line_int_list->n += 2;
+}
+
+void simPolyFill(cdSimulation* simulation, cdPoint* poly, int n)
+{
+ simLineSegment *seg_i;
+ simIntervalList* line_int_list, *line_il;
+ int y_max, y_min, i, y, i1, fill_mode, num_lines,
+ inter_count, width, height, *xx;
+
+ simLineSegment *segment = (simLineSegment *)malloc(n*sizeof(simLineSegment));
+
+ width = simulation->canvas->w;
+ height = simulation->canvas->h;
+ fill_mode = simulation->canvas->fill_mode;
+
+ y_max = poly[0].y;
+ y_min = poly[0].y;
+ for(i = 0; i < n; i++)
+ {
+ i1 = (i+1)%n; /* next point(i+1), next of last(n-1) is first(0) */
+ simAddSegment(segment+i, poly[i].x, poly[i].y, poly[i1].x, poly[i1].y, &y_max, &y_min);
+ }
+
+ if (y_min > height-1 || y_max < 0)
+ {
+ free(segment);
+ return;
+ }
+
+ if (y_min < 0)
+ y_min = 0;
+
+ if (y_max > height-1)
+ num_lines = height-y_min;
+ else
+ num_lines = y_max-y_min+1;
+
+ line_int_list = malloc(sizeof(simIntervalList)*num_lines);
+ memset(line_int_list, 0, sizeof(simIntervalList)*num_lines);
+
+ xx = (int*)malloc((n+1)*sizeof(int));
+
+ /* for all horizontal lines between y_max and y_min */
+ for(y = y_max; y >= y_min; y--)
+ {
+ inter_count = 0;
+
+ /* for all segments, calculates the intervals to be filled
+ from the intersection with the horizontal line y. */
+ for(i = 0; i < n; i++)
+ {
+ seg_i = segment + i;
+
+ /* if the minimum Y coordinate of the segment is greater than the current y, then ignore the segment. */
+ /* if it is an horizontal line, then ignore the segment. */
+ if (seg_i->y1 > y ||
+ seg_i->y1 == seg_i->y2)
+ continue;
+
+ if (y == seg_i->y1) /* intersection at the start point (x1,y1) */
+ {
+ int i_next = (i==n-1)? 0: i+1;
+ int i_prev = (i==0)? n-1: i-1;
+ simLineSegment *seg_i_next = segment + i_next;
+ simLineSegment *seg_i_prev = segment + i_prev;
+
+ /* always save at least one intersection point for (y1) */
+
+ xx[inter_count++] = seg_i->x1; /* save the intersection point */
+
+ /* check for missing bottom-corner points (|_|), must duplicate the intersection */
+ if ((seg_i_next->y1 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */
+ (seg_i_prev->y1 == y && seg_i_prev->y2 == seg_i_prev->y1)) /* previous is an horizontal line */
+ {
+ xx[inter_count++] = seg_i->x1; /* save the intersection point */
+ }
+ }
+ else if ((y > seg_i->y1) && (y < seg_i->y2)) /* intersection inside the segment, do not include y2 */
+ {
+ xx[inter_count++] = simSegmentInc(seg_i, simulation->canvas, y); /* save the intersection point */
+ }
+ else if (y == seg_i->y2) /* intersection at the end point (x2,y2) */
+ {
+ int i_next = (i==n-1)? 0: i+1;
+ int i_prev = (i==0)? n-1: i-1;
+ simLineSegment *seg_i_next = segment + i_next;
+ simLineSegment *seg_i_prev = segment + i_prev;
+
+ /* only save the intersection point for (y2) if not handled by (y1) of another segment */
+
+ /* check for missing top-corner points (^) or (|¯¯|) */
+ if ((seg_i_next->y2 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */
+ (seg_i_prev->y2 == y && seg_i_prev->y2 == seg_i_prev->y1) || /* previous is an horizontal line */
+ (seg_i_next->y2 == y && seg_i_next->x2 == seg_i->x2 && seg_i_next->x1 != seg_i->x1) ||
+ (seg_i_prev->y2 == y && seg_i_prev->x2 == seg_i->x2 && seg_i_prev->x1 != seg_i->x1))
+ {
+ xx[inter_count++] = seg_i->x2; /* save the intersection point */
+ }
+ }
+ }
+
+ /* if outside the canvas, ignore the intervals and */
+ /* continue since the segments where updated. */
+ if (y > height-1 || inter_count == 0)
+ continue;
+
+ /* sort the intervals */
+ qsort(xx, inter_count, sizeof(int), (int (*)(const void*,const void*))compare_int);
+
+ line_il = line_int_list+(y-y_min);
+ simLineIntervallInit(line_il, inter_count*2);
+
+ /* for all intervals, fill the interval */
+ for(i = 0; i < inter_count; i += 2) /* process only pairs */
+ {
+ if (fill_mode == CD_EVENODD)
+ {
+ /* since it fills only pairs of intervals, */
+ /* it is the EVENODD fill rule. */
+ simFillHorizLine(simulation, xx[i], y, xx[i+1]);
+ simLineIntervallAdd(line_il, xx[i], xx[i+1]);
+ }
+ else
+ {
+ simFillHorizLine(simulation, xx[i], y, xx[i+1]);
+ simLineIntervallAdd(line_il, xx[i], xx[i+1]);
+ if ((i+2 < inter_count) && (xx[i+1] < xx[i+2])) /* avoid point intervals */
+ if (simIsPointInPolyWind(poly, n, (xx[i+1]+xx[i+2])/2, y)) /* if the next interval is inside the polygon then fill it */
+ {
+ simFillHorizLine(simulation, xx[i+1], y, xx[i+2]);
+ simLineIntervallAdd(line_il, xx[i+1], xx[i+2]);
+ }
+ }
+ }
+ }
+
+ free(xx);
+ free(segment);
+
+ /* Once the polygon has been filled, now let's draw the
+ * antialiased and incomplete pixels at the edges */
+
+ if (y_max > height-1)
+ y_max = height-1;
+
+ /* Go through all line segments of the poly */
+ for(i = 0; i < n; i++)
+ {
+ i1 = (i+1)%n;
+ simPolyAAPixels(simulation->canvas, line_int_list, y_min, y_max, poly[i].x, poly[i].y, poly[i1].x, poly[i1].y);
+ }
+
+ for (i = 0; i < num_lines; i++)
+ {
+ if (line_int_list[i].xx)
+ free(line_int_list[i].xx);
+ }
+ free(line_int_list);
+}
+
+/*************************************************************************************/
+/*************************************************************************************/
+
+#define _cdLineDrawPixel(_canvas, _x1, _y1, _ls, _fgcolor, _bgcolor) \
+{ \
+ if (_ls & 1) \
+ _canvas->cxPixel(_canvas->ctxcanvas, _x1, _y1, _fgcolor); \
+ else if (canvas->back_opacity == CD_OPAQUE) \
+ _canvas->cxPixel(_canvas->ctxcanvas, _x1, _y1, _bgcolor); \
+}
+
+void simLineThick(cdCanvas* canvas, int x1, int y1, int x2, int y2)
+{
+ const int interior = canvas->interior_style;
+ const int width = canvas->line_width;
+ const int style = canvas->line_style;
+
+ const int dx = x2-x1;
+ const int dy = y2-y1;
+
+ const double len = hypot(dx,dy);
+
+ const double dnx = dx/len;
+ const double dny = dy/len;
+
+ const int w1 = (int)width/2;
+ const int w2 = width-w1;
+
+ const int n1x = cdRound( w1*dny);
+ const int n1y = cdRound(-w1*dnx);
+
+ const int n2x = cdRound(-w2*dny);
+ const int n2y = cdRound( w2*dnx);
+
+ const int p1x = x1 + n1x;
+ const int p1y = y1 + n1y;
+ const int p2x = x1 + n2x;
+ const int p2y = y1 + n2y;
+ const int p3x = p2x + dx;
+ const int p3y = p2y + dy;
+ const int p4x = p1x + dx;
+ const int p4y = p1y + dy;
+
+ cdPoint poly[4];
+
+ cdCanvasLineWidth(canvas, 1);
+ cdCanvasInteriorStyle(canvas, CD_SOLID);
+ cdCanvasLineStyle(canvas, CD_CONTINUOUS);
+
+ poly[0].x = p1x;
+ poly[0].y = p1y;
+ poly[1].x = p2x;
+ poly[1].y = p2y;
+ poly[2].x = p3x;
+ poly[2].y = p3y;
+ poly[3].x = p4x;
+ poly[3].y = p4y;
+
+ simPolyFill(canvas->simulation, poly, 4);
+
+ cdCanvasLineWidth(canvas, width);
+ cdCanvasInteriorStyle(canvas, interior);
+ cdCanvasLineStyle(canvas, style);
+}
+
+void simLineThin(cdCanvas* canvas, int x1, int y1, int x2, int y2)
+{
+ unsigned short ErrorInc, ErrorAcc;
+ unsigned short ErrorAccTemp, Weighting;
+ int DeltaX, DeltaY, XDir;
+ long aa_fgcolor;
+ unsigned char alpha = cdAlpha(canvas->foreground), aa_alpha;
+ int no_antialias = !(canvas->simulation->antialias);
+ unsigned short int ls;
+ long fgcolor = canvas->foreground;
+ long bgcolor = canvas->background;
+
+ if (simLineStyleNoReset == 2)
+ ls = simLineStyleLastBits;
+ else
+ {
+ ls = simLineStyleBitTable[canvas->line_style];
+
+ if (simLineStyleNoReset == 1)
+ simLineStyleNoReset = 2;
+ }
+
+ /* Make sure p2.y > p1.y */
+ if (y1 > y2)
+ {
+ _cdSwapInt(y1, y2);
+ _cdSwapInt(x1, x2);
+ }
+
+ /* Draw the initial pixel, which is always exactly intersected by
+ the line and so needs no weighting */
+ _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor);
+ ls = simRotateLineStyle(ls);
+
+ DeltaX = x2 - x1;
+ if (DeltaX >= 0)
+ XDir = 1;
+ else
+ {
+ XDir = -1;
+ DeltaX = -DeltaX; /* make DeltaX positive */
+ }
+
+ /* Special-case horizontal, vertical, and diagonal lines, which
+ require no weighting because they go right through the center of
+ every pixel */
+ DeltaY = y2 - y1;
+ if (DeltaY == 0)
+ {
+ /* Horizontal line */
+ while (DeltaX-- != 0)
+ {
+ x1 += XDir;
+ _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor);
+ ls = simRotateLineStyle(ls);
+ }
+ simLineStyleLastBits = ls;
+ return;
+ }
+
+ if (DeltaX == 0)
+ {
+ /* Vertical line */
+ do
+ {
+ y1++;
+ _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor);
+ ls = simRotateLineStyle(ls);
+ } while (--DeltaY != 0);
+ simLineStyleLastBits = ls;
+ return;
+ }
+
+ if (DeltaX == DeltaY)
+ {
+ /* Perfect Diagonal line */
+ do
+ {
+ x1 += XDir;
+ y1++;
+ _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor);
+ ls = simRotateLineStyle(ls);
+ } while (--DeltaY != 0);
+ simLineStyleLastBits = ls;
+ return;
+ }
+
+ /* Line is not horizontal, diagonal, or vertical */
+
+ ErrorAcc = 0; /* initialize the line error accumulator to 0 */
+
+ /* Is this an X-major or Y-major line? */
+ if (DeltaY > DeltaX)
+ {
+ /* Y-major line; calculate 16-bit fixed-point fractional part of a
+ pixel that X advances each time Y advances 1 pixel, truncating the
+ result so that we won't overrun the endpoint along the X axis */
+ ErrorInc = (unsigned short)(((unsigned long)DeltaX << 16) / (unsigned long)DeltaY);
+
+ /* Draw all pixels other than the first and last */
+ while (--DeltaY)
+ {
+ ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
+ ErrorAcc += ErrorInc; /* calculate error for next pixel */
+ if (ErrorAcc <= ErrorAccTemp)
+ {
+ /* The error accumulator turned over, so advance the X coord */
+ x1 += XDir;
+ }
+
+ y1++; /* Y-major, so always advance Y */
+
+ Weighting = ErrorAcc >> INTENSITYSHIFT;
+
+ if (no_antialias)
+ {
+ if (Weighting < 128)
+ _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor)
+ else
+ _cdLineDrawPixel(canvas, x1 + XDir, y1, ls, fgcolor, bgcolor)
+ ls = simRotateLineStyle(ls);
+ }
+ else
+ {
+ /* The IntensityBits most significant bits of ErrorAcc give us the
+ intensity weighting for this pixel, and the complement of the
+ weighting for the paired pixel.
+ Combine the Weighting with the existing alpha,
+ When Weighting is zero alpha must be fully preserved. */
+ aa_alpha = ((255-Weighting) * alpha) / 255;
+
+ aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha);
+ _cdLineDrawPixel(canvas, x1, y1, ls, aa_fgcolor, bgcolor);
+ aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha);
+ _cdLineDrawPixel(canvas, x1 + XDir, y1, ls, aa_fgcolor, bgcolor);
+ ls = simRotateLineStyle(ls);
+ }
+ }
+ /* Draw the final pixel, which is always exactly intersected by the line
+ and so needs no weighting */
+ _cdLineDrawPixel(canvas, x2, y2, ls, fgcolor, bgcolor);
+ ls = simRotateLineStyle(ls);
+ }
+ else
+ {
+ /* It's an X-major line; calculate 16-bit fixed-point fractional part of a
+ pixel that Y advances each time X advances 1 pixel, truncating the
+ result to avoid overrunning the endpoint along the X axis */
+ ErrorInc = (unsigned short)(((unsigned long)DeltaY << 16) / (unsigned long)DeltaX);
+
+ /* Draw all pixels other than the first and last */
+ while (--DeltaX)
+ {
+ ErrorAccTemp = ErrorAcc; /* remember currrent accumulated error */
+ ErrorAcc += ErrorInc; /* calculate error for next pixel */
+ if (ErrorAcc <= ErrorAccTemp)
+ {
+ /* The error accumulator turned over, so advance the Y coord */
+ y1++;
+ }
+
+ x1 += XDir; /* X-major, so always advance X */
+
+ Weighting = ErrorAcc >> INTENSITYSHIFT;
+
+ if (no_antialias)
+ {
+ if (Weighting < 128)
+ _cdLineDrawPixel(canvas, x1, y1, ls, fgcolor, bgcolor)
+ else
+ _cdLineDrawPixel(canvas, x1, y1+1, ls, fgcolor, bgcolor)
+ ls = simRotateLineStyle(ls);
+ }
+ else
+ {
+ /* The IntensityBits most significant bits of ErrorAcc give us the
+ intensity weighting for this pixel, and the complement of the
+ weighting for the paired pixel.
+ Combine the Weighting with the existing alpha,
+ When Weighting is zero alpha must be fully preserved. */
+ aa_alpha = ((255-Weighting) * alpha) / 255;
+
+ aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha);
+ _cdLineDrawPixel(canvas, x1, y1, ls, aa_fgcolor, bgcolor);
+ aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha);
+ _cdLineDrawPixel(canvas, x1, y1+1, ls, aa_fgcolor, bgcolor);
+ ls = simRotateLineStyle(ls);
+ }
+ }
+
+ /* Draw the final pixel, which is always exactly intersected by the line
+ and so needs no weighting */
+ _cdLineDrawPixel(canvas, x2, y2, ls, fgcolor, bgcolor);
+ ls = simRotateLineStyle(ls);
+ }
+
+ simLineStyleLastBits = ls;
+}
+
+void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, int *last_xi_a, int *last_yi_a, int *last_xi_b, int *last_yi_b)
+{
+ double DeltaX, DeltaY, a, b;
+ long aa_fgcolor;
+ unsigned char alpha = cdAlpha(canvas->foreground), aa_alpha;
+ int no_antialias = !(canvas->simulation->antialias);
+ int yi, xi, update_a = 1, update_b = 1;
+ unsigned short int ls;
+ long fgcolor = canvas->foreground;
+ long bgcolor = canvas->background;
+
+ if (simLineStyleNoReset == 2)
+ ls = simLineStyleLastBits;
+ else
+ {
+ ls = simLineStyleBitTable[canvas->line_style];
+
+ if (simLineStyleNoReset == 1)
+ simLineStyleNoReset = 2;
+ }
+
+ DeltaX = fabs(x2 - x1);
+ DeltaY = fabs(y2 - y1);
+
+ if (DeltaX > 0.0001)
+ {
+ a = (y1-y2)/(x1-x2);
+ b = y1 - a*x1;
+ }
+ else
+ {
+ a = 0;
+ b = x1;
+ }
+
+ /* NOTICE: all the complexity of this function
+ is related to check and update the previous point */
+
+ /* Is this an X-major or Y-major line? */
+ if (DeltaY > DeltaX)
+ {
+ /* Increment in Y */
+ int y1i = _cdRound(y1),
+ y2i = _cdRound(y2);
+ int yi_first = y1i;
+ int yi_last = y2i, xi_last;
+
+ if (y1i > y2i)
+ _cdSwapInt(y1i, y2i);
+
+ for (yi = y1i; yi <= y2i; yi++)
+ {
+ double x;
+ if (a)
+ x = (yi - b)/a;
+ else
+ x = b;
+
+ xi = (int)floor(x);
+
+ /* if at the last pixel, store the return value */
+ if (yi == yi_last)
+ xi_last = xi;
+
+ /* Combine the Weighting with the existing alpha,
+ When Weighting is zero alpha must be fully preserved. */
+ aa_alpha = (int)((1.0-(x - xi)) * alpha);
+
+ if (no_antialias)
+ {
+ if (aa_alpha > 128)
+ _cdLineDrawPixel(canvas, xi, yi, ls, fgcolor, bgcolor)
+ else
+ _cdLineDrawPixel(canvas, xi+1, yi, ls, fgcolor, bgcolor)
+ }
+ else
+ {
+ if (yi == yi_first)
+ {
+ if (yi == yi_last) /* one pixel only */
+ {
+ update_a = 0;
+ update_b = 0;
+ }
+
+ /* if at first, compare with the last two previously drawn */
+ /* if the new is equal to the previous, do NOT draw */
+ if ((xi != *last_xi_a || yi != *last_yi_a) &&
+ (xi != *last_xi_b || yi != *last_yi_b))
+ {
+ aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha);
+ _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor, bgcolor);
+
+ if (yi == yi_last) /* one pixel only */
+ update_a = 1;
+ }
+
+ if ((xi+1 != *last_xi_a || yi != *last_yi_a) &&
+ (xi+1 != *last_xi_b || yi != *last_yi_b))
+ {
+ aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha);
+ _cdLineDrawPixel(canvas, xi+1, yi, ls, aa_fgcolor, bgcolor);
+
+ if (yi == yi_last) /* one pixel only */
+ update_b = 1;
+ }
+ }
+ else
+ {
+ aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha);
+ _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor, bgcolor);
+ aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha);
+ _cdLineDrawPixel(canvas, xi+1, yi, ls, aa_fgcolor, bgcolor);
+ }
+ }
+
+ ls = simRotateLineStyle(ls);
+ }
+
+ if (update_a)
+ {
+ *last_xi_a = xi_last;
+ *last_yi_a = yi_last;
+ }
+ if (update_b)
+ {
+ *last_xi_b = xi_last+1;
+ *last_yi_b = yi_last;
+ }
+ }
+ else
+ {
+ /* Increment in X */
+ int x1i = _cdRound(x1),
+ x2i = _cdRound(x2);
+ int xi_first = x1i;
+ int xi_last = x2i, yi_last;
+
+ if (x1i > x2i)
+ _cdSwapInt(x1i, x2i);
+
+ for (xi = x1i; xi <= x2i; xi++)
+ {
+ double y = a*xi + b;
+ yi = (int)floor(y);
+
+ /* if at the last pixel, store the return value */
+ if (xi == xi_last)
+ yi_last = yi;
+
+ /* Combine the Weighting with the existing alpha,
+ When Weighting is zero alpha must be fully preserved. */
+ aa_alpha = (int)((1.0-(y - yi)) * alpha);
+
+ if (no_antialias)
+ {
+ if (aa_alpha > 128)
+ _cdLineDrawPixel(canvas, xi, yi, ls, fgcolor, bgcolor)
+ else
+ _cdLineDrawPixel(canvas, xi, yi+1, ls, fgcolor, bgcolor)
+ }
+ else
+ {
+ if (xi == xi_first)
+ {
+ if (xi == xi_last) /* one pixel only */
+ {
+ update_a = 0;
+ update_b = 0;
+ }
+
+ /* if at first, compare with the last to draw */
+ /* if new is equal to the previous, do NOT draw */
+ if ((xi != *last_xi_a || yi != *last_yi_a) &&
+ (xi != *last_xi_b || yi != *last_yi_b))
+ {
+ aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha);
+ _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor, bgcolor);
+
+ if (xi == xi_last) /* one pixel only */
+ update_a = 1;
+ }
+
+ if ((xi != *last_xi_a || yi+1 != *last_yi_a) &&
+ (xi != *last_xi_b || yi+1 != *last_yi_b))
+ {
+ aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha);
+ _cdLineDrawPixel(canvas, xi, yi+1, ls, aa_fgcolor, bgcolor);
+
+ if (xi == xi_last) /* one pixel only */
+ update_b = 1;
+ }
+ }
+ else
+ {
+ aa_fgcolor = cdEncodeAlpha(fgcolor, aa_alpha);
+ _cdLineDrawPixel(canvas, xi, yi, ls, aa_fgcolor, bgcolor);
+ aa_fgcolor = cdEncodeAlpha(fgcolor, 255-aa_alpha);
+ _cdLineDrawPixel(canvas, xi, yi+1, ls, aa_fgcolor, bgcolor);
+ }
+ }
+
+ ls = simRotateLineStyle(ls);
+ }
+
+ if (update_a)
+ {
+ *last_xi_a = xi_last;
+ *last_yi_a = yi_last;
+ }
+ if (update_b)
+ {
+ *last_xi_b = xi_last;
+ *last_yi_b = yi_last+1;
+ }
+ }
+
+ simLineStyleLastBits = ls;
+}
diff --git a/src/sim/sim_other.c b/src/sim/sim_other.c
new file mode 100644
index 0000000..0954406
--- /dev/null
+++ b/src/sim/sim_other.c
@@ -0,0 +1,411 @@
+/** \file
+ * \brief Simulation that is independent of the Simulation Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <memory.h>
+
+#include "cd.h"
+#include "cd_private.h"
+
+
+void cdSimMark(cdCanvas* canvas, int x, int y)
+{
+ int oldinteriorstyle = canvas->interior_style;
+ int oldlinestyle = canvas->line_style;
+ int oldlinewidth = canvas->line_width;
+ int size = canvas->mark_size;
+ int half_size = size/2;
+ int bottom = y-half_size;
+ int top = y+half_size;
+ int left = x-half_size;
+ int right = x+half_size;
+
+ if (canvas->interior_style != CD_SOLID &&
+ (canvas->mark_type == CD_CIRCLE ||
+ canvas->mark_type == CD_BOX ||
+ canvas->mark_type == CD_DIAMOND))
+ cdCanvasInteriorStyle(canvas, CD_SOLID);
+
+ if (canvas->line_style != CD_CONTINUOUS &&
+ (canvas->mark_type == CD_STAR ||
+ canvas->mark_type == CD_PLUS ||
+ canvas->mark_type == CD_X ||
+ canvas->mark_type == CD_HOLLOW_BOX ||
+ canvas->mark_type == CD_HOLLOW_CIRCLE ||
+ canvas->mark_type == CD_HOLLOW_DIAMOND))
+ cdCanvasLineStyle(canvas, CD_CONTINUOUS);
+
+ if (canvas->line_width != 1 &&
+ (canvas->mark_type == CD_STAR ||
+ canvas->mark_type == CD_PLUS ||
+ canvas->mark_type == CD_X ||
+ canvas->mark_type == CD_HOLLOW_BOX ||
+ canvas->mark_type == CD_HOLLOW_CIRCLE ||
+ canvas->mark_type == CD_HOLLOW_DIAMOND))
+ cdCanvasLineWidth(canvas, 1);
+
+ switch (canvas->mark_type)
+ {
+ case CD_STAR:
+ canvas->cxLine(canvas->ctxcanvas, left, bottom, right, top);
+ canvas->cxLine(canvas->ctxcanvas, left, top, right, bottom);
+ /* continue */
+ case CD_PLUS:
+ canvas->cxLine(canvas->ctxcanvas, left, y, right, y);
+ canvas->cxLine(canvas->ctxcanvas, x, bottom, x, top);
+ break;
+ case CD_HOLLOW_CIRCLE:
+ canvas->cxArc(canvas->ctxcanvas, x, y, size, size, 0, 360);
+ break;
+ case CD_HOLLOW_BOX:
+ canvas->cxRect(canvas->ctxcanvas, left, right, bottom, top);
+ break;
+ case CD_HOLLOW_DIAMOND:
+ canvas->cxLine(canvas->ctxcanvas, left, y, x, top);
+ canvas->cxLine(canvas->ctxcanvas, x, top, right, y);
+ canvas->cxLine(canvas->ctxcanvas, right, y, x, bottom);
+ canvas->cxLine(canvas->ctxcanvas, x, bottom, left, y);
+ break;
+ case CD_X:
+ canvas->cxLine(canvas->ctxcanvas, left, bottom, right, top);
+ canvas->cxLine(canvas->ctxcanvas, left, top, right, bottom);
+ break;
+ case CD_CIRCLE:
+ canvas->cxSector(canvas->ctxcanvas, x, y, size, size, 0, 360);
+ break;
+ case CD_BOX:
+ canvas->cxBox(canvas->ctxcanvas, left, right, bottom, top);
+ break;
+ case CD_DIAMOND:
+ {
+ cdPoint poly[5];
+ poly[0].x = left;
+ poly[0].y = y;
+ poly[1].x = x;
+ poly[1].y = top;
+ poly[2].x = right;
+ poly[2].y = y;
+ poly[3].x = x;
+ poly[3].y = bottom;
+ canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, 4);
+ }
+ break;
+ }
+
+ if (canvas->interior_style != oldinteriorstyle &&
+ (canvas->mark_type == CD_CIRCLE ||
+ canvas->mark_type == CD_BOX ||
+ canvas->mark_type == CD_DIAMOND))
+ cdCanvasInteriorStyle(canvas, oldinteriorstyle);
+
+ if (canvas->line_style != oldlinestyle &&
+ (canvas->mark_type == CD_STAR ||
+ canvas->mark_type == CD_PLUS ||
+ canvas->mark_type == CD_X ||
+ canvas->mark_type == CD_HOLLOW_BOX ||
+ canvas->mark_type == CD_HOLLOW_CIRCLE ||
+ canvas->mark_type == CD_HOLLOW_DIAMOND))
+ cdCanvasLineStyle(canvas, oldlinestyle);
+
+ if (canvas->line_width != oldlinewidth &&
+ (canvas->mark_type == CD_STAR ||
+ canvas->mark_type == CD_PLUS ||
+ canvas->mark_type == CD_X ||
+ canvas->mark_type == CD_HOLLOW_BOX ||
+ canvas->mark_type == CD_HOLLOW_CIRCLE ||
+ canvas->mark_type == CD_HOLLOW_DIAMOND))
+ cdCanvasLineWidth(canvas, oldlinewidth);
+}
+
+/* Setup Bezier coefficient array once for each control polygon.
+ */
+static void BezierForm(const cdPoint* p, cdfPoint* c)
+{
+ int k;
+ static int choose[4] = {1, 3, 3, 1};
+ for (k = 0; k < 4; k++)
+ {
+ c[k].x = p[k].x * choose[k];
+ c[k].y = p[k].y * choose[k];
+ }
+}
+
+static void fBezierForm(const cdfPoint* p, cdfPoint* c)
+{
+ int k;
+ static int choose[4] = {1, 3, 3, 1};
+ for (k = 0; k < 4; k++)
+ {
+ c[k].x = p[k].x * choose[k];
+ c[k].y = p[k].y * choose[k];
+ }
+}
+
+/* Return Point pt(t), t <= 0 <= 1 from C.
+ * BezierForm must be called once for any given control polygon.
+ */
+static void BezierCurve(const cdfPoint* c, cdfPoint *pt, double t)
+{
+ int k;
+ double t1, tt, u;
+ cdfPoint b[4];
+
+ u = t;
+
+ b[0].x = c[0].x;
+ b[0].y = c[0].y;
+ for(k = 1; k < 4; k++)
+ {
+ b[k].x = c[k].x * u;
+ b[k].y = c[k].y * u;
+ u =u*t;
+ }
+
+ pt->x = b[3].x;
+ pt->y = b[3].y;
+ t1 = 1-t;
+ tt = t1;
+ for(k = 2; k >= 0; k--)
+ {
+ pt->x += b[k].x * tt;
+ pt->y += b[k].y * tt;
+ tt =tt*t1;
+ }
+}
+
+static int BezierNumSegments(cdCanvas* canvas, const cdPoint* p)
+{
+ int i, K, dx, dy, d,
+ xmax = p[0].x,
+ ymax = p[0].y,
+ xmin = p[0].x,
+ ymin = p[0].y;
+
+ for (i = 1; i < 4; i++)
+ {
+ if (p[i].x > xmax)
+ xmax = p[i].x;
+ if (p[i].y > ymax)
+ ymax = p[i].y;
+ if (p[i].x < xmin)
+ xmin = p[i].x;
+ if (p[i].y < ymin)
+ ymin = p[i].y;
+ }
+
+ if (canvas->use_matrix)
+ {
+ cdMatrixTransformPoint(canvas->matrix, xmin, ymin, &xmin, &ymin);
+ cdMatrixTransformPoint(canvas->matrix, xmax, ymax, &xmax, &ymax);
+ }
+
+ /* diagonal of the bouding box */
+ dx = (xmax-xmin);
+ dy = (ymax-ymin);
+ d = (int)(sqrt(dx*dx + dy*dy));
+ K = d / 8;
+ if (K < 8) K = 8;
+ return K;
+}
+
+static int fBezierNumSegments(cdCanvas* canvas, const cdfPoint* p)
+{
+ int i, K, d;
+ double dx, dy,
+ xmax = p[0].x,
+ ymax = p[0].y,
+ xmin = p[0].x,
+ ymin = p[0].y;
+
+ for (i = 1; i < 4; i++)
+ {
+ if (p[i].x > xmax)
+ xmax = p[i].x;
+ if (p[i].y > ymax)
+ ymax = p[i].y;
+ if (p[i].x < xmin)
+ xmin = p[i].x;
+ if (p[i].y < ymin)
+ ymin = p[i].y;
+ }
+
+ /* diagonal of the bouding box */
+ dx = (xmax-xmin);
+ dy = (ymax-ymin);
+ d = (int)(sqrt(dx*dx + dy*dy));
+ K = d / 8;
+ if (K < 8) K = 8;
+ return K;
+}
+
+/* from sim.h */
+void simfLineThin(cdCanvas* canvas, double x1, double y1, double x2, double y2, int *last_xi_a, int *last_yi_a, int *last_xi_b, int *last_yi_b);
+
+/* Quick and Simple Bezier Curve Drawing --- Robert D. Miller
+ * Graphics GEMS V */
+void cdSimPolyBezier(cdCanvas* canvas, const cdPoint* points, int n)
+{
+ int i = 0, k, K, poly_max = 0;
+ cdfPoint pt, prev_pt;
+ cdfPoint bezier_control[4];
+ cdPoint* poly = NULL;
+ int use_poly = 0,
+ last_xi_a = -65535,
+ last_yi_a = -65535,
+ last_xi_b = -65535,
+ last_yi_b = -65535;
+
+ /* Use special floating point anti-alias line draw when
+ line_width==1, and NOT using cdlineSIM. */
+ if (canvas->line_width > 1 || canvas->cxLine != cdlineSIM)
+ use_poly = 1;
+
+ n--; /* first n is 4 */
+ while (n >= 3)
+ {
+ BezierForm(points+i, bezier_control);
+ K = BezierNumSegments(canvas, points+i);
+
+ if (use_poly && poly_max < K+1)
+ {
+ poly = realloc(poly, sizeof(cdPoint)*(K+1)); /* K+1 points */
+ if (!poly) return;
+ poly_max = K+1;
+ }
+
+ /* first segment */
+ BezierCurve(bezier_control, &pt, 0);
+ if (use_poly)
+ {
+ poly[0].x = _cdRound(pt.x);
+ poly[0].y = _cdRound(pt.y);
+ }
+ else
+ prev_pt = pt;
+
+ for(k = 1; k < K+1; k++)
+ {
+ BezierCurve(bezier_control, &pt, (double)k/(double)K);
+
+ if (use_poly)
+ {
+ poly[k].x = _cdRound(pt.x);
+ poly[k].y = _cdRound(pt.y);
+ }
+ else
+ {
+ int old_use_matrix = canvas->use_matrix;
+ double x1 = prev_pt.x,
+ y1 = prev_pt.y,
+ x2 = pt.x,
+ y2 = pt.y;
+
+ if (canvas->use_matrix && !canvas->invert_yaxis)
+ {
+ cdfMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1);
+ cdfMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2);
+ }
+
+ /* must disable transformation here, because line simulation use cxPixel */
+ canvas->use_matrix = 0;
+
+ simfLineThin(canvas, x1, y1, x2, y2, &last_xi_a, &last_yi_a, &last_xi_b, &last_yi_b);
+
+ canvas->use_matrix = old_use_matrix;
+ prev_pt = pt;
+ }
+ }
+
+ if (use_poly)
+ canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, k);
+
+ n -= 3; i += 3;
+ }
+
+ if (poly) free(poly);
+}
+
+void cdfSimPolyBezier(cdCanvas* canvas, const cdfPoint* points, int n)
+{
+ int i = 0, k, K, poly_max = 0;
+ cdfPoint pt;
+ cdfPoint bezier_control[4];
+ cdfPoint* poly = NULL;
+
+ n--; /* first n is 4 */
+ while (n >= 3)
+ {
+ fBezierForm(points+i, bezier_control);
+ K = fBezierNumSegments(canvas, points+i);
+
+ if (poly_max < K+1)
+ {
+ poly = realloc(poly, sizeof(cdfPoint)*(K+1)); /* K+1 points */
+ if (!poly) return;
+ poly_max = K+1;
+ }
+
+ /* first segment */
+ BezierCurve(bezier_control, &pt, 0);
+ poly[0].x = _cdRound(pt.x);
+ poly[0].y = _cdRound(pt.y);
+
+ for(k = 1; k < K+1; k++)
+ {
+ BezierCurve(bezier_control, &pt, (double)k/(double)K);
+
+ poly[k].x = _cdRound(pt.x);
+ poly[k].y = _cdRound(pt.y);
+ }
+
+ canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, k);
+ n -= 3; i += 3;
+ }
+
+ if (poly) free(poly);
+}
+
+void cdSimPutImageRectRGBA(cdCanvas* canvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int size, i, j, dst, src, *fx, *fy, rw, rh;
+ unsigned char *ar, *ag, *ab, al;
+
+ size = w * h;
+ ar = (unsigned char*)malloc(size*3);
+ if (!ar) return;
+ ag = ar + size;
+ ab = ag + size;
+
+ canvas->cxGetImageRGB(canvas->ctxcanvas, ar, ag, ab, x, y, w, h);
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ fx = cdGetZoomTable(w, rw, xmin);
+ fy = cdGetZoomTable(h, rh, ymin);
+
+ for (j = 0; j < h; j++)
+ {
+ for (i = 0; i < w; i++)
+ {
+ dst = j * w + i;
+ src = fy[j] * iw + fx[i];
+ al = a[src];
+ ar[dst] = CD_ALPHA_BLEND(r[src], ar[dst], al);
+ ag[dst] = CD_ALPHA_BLEND(g[src], ag[dst], al);
+ ab[dst] = CD_ALPHA_BLEND(b[src], ab[dst], al);
+ }
+ }
+
+ canvas->cxPutImageRectRGB(canvas->ctxcanvas, w, h, ar, ag, ab, x, y, w, h, 0, 0, 0, 0);
+
+ free(ar);
+
+ free(fx);
+ free(fy);
+}
diff --git a/src/sim/sim_primitives.c b/src/sim/sim_primitives.c
new file mode 100644
index 0000000..5f5e0a3
--- /dev/null
+++ b/src/sim/sim_primitives.c
@@ -0,0 +1,524 @@
+/** \file
+ * \brief Primitives of the Simulation Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <memory.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cd_truetype.h"
+#include "sim.h"
+
+void cdlineSIM(cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ int old_use_matrix = canvas->use_matrix;
+
+ if (canvas->use_matrix && !canvas->invert_yaxis)
+ {
+ cdMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1);
+ cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2);
+ }
+
+ /* must disable transformation here, because line simulation use cxPixel */
+ canvas->use_matrix = 0;
+
+ if(canvas->line_width > 1)
+ simLineThick(canvas, x1, y1, x2, y2);
+ else
+ simLineThin(canvas, x1, y1, x2, y2);
+
+ canvas->use_matrix = old_use_matrix;
+}
+
+void cdrectSIM(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ cdPoint poly[5]; /* leave room of one more point */
+ poly[0].x = xmin; poly[0].y = ymin;
+ poly[1].x = xmin; poly[1].y = ymax;
+ poly[2].x = xmax; poly[2].y = ymax;
+ poly[3].x = xmax; poly[3].y = ymin;
+ canvas->cxPoly(canvas->ctxcanvas, CD_CLOSED_LINES, poly, 4);
+}
+
+void cdboxSIM(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+
+ if (canvas->use_matrix)
+ {
+ cdPoint poly[5]; /* leave room of one more point */
+ poly[0].x = xmin; poly[0].y = ymin;
+ poly[1].x = xmin; poly[1].y = ymax;
+ poly[2].x = xmax; poly[2].y = ymax;
+ poly[3].x = xmax; poly[3].y = ymin;
+ canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, 4);
+ }
+ else
+ {
+ cdSimulation* simulation = canvas->simulation;
+ int y;
+
+ /* must set line attributes here, because fill simulation use cxLine and cxPixel */
+ int old_line_style = cdCanvasLineStyle(canvas, CD_CONTINUOUS);
+ int old_line_width = cdCanvasLineWidth(canvas, 1);
+
+ for(y=ymin;y<=ymax;y++)
+ simFillHorizLine(simulation, xmin, y, xmax);
+
+ cdCanvasLineStyle(canvas, old_line_style);
+ cdCanvasLineWidth(canvas, old_line_width);
+ }
+}
+
+void cdfSimBox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ cdfPoint poly[5]; /* leave room of one more point */
+ poly[0].x = xmin; poly[0].y = ymin;
+ poly[1].x = xmin; poly[1].y = ymax;
+ poly[2].x = xmax; poly[2].y = ymax;
+ poly[3].x = xmax; poly[3].y = ymin;
+ canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, poly, 4);
+}
+
+void cdfSimRect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ cdfPoint poly[5]; /* leave room of one more point */
+ poly[0].x = xmin; poly[0].y = ymin;
+ poly[1].x = xmin; poly[1].y = ymax;
+ poly[2].x = xmax; poly[2].y = ymax;
+ poly[3].x = xmax; poly[3].y = ymin;
+ canvas->cxFPoly(canvas->ctxcanvas, CD_CLOSED_LINES, poly, 4);
+}
+
+int simCalcEllipseNumSegments(cdCanvas* canvas, int xc, int yc, int width, int height)
+{
+ int n, dx, dy, hd;
+ int w2 = width/2;
+ int h2 = height/2;
+ int x1 = xc-w2,
+ y1 = yc-h2,
+ x2 = xc+w2,
+ y2 = yc+h2;
+
+ if (canvas->use_matrix)
+ {
+ cdMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1);
+ cdMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2);
+ }
+
+ dx = (x1-x2);
+ dy = (y1-y2);
+ hd = (int)(sqrt(dx*dx + dy*dy)/2);
+
+ /* Estimation Heuristic:
+ use half diagonal to estimate the number of segments for 360 degrees.
+ Use the difference of the half diagonal and its projection to calculate the minimum angle:
+ cos(min_angle) = hd / (hd + 1) or min_angle = acos(hd / (hd + 1))
+ The number of segments will be 360 / min_angle.
+ */
+
+ n = (int)((360.0*CD_DEG2RAD) / acos((double)hd / (hd + 1.0)) + 0.5); /* round up */
+
+ /* multiple of 4 */
+ n = ((n + 3)/4)*4;
+
+ /* minimum number is 4 */
+ if (n < 4) n = 4;
+
+ return n;
+}
+
+void cdarcSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ double c, s, sx, sy, x, y, prev_x, prev_y;
+ double da;
+ int i, yc2 = 2*yc, p,
+ last_xi_a = -65535,
+ last_yi_a = -65535,
+ last_xi_b = -65535,
+ last_yi_b = -65535;
+ cdPoint* poly = NULL;
+
+ /* number of segments of equivalent poligonal for a full ellipse */
+ int n = simCalcEllipseNumSegments(canvas, xc, yc, width, height);
+
+ /* Use special floating point anti-alias line draw when
+ line_width==1, and NOT using cdlineSIM. */
+ if (canvas->line_width > 1 || canvas->cxLine != cdlineSIM)
+ {
+ poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+1)); /* n+1 points */
+ if (!poly) return;
+ }
+
+ /* number of segments for the arc */
+ n = cdRound((fabs(angle2-angle1)*n)/360);
+ if (n < 1) n = 1;
+
+ /* converts degrees into radians */
+ angle1 *= CD_DEG2RAD;
+ angle2 *= CD_DEG2RAD;
+
+ /* generates arc points at origin with axis x and y */
+
+ da = (angle2-angle1)/n;
+ c = cos(da);
+ s = sin(da);
+ sx = -(width*s)/height;
+ sy = (height*s)/width;
+
+ x = (width/2.0f)*cos(angle1);
+ y = (height/2.0f)*sin(angle1);
+ prev_x = x;
+ prev_y = y;
+ if (poly)
+ {
+ poly[0].x = _cdRound(x)+xc;
+ poly[0].y = _cdRound(y)+yc;
+
+ if (canvas->invert_yaxis) /* must invert because of the angle orientation */
+ poly[0].y = yc2 - poly[0].y;
+
+ p = 1;
+ }
+ else
+ simLineStyleNoReset = 1;
+
+ for (i = 1; i < n+1; i++) /* n+1 points */
+ {
+ x = c*prev_x + sx*prev_y;
+ y = sy*prev_x + c*prev_y;
+
+ if (poly)
+ {
+ poly[p].x = _cdRound(x)+xc;
+ poly[p].y = _cdRound(y)+yc;
+
+ if (canvas->invert_yaxis) /* must invert because of the angle orientation */
+ poly[p].y = yc2 - poly[p].y;
+
+ if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y)
+ p++;
+ }
+ else
+ {
+ int old_use_matrix = canvas->use_matrix;
+ double x1 = prev_x+xc,
+ y1 = prev_y+yc,
+ x2 = x+xc,
+ y2 = y+yc;
+
+ if (canvas->use_matrix && !canvas->invert_yaxis)
+ {
+ cdfMatrixTransformPoint(canvas->matrix, x1, y1, &x1, &y1);
+ cdfMatrixTransformPoint(canvas->matrix, x2, y2, &x2, &y2);
+ }
+
+ /* must disable transformation here, because line simulation use cxPixel */
+ canvas->use_matrix = 0;
+
+ if (canvas->invert_yaxis) /* must invert because of the angle orientation */
+ {
+ y1 = yc2 - y1;
+ y2 = yc2 - y2;
+ }
+
+ simfLineThin(canvas, x1, y1, x2, y2, &last_xi_a, &last_yi_a, &last_xi_b, &last_yi_b);
+
+ canvas->use_matrix = old_use_matrix;
+ }
+
+ prev_x = x;
+ prev_y = y;
+ }
+
+ if (poly)
+ {
+ canvas->cxPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, p);
+ free(poly);
+ }
+ else
+ simLineStyleNoReset = 0;
+}
+
+void cdfSimArc(cdCtxCanvas *ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ double c, s, sx, sy, x, y, prev_x, prev_y, da;
+ int i, p;
+ cdfPoint* poly = NULL;
+
+ /* number of segments of equivalent poligonal for a full ellipse */
+ int n = simCalcEllipseNumSegments(canvas, (int)xc, (int)yc, (int)width, (int)height);
+
+ poly = (cdfPoint*)malloc(sizeof(cdfPoint)*(n+1)); /* n+1 points */
+ if (!poly) return;
+
+ /* number of segments for the arc */
+ n = cdRound((fabs(angle2-angle1)*n)/360);
+ if (n < 1) n = 1;
+
+ /* converts degrees into radians */
+ angle1 *= CD_DEG2RAD;
+ angle2 *= CD_DEG2RAD;
+
+ /* generates arc points at origin with axis x and y */
+
+ da = (angle2-angle1)/n;
+ c = cos(da);
+ s = sin(da);
+ sx = -(width*s)/height;
+ sy = (height*s)/width;
+
+ x = (width/2.0f)*cos(angle1);
+ y = (height/2.0f)*sin(angle1);
+ prev_x = x;
+ prev_y = y;
+ poly[0].x = x+xc;
+ poly[0].y = y+yc;
+
+ p = 1;
+
+ for (i = 1; i < n+1; i++) /* n+1 points */
+ {
+ x = c*prev_x + sx*prev_y;
+ y = sy*prev_x + c*prev_y;
+
+ poly[p].x = x+xc;
+ poly[p].y = y+yc;
+
+ if (poly[p-1].x != poly[p].x ||
+ poly[p-1].y != poly[p].y)
+ p++;
+
+ prev_x = x;
+ prev_y = y;
+ }
+
+ canvas->cxFPoly(canvas->ctxcanvas, CD_OPEN_LINES, poly, p);
+ free(poly);
+}
+
+void cdfSimElipse(cdCtxCanvas* ctxcanvas, double xc, double yc, double width, double height, double angle1, double angle2, int sector)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ double c, s, sx, sy, x, y, prev_x, prev_y, da;
+ int i, p;
+ cdfPoint* poly;
+
+ /* number of segments of equivalent poligonal for a full ellipse */
+ int n = simCalcEllipseNumSegments(canvas, (int)xc, (int)yc, (int)width, (int)height);
+
+ /* number of segments for the arc */
+ n = cdRound(((angle2-angle1)*n)/360);
+ if (n < 1) n = 1;
+
+ poly = (cdfPoint*)malloc(sizeof(cdfPoint)*(n+2+1)); /* n+1 points +1 center */
+
+ /* converts degrees into radians */
+ angle1 *= CD_DEG2RAD;
+ angle2 *= CD_DEG2RAD;
+
+ /* generates arc points at origin with axis x and y */
+
+ da = (angle2-angle1)/n;
+ c = cos(da);
+ s = sin(da);
+ sx = -(width*s)/height;
+ sy = (height*s)/width;
+
+ x = xc + (width/2.0)*cos(angle1);
+ y = yc + (height/2.0)*sin(angle1);
+ prev_x = x;
+ prev_y = y;
+
+ poly[0].x = x;
+ poly[0].y = y;
+ p = 1;
+
+ for (i = 1; i < n+1; i++) /* n+1 points */
+ {
+ x = xc + c*(prev_x-xc) + sx*(prev_y-yc);
+ y = yc + sy*(prev_x-xc) + c*(prev_y-yc);
+
+ poly[p].x = x;
+ poly[p].y = y;
+
+ if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y)
+ p++;
+
+ prev_x = x;
+ prev_y = y;
+ }
+
+ if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y)
+ {
+ if (sector) /* cdSector */
+ {
+ /* add center */
+ poly[p].x = xc;
+ poly[p].y = yc;
+ }
+ else /* cdChord */
+ {
+ /* add initial point */
+ poly[p].x = poly[0].x;
+ poly[p].y = poly[0].y;
+ }
+ p++;
+ }
+
+ canvas->cxFPoly(canvas->ctxcanvas, CD_FILL, poly, p);
+ free(poly);
+}
+
+static void cdSimElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2, int sector)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ float c, s, sx, sy, x, y, prev_x, prev_y;
+ double da;
+ int i, p, yc2 = 2*yc;
+ cdPoint* poly;
+
+ /* number of segments of equivalent poligonal for a full ellipse */
+ int n = simCalcEllipseNumSegments(canvas, xc, yc, width, height);
+
+ /* number of segments for the arc */
+ n = cdRound(((angle2-angle1)*n)/360);
+ if (n < 1) n = 1;
+
+ poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+2+1)); /* n+1 points +1 center */
+
+ /* converts degrees into radians */
+ angle1 *= CD_DEG2RAD;
+ angle2 *= CD_DEG2RAD;
+
+ /* generates arc points at origin with axis x and y */
+
+ da = (angle2-angle1)/n;
+ c = (float)cos(da);
+ s = (float)sin(da);
+ sx = -(width*s)/height;
+ sy = (height*s)/width;
+
+ x = xc + (width/2.0f)*(float)cos(angle1);
+ y = yc + (height/2.0f)*(float)sin(angle1);
+ prev_x = x;
+ prev_y = y;
+
+ poly[0].x = _cdRound(x);
+ poly[0].y = _cdRound(y);
+ if (canvas->invert_yaxis)
+ poly[0].y = yc2 - poly[0].y;
+ p = 1;
+
+ for (i = 1; i < n+1; i++) /* n+1 points */
+ {
+ x = xc + c*(prev_x-xc) + sx*(prev_y-yc);
+ y = yc + sy*(prev_x-xc) + c*(prev_y-yc);
+
+ poly[p].x = _cdRound(x);
+ poly[p].y = _cdRound(y);
+
+ if (canvas->invert_yaxis)
+ poly[p].y = yc2 - poly[p].y;
+
+ if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y)
+ p++;
+
+ prev_x = x;
+ prev_y = y;
+ }
+
+ if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y)
+ {
+ if (sector) /* cdSector */
+ {
+ /* add center */
+ poly[p].x = xc;
+ poly[p].y = yc;
+ }
+ else /* cdChord */
+ {
+ /* add initial point */
+ poly[p].x = poly[0].x;
+ poly[p].y = poly[0].y;
+ }
+ p++;
+ }
+
+ canvas->cxPoly(canvas->ctxcanvas, CD_FILL, poly, p);
+
+ free(poly);
+}
+
+void cdsectorSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2)
+{
+ cdSimElipse(ctxcanvas, xc, yc, width, height, angle1, angle2, 1);
+}
+
+void cdchordSIM(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2)
+{
+ cdSimElipse(ctxcanvas, xc, yc, width, height, angle1, angle2, 0);
+}
+
+void cdpolySIM(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ int i, reset = 1;
+
+ switch(mode)
+ {
+ case CD_CLOSED_LINES:
+ poly[n] = poly[0];
+ n++;
+ /* continue */
+ case CD_OPEN_LINES:
+ if (simLineStyleNoReset) /* Bezier simulation use several poly */
+ {
+ reset = 0;
+ simLineStyleNoReset = 1;
+ }
+ for (i = 0; i< n - 1; i++)
+ canvas->cxLine(canvas->ctxcanvas, poly[i].x, poly[i].y, poly[i+1].x, poly[i+1].y);
+ if (reset) simLineStyleNoReset = 0;
+ break;
+ case CD_BEZIER:
+ simLineStyleNoReset = 1;
+ cdSimPolyBezier(canvas, poly, n);
+ simLineStyleNoReset = 0;
+ break;
+ case CD_FILL:
+ {
+ /* must set line attributes here, because fill simulation use cxLine */
+ int oldwidth = cdCanvasLineWidth(canvas, 1);
+ int oldstyle = cdCanvasLineStyle(canvas, CD_CONTINUOUS);
+ int old_use_matrix = canvas->use_matrix;
+
+ if (canvas->use_matrix && !canvas->invert_yaxis)
+ {
+ for(i = 0; i < n; i++)
+ cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y);
+ }
+
+ /* must disable transformation here, because line simulation use cxPixel */
+ canvas->use_matrix = 0;
+
+ simPolyFill(canvas->simulation, poly, n);
+
+ canvas->use_matrix = old_use_matrix;
+ cdCanvasLineStyle(canvas, oldstyle);
+ cdCanvasLineWidth(canvas, oldwidth);
+ }
+ break;
+ }
+}
diff --git a/src/sim/sim_text.c b/src/sim/sim_text.c
new file mode 100644
index 0000000..3ea7aef
--- /dev/null
+++ b/src/sim/sim_text.c
@@ -0,0 +1,371 @@
+/** \file
+ * \brief Text and Font Functions of the Simulation Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <memory.h>
+#include <ctype.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cd_truetype.h"
+#include "sim.h"
+#include FT_GLYPH_H
+
+
+static int font_name_match(const char* map, const char* name)
+{
+ while (*map != '=')
+ {
+ if (tolower(*map) != tolower(*name))
+ return 0;
+
+ map++;
+ name++;
+ }
+
+ return 1;
+}
+
+static void cdSimAddFontMap(cdSimulation* simulation, const char* map)
+{
+ int i;
+
+ if (!strstr(map, "="))
+ return;
+
+ for (i = 0; i < simulation->font_map_n; i++)
+ {
+ if (font_name_match(simulation->font_map[i], map))
+ {
+ /* replace */
+ simulation->font_map[i] = map;
+ return;
+ }
+ }
+
+ /* not found add */
+ simulation->font_map[i] = map;
+ simulation->font_map_n++;
+}
+
+static void set_addfontmap(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (data)
+ {
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ cdSimAddFontMap(canvas->simulation, data);
+ }
+}
+
+static cdAttribute addfontmap_attrib =
+{
+ "ADDFONTMAP",
+ set_addfontmap,
+ NULL
+};
+
+void cdSimInitText(cdSimulation* simulation)
+{
+ if (!simulation->tt_text)
+ simulation->tt_text = cdTT_create();
+
+ cdRegisterAttribute(simulation->canvas, &addfontmap_attrib);
+}
+
+static const char* find_font_filename(cdSimulation* simulation, const char* name)
+{
+ int i;
+ for (i = 0; i < simulation->font_map_n; i++)
+ {
+ if (font_name_match(simulation->font_map[i], name))
+ return strstr(simulation->font_map[i], "=")+1;
+ }
+ return NULL;
+}
+
+int cdfontSIM(cdCtxCanvas* ctxcanvas, const char *type_face, int style, int size)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+
+ /* check for the pre-defined names */
+ if (cdStrEqualNoCase(type_face, "System"))
+ type_face = "cour";
+ else if (cdStrEqualNoCase(type_face, "Courier"))
+ type_face = "cour";
+ else if (cdStrEqualNoCase(type_face, "Times"))
+ type_face = "times";
+ else if (cdStrEqualNoCase(type_face, "Helvetica"))
+ type_face = "arial";
+ else
+ {
+ /* use the font map */
+ const char* filename = find_font_filename(canvas->simulation, type_face);
+ if (filename)
+ return cdTT_load(canvas->simulation->tt_text, filename, cdGetFontSizePoints(canvas, size), canvas->xres, canvas->yres);
+ else
+ {
+ /* try the type_face name without change */
+ if (cdTT_load(canvas->simulation->tt_text, type_face, cdGetFontSizePoints(canvas, size), canvas->xres, canvas->yres))
+ return 1;
+ }
+ }
+
+ {
+ static char * cd_ttf_font_style[4] = {
+ "",
+ "bd",
+ "i",
+ "bi"};
+ char font[10240]; /* can have a path */
+ sprintf(font, "%s%s", type_face, cd_ttf_font_style[style&3]);
+ return cdTT_load(canvas->simulation->tt_text, font, cdGetFontSizePoints(canvas, size), canvas->xres, canvas->yres);
+ }
+}
+
+void cdgetfontdimSIM(cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ cdSimulation* simulation = canvas->simulation;
+
+ if (!simulation->tt_text->face)
+ return;
+
+ if(ascent) *ascent = simulation->tt_text->ascent;
+ if(descent) *descent= simulation->tt_text->descent;
+ if(max_width) *max_width= simulation->tt_text->max_width;
+ if(height) *height= simulation->tt_text->max_height;
+}
+
+void cdgettextsizeSIM(cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ cdSimulation* simulation = canvas->simulation;
+ int w = 0;
+ FT_Face face;
+ FT_GlyphSlot slot;
+ FT_Error error;
+
+ if (!simulation->tt_text->face)
+ return;
+
+ face = simulation->tt_text->face;
+ slot = face->glyph;
+
+ /* set transformation */
+ FT_Set_Transform( face, NULL, NULL );
+
+ while(*s)
+ {
+ /* load glyph image into the slot (erase previous one) */
+ error = FT_Load_Char( face, *(unsigned char*)s, FT_LOAD_DEFAULT );
+ if (error) {s++; continue;} /* ignore errors */
+
+ w += slot->advance.x;
+
+ s++;
+ }
+
+ if (height) *height = simulation->tt_text->max_height;
+ if (width) *width = w >> 6;
+}
+
+static void simDrawTextBitmap(cdSimulation* simulation, FT_Bitmap* bitmap, int x, int y)
+{
+ unsigned char *red, *green, *blue, *alpha, *bitmap_data;
+ int width = bitmap->width;
+ int height = bitmap->rows;
+ int size = width*height;
+ int rgba_data_size = size*4;
+ int olduse_matrix = simulation->canvas->use_matrix;
+
+ /* avoid spaces */
+ if (width == 0 || height == 0)
+ return;
+
+ if (!simulation->tt_text->rgba_data)
+ simulation->tt_text->rgba_data = malloc(rgba_data_size);
+ else if (rgba_data_size > simulation->tt_text->rgba_data_size)
+ {
+ simulation->tt_text->rgba_data = realloc(simulation->tt_text->rgba_data, rgba_data_size);
+ simulation->tt_text->rgba_data_size = rgba_data_size;
+ }
+
+ /* disable image transformation */
+ simulation->canvas->use_matrix = 0;
+
+ bitmap_data = bitmap->buffer + (height-1)*width; /* bitmap is top down. */
+ red = simulation->tt_text->rgba_data;
+ green = red + size;
+ blue = green + size;
+ alpha = blue + size;
+
+ if (!simulation->canvas->cxPutImageRectRGBA && !simulation->canvas->cxGetImageRGB)
+ {
+ int i, j;
+ unsigned char bg_red, bg_green, bg_blue, fg_red, fg_green, fg_blue;
+ long int c;
+ c = simulation->canvas->background;
+ bg_red = cdRed(c);
+ bg_green = cdGreen(c);
+ bg_blue = cdBlue(c);
+ c = simulation->canvas->foreground;
+ fg_red = cdRed(c);
+ fg_green = cdGreen(c);
+ fg_blue = cdBlue(c);
+
+ for (i = 0; i < height; i++)
+ {
+ for (j = 0; j < width; j++)
+ {
+ *red++ = (fg_red*bitmap_data[j] + bg_red*(255-bitmap_data[j]))/255;
+ *green++ = (fg_green*bitmap_data[j] + bg_green*(255-bitmap_data[j]))/255;
+ *blue++ = (fg_blue*bitmap_data[j] + bg_blue*(255-bitmap_data[j]))/255;
+ }
+
+ bitmap_data -= width;
+ }
+
+ red = simulation->tt_text->rgba_data;
+ green = red + size;
+ blue = green + size;
+ simulation->canvas->cxPutImageRectRGB(simulation->canvas->ctxcanvas, width,height,red,green,blue,x,y,width,height,0,width-1,0,height-1);
+ }
+ else
+ {
+ int i;
+ long int fg = simulation->canvas->foreground;
+ memset(red, cdRed(fg), size);
+ memset(green, cdGreen(fg), size);
+ memset(blue, cdBlue(fg), size);
+ for (i = 0; i < height; i++)
+ {
+ memcpy(alpha, bitmap_data, width);
+ alpha += width;
+ bitmap_data -= width;
+ }
+
+ alpha = blue + size;
+ simulation->canvas->cxPutImageRectRGBA(simulation->canvas->ctxcanvas, width,height,red,green,blue,alpha,x,y,width,height,0,width-1,0,height-1);
+ }
+
+ simulation->canvas->use_matrix = olduse_matrix;
+}
+
+void simGetPenPos(cdCanvas* canvas, int x, int y, const char* s, FT_Matrix *matrix, FT_Vector *pen)
+{
+ int ox = x, oy = y;
+ int old_invert_yaxis = canvas->invert_yaxis;
+ int w, h, ascent, height, baseline;
+
+ cdCanvasGetTextSize(canvas, s, &w, &h);
+ cdCanvasGetFontDim(canvas, NULL, &height, &ascent, NULL);
+ baseline = height - ascent;
+
+ /* in this case we are always upwards */
+
+ /* move to bottom left */
+ canvas->invert_yaxis = 0;
+ cdTextTranslatePoint(canvas, x, y, w, h, baseline, &x, &y);
+ canvas->invert_yaxis = old_invert_yaxis;
+
+ /* move to the base line */
+ y += baseline;
+
+ /* set up matrix */
+ matrix->xx = (FT_Fixed)0x10000L;
+ matrix->xy = (FT_Fixed)0;
+ matrix->yx = (FT_Fixed)0;
+ matrix->yy = (FT_Fixed)0x10000L;
+
+ if (canvas->text_orientation)
+ {
+ FT_Matrix text_matrix;
+ double cos_theta = cos(canvas->text_orientation*CD_DEG2RAD);
+ double sin_theta = sin(canvas->text_orientation*CD_DEG2RAD);
+
+ /* manually rotate the initial point */
+ canvas->invert_yaxis = 0;
+ cdRotatePoint(canvas, x, y, ox, oy, &x, &y, sin_theta, cos_theta);
+ canvas->invert_yaxis = old_invert_yaxis;
+
+ text_matrix.xx = (FT_Fixed)( cos_theta*0x10000L);
+ text_matrix.xy = (FT_Fixed)(-sin_theta*0x10000L);
+ text_matrix.yx = (FT_Fixed)( sin_theta*0x10000L);
+ text_matrix.yy = (FT_Fixed)( cos_theta*0x10000L);
+
+ FT_Matrix_Multiply(&text_matrix, matrix);
+ }
+
+ if (canvas->use_matrix && !canvas->invert_yaxis)
+ {
+ FT_Matrix trans_matrix;
+ trans_matrix.xx = (FT_Fixed)(canvas->matrix[0]*0x10000L);
+ trans_matrix.yx = (FT_Fixed)(canvas->matrix[1]*0x10000L);
+ trans_matrix.xy = (FT_Fixed)(canvas->matrix[2]*0x10000L);
+ trans_matrix.yy = (FT_Fixed)(canvas->matrix[3]*0x10000L);
+
+ FT_Matrix_Multiply(&trans_matrix, matrix);
+
+ /* manually transform the initial point */
+ cdMatrixTransformPoint(canvas->matrix, x, y, &x, &y);
+ }
+
+ /* the pen position in 26.6 scale */
+ pen->x = x * 64;
+ pen->y = y * 64;
+
+}
+
+void cdtextSIM(cdCtxCanvas* ctxcanvas, int x, int y, const char * s)
+{
+ cdCanvas* canvas = ((cdCtxCanvasBase*)ctxcanvas)->canvas;
+ cdSimulation* simulation = canvas->simulation;
+ FT_Face face;
+ FT_GlyphSlot slot;
+ FT_Matrix matrix; /* transformation matrix */
+ FT_Vector pen; /* untransformed origin */
+ FT_Error error;
+
+ if (!simulation->tt_text->face)
+ return;
+
+ face = simulation->tt_text->face;
+ slot = face->glyph;
+
+ /* the pen position is in cartesian space coordinates */
+ if (simulation->canvas->invert_yaxis)
+ y = _cdInvertYAxis(canvas, y); /* y is already inverted, invert back to cartesian space */
+
+ /* move the reference point to the baseline-left */
+ simGetPenPos(simulation->canvas, x, y, s, &matrix, &pen);
+
+ while(*s)
+ {
+ /* set transformation */
+ FT_Set_Transform(face, &matrix, &pen);
+
+ /* load glyph image into the slot (erase previous one) */
+ error = FT_Load_Char(face, *(unsigned char*)s, FT_LOAD_RENDER);
+ if (error) {s++; continue;} /* ignore errors */
+
+ x = slot->bitmap_left;
+ y = slot->bitmap_top-slot->bitmap.rows; /* CD image reference point is at bottom-left */
+
+ if (canvas->invert_yaxis)
+ y = _cdInvertYAxis(canvas, y);
+
+ /* now, draw to our target surface (convert position) */
+ simDrawTextBitmap(simulation, &slot->bitmap, x, y);
+
+ /* increment pen position */
+ pen.x += slot->advance.x;
+ pen.y += slot->advance.y;
+
+ s++;
+ }
+}
diff --git a/src/sim/truetype.h b/src/sim/truetype.h
new file mode 100644
index 0000000..5675998
--- /dev/null
+++ b/src/sim/truetype.h
@@ -0,0 +1,46 @@
+/** \file
+ * \brief Text and Font Simulation using FreeType library.
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#ifndef __TRUETYPE_H
+#define __TRUETYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ft2build.h"
+#include FT_FREETYPE_H
+
+/*
+ In CD version 4.4 we start to use FreeType 2.
+ Only TrueType font support is enabled.
+*/
+
+typedef struct _cdTT_Text
+{
+ FT_Library library;
+ FT_Face face;
+
+ unsigned char* rgba_data;
+ int rgba_data_size;
+
+ int max_height;
+ int max_width;
+ int descent;
+ int ascent;
+
+}cdTT_Text;
+
+cdTT_Text* cdTT_create(void);
+void cdTT_free(cdTT_Text * tt_text);
+int cdTT_load(cdTT_Text * tt_text, const char *font,int size, double xres, double yres);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef _CD_TRUETYPE_ */
+