diff options
Diffstat (limited to 'src/sim')
-rw-r--r-- | src/sim/cd_truetype.c | 181 | ||||
-rw-r--r-- | src/sim/cd_truetype.h | 46 | ||||
-rw-r--r-- | src/sim/cdfontex.c | 669 | ||||
-rw-r--r-- | src/sim/sim.c | 328 | ||||
-rw-r--r-- | src/sim/sim.h | 58 | ||||
-rw-r--r-- | src/sim/sim_linepolyfill.c | 1000 | ||||
-rw-r--r-- | src/sim/sim_other.c | 411 | ||||
-rw-r--r-- | src/sim/sim_primitives.c | 524 | ||||
-rw-r--r-- | src/sim/sim_text.c | 371 | ||||
-rw-r--r-- | src/sim/truetype.h | 46 |
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_ */ + |