curvedraw
changeset 15:37ab3a4c02f8
merged
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 20 Dec 2015 09:06:04 +0200 |
parents | b625f0575d66 4da693339d99 |
children | 7f795f7fecd6 |
files | Makefile src/app.cc src/curvefile.cc src/curvefile.h src/main.cc |
diffstat | 12 files changed, 834 insertions(+), 112 deletions(-) [+] |
line diff
1.1 --- a/Makefile Thu Dec 17 16:41:42 2015 +0200 1.2 +++ b/Makefile Sun Dec 20 09:06:04 2015 +0200 1.3 @@ -5,17 +5,17 @@ 1.4 dep = $(obj:.o=.d) 1.5 bin = curvedraw 1.6 1.7 -CXXFLAGS = -pedantic -Wall -g 1.8 +CXXFLAGS = -std=c++11 -pedantic -Wall -g 1.9 LDFLAGS = $(libgl) -lvmath -ldrawtext -lm 1.10 1.11 sys := $(shell uname -s | sed 's/MINGW.*/win32/') 1.12 1.13 ifeq ($(sys), Darwin) 1.14 - libgl = -framework OpenGL -framework GLUT 1.15 + libgl = -framework OpenGL -framework GLUT -lGLEW 1.16 else ifeq ($(sys), win32) 1.17 - libgl = -lopengl32 -lglut32 1.18 + libgl = -lopengl32 -lglut32 -lglew32 1.19 else 1.20 - libgl = -lGL -lglut 1.21 + libgl = -lGL -lglut -lGLEW 1.22 endif 1.23 1.24 $(bin): $(obj)
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/curvedraw.sln Sun Dec 20 09:06:04 2015 +0200 2.3 @@ -0,0 +1,22 @@ 2.4 + 2.5 +Microsoft Visual Studio Solution File, Format Version 12.00 2.6 +# Visual Studio 2013 2.7 +VisualStudioVersion = 12.0.31101.0 2.8 +MinimumVisualStudioVersion = 10.0.40219.1 2.9 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curvedraw", "curvedraw.vcxproj", "{04CA7CB1-80DB-4E89-8FD3-54715CDA43CE}" 2.10 +EndProject 2.11 +Global 2.12 + GlobalSection(SolutionConfigurationPlatforms) = preSolution 2.13 + Debug|Win32 = Debug|Win32 2.14 + Release|Win32 = Release|Win32 2.15 + EndGlobalSection 2.16 + GlobalSection(ProjectConfigurationPlatforms) = postSolution 2.17 + {04CA7CB1-80DB-4E89-8FD3-54715CDA43CE}.Debug|Win32.ActiveCfg = Debug|Win32 2.18 + {04CA7CB1-80DB-4E89-8FD3-54715CDA43CE}.Debug|Win32.Build.0 = Debug|Win32 2.19 + {04CA7CB1-80DB-4E89-8FD3-54715CDA43CE}.Release|Win32.ActiveCfg = Release|Win32 2.20 + {04CA7CB1-80DB-4E89-8FD3-54715CDA43CE}.Release|Win32.Build.0 = Release|Win32 2.21 + EndGlobalSection 2.22 + GlobalSection(SolutionProperties) = preSolution 2.23 + HideSolutionNode = FALSE 2.24 + EndGlobalSection 2.25 +EndGlobal
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/curvedraw.vcxproj Sun Dec 20 09:06:04 2015 +0200 3.3 @@ -0,0 +1,99 @@ 3.4 +<?xml version="1.0" encoding="utf-8"?> 3.5 +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 3.6 + <ItemGroup Label="ProjectConfigurations"> 3.7 + <ProjectConfiguration Include="Debug|Win32"> 3.8 + <Configuration>Debug</Configuration> 3.9 + <Platform>Win32</Platform> 3.10 + </ProjectConfiguration> 3.11 + <ProjectConfiguration Include="Release|Win32"> 3.12 + <Configuration>Release</Configuration> 3.13 + <Platform>Win32</Platform> 3.14 + </ProjectConfiguration> 3.15 + </ItemGroup> 3.16 + <PropertyGroup Label="Globals"> 3.17 + <ProjectGuid>{04CA7CB1-80DB-4E89-8FD3-54715CDA43CE}</ProjectGuid> 3.18 + <Keyword>Win32Proj</Keyword> 3.19 + <RootNamespace>curvedraw</RootNamespace> 3.20 + </PropertyGroup> 3.21 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> 3.22 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> 3.23 + <ConfigurationType>Application</ConfigurationType> 3.24 + <UseDebugLibraries>true</UseDebugLibraries> 3.25 + <PlatformToolset>v120</PlatformToolset> 3.26 + <CharacterSet>MultiByte</CharacterSet> 3.27 + </PropertyGroup> 3.28 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> 3.29 + <ConfigurationType>Application</ConfigurationType> 3.30 + <UseDebugLibraries>false</UseDebugLibraries> 3.31 + <PlatformToolset>v120</PlatformToolset> 3.32 + <WholeProgramOptimization>false</WholeProgramOptimization> 3.33 + <CharacterSet>MultiByte</CharacterSet> 3.34 + </PropertyGroup> 3.35 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> 3.36 + <ImportGroup Label="ExtensionSettings"> 3.37 + </ImportGroup> 3.38 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 3.39 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 3.40 + </ImportGroup> 3.41 + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 3.42 + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 3.43 + </ImportGroup> 3.44 + <PropertyGroup Label="UserMacros" /> 3.45 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 3.46 + <LinkIncremental>true</LinkIncremental> 3.47 + </PropertyGroup> 3.48 + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 3.49 + <LinkIncremental>false</LinkIncremental> 3.50 + </PropertyGroup> 3.51 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 3.52 + <ClCompile> 3.53 + <PrecompiledHeader> 3.54 + </PrecompiledHeader> 3.55 + <WarningLevel>Level3</WarningLevel> 3.56 + <Optimization>Disabled</Optimization> 3.57 + <PreprocessorDefinitions>WIN32;FREEGLUT_LIB_PRAGMAS=0;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> 3.58 + <DisableSpecificWarnings>4244;4996;4305</DisableSpecificWarnings> 3.59 + </ClCompile> 3.60 + <Link> 3.61 + <SubSystem>Console</SubSystem> 3.62 + <GenerateDebugInformation>true</GenerateDebugInformation> 3.63 + <AdditionalDependencies>freeglut.lib;libdrawtext.lib;opengl32.lib;glu32.lib;glew32.lib;libvmath-dbg.lib;%(AdditionalDependencies)</AdditionalDependencies> 3.64 + </Link> 3.65 + </ItemDefinitionGroup> 3.66 + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 3.67 + <ClCompile> 3.68 + <WarningLevel>Level3</WarningLevel> 3.69 + <PrecompiledHeader> 3.70 + </PrecompiledHeader> 3.71 + <Optimization>MaxSpeed</Optimization> 3.72 + <FunctionLevelLinking>true</FunctionLevelLinking> 3.73 + <IntrinsicFunctions>true</IntrinsicFunctions> 3.74 + <PreprocessorDefinitions>WIN32;FREEGLUT_LIB_PRAGMAS=0;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> 3.75 + <DisableSpecificWarnings>4244;4996;4305</DisableSpecificWarnings> 3.76 + </ClCompile> 3.77 + <Link> 3.78 + <SubSystem>Console</SubSystem> 3.79 + <GenerateDebugInformation>true</GenerateDebugInformation> 3.80 + <EnableCOMDATFolding>true</EnableCOMDATFolding> 3.81 + <OptimizeReferences>true</OptimizeReferences> 3.82 + <AdditionalDependencies>freeglut.lib;libdrawtext.lib;opengl32.lib;glu32.lib;glew32.lib;libvmath.lib;%(AdditionalDependencies)</AdditionalDependencies> 3.83 + </Link> 3.84 + </ItemDefinitionGroup> 3.85 + <ItemGroup> 3.86 + <ClCompile Include="src\app.cc" /> 3.87 + <ClCompile Include="src\curve.cc" /> 3.88 + <ClCompile Include="src\curvefile.cc" /> 3.89 + <ClCompile Include="src\main.cc" /> 3.90 + <ClCompile Include="src\widgets.cc" /> 3.91 + </ItemGroup> 3.92 + <ItemGroup> 3.93 + <ClInclude Include="src\app.h" /> 3.94 + <ClInclude Include="src\curve.h" /> 3.95 + <ClInclude Include="src\curvefile.h" /> 3.96 + <ClInclude Include="src\opengl.h" /> 3.97 + <ClInclude Include="src\widgets.h" /> 3.98 + </ItemGroup> 3.99 + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> 3.100 + <ImportGroup Label="ExtensionTargets"> 3.101 + </ImportGroup> 3.102 +</Project> 3.103 \ No newline at end of file
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/curvedraw.vcxproj.filters Sun Dec 20 09:06:04 2015 +0200 4.3 @@ -0,0 +1,43 @@ 4.4 +<?xml version="1.0" encoding="utf-8"?> 4.5 +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 4.6 + <ItemGroup> 4.7 + <Filter Include="src"> 4.8 + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> 4.9 + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;h</Extensions> 4.10 + </Filter> 4.11 + </ItemGroup> 4.12 + <ItemGroup> 4.13 + <ClCompile Include="src\app.cc"> 4.14 + <Filter>src</Filter> 4.15 + </ClCompile> 4.16 + <ClCompile Include="src\curve.cc"> 4.17 + <Filter>src</Filter> 4.18 + </ClCompile> 4.19 + <ClCompile Include="src\main.cc"> 4.20 + <Filter>src</Filter> 4.21 + </ClCompile> 4.22 + <ClCompile Include="src\widgets.cc"> 4.23 + <Filter>src</Filter> 4.24 + </ClCompile> 4.25 + <ClCompile Include="src\curvefile.cc"> 4.26 + <Filter>src</Filter> 4.27 + </ClCompile> 4.28 + </ItemGroup> 4.29 + <ItemGroup> 4.30 + <ClInclude Include="src\app.h"> 4.31 + <Filter>src</Filter> 4.32 + </ClInclude> 4.33 + <ClInclude Include="src\curve.h"> 4.34 + <Filter>src</Filter> 4.35 + </ClInclude> 4.36 + <ClInclude Include="src\opengl.h"> 4.37 + <Filter>src</Filter> 4.38 + </ClInclude> 4.39 + <ClInclude Include="src\widgets.h"> 4.40 + <Filter>src</Filter> 4.41 + </ClInclude> 4.42 + <ClInclude Include="src\curvefile.h"> 4.43 + <Filter>src</Filter> 4.44 + </ClInclude> 4.45 + </ItemGroup> 4.46 +</Project> 4.47 \ No newline at end of file
5.1 --- a/src/app.cc Thu Dec 17 16:41:42 2015 +0200 5.2 +++ b/src/app.cc Sun Dec 20 09:06:04 2015 +0200 5.3 @@ -7,6 +7,7 @@ 5.4 #include "app.h" 5.5 #include "curve.h" 5.6 #include "widgets.h" 5.7 +#include "curvefile.h" 5.8 5.9 enum SnapMode { 5.10 SNAP_NONE, 5.11 @@ -29,21 +30,24 @@ 5.12 static float grid_size = 1.0; 5.13 static SnapMode snap_mode; 5.14 5.15 +static bool show_bounds; 5.16 + 5.17 static std::vector<Curve*> curves; 5.18 static Curve *sel_curve; // selected curve being edited 5.19 static Curve *new_curve; // new curve being entered 5.20 static Curve *hover_curve; // curve the mouse is hovering over (click to select) 5.21 -static int sel_pidx = -1; // selected point of the selected or hovered-over curve 5.22 +static int sel_pidx = -1; // selected point of the selected curve 5.23 +static int hover_pidx = -1; // hovered over point 5.24 5.25 static Label *weight_label; // floating label for the cp weight 5.26 5.27 -#ifdef DRAW_MOUSE_POINTER 5.28 static Vector2 mouse_pointer; 5.29 -#endif 5.30 5.31 5.32 bool app_init(int argc, char **argv) 5.33 { 5.34 + glewInit(); 5.35 + 5.36 glEnable(GL_MULTISAMPLE); 5.37 glEnable(GL_CULL_FACE); 5.38 5.39 @@ -148,6 +152,20 @@ 5.40 int numpt = curve->size(); 5.41 int segm = numpt * 16; 5.42 5.43 + if(show_bounds) { 5.44 + Vector3 bmin, bmax; 5.45 + curve->get_bbox(&bmin, &bmax); 5.46 + 5.47 + glLineWidth(1.0); 5.48 + glColor3f(0, 1, 0); 5.49 + glBegin(GL_LINE_LOOP); 5.50 + glVertex2f(bmin.x, bmin.y); 5.51 + glVertex2f(bmax.x, bmin.y); 5.52 + glVertex2f(bmax.x, bmax.y); 5.53 + glVertex2f(bmin.x, bmax.y); 5.54 + glEnd(); 5.55 + } 5.56 + 5.57 glLineWidth(curve == hover_curve ? 4.0 : 2.0); 5.58 if(curve == sel_curve) { 5.59 glColor3f(0.3, 0.4, 1.0); 5.60 @@ -159,7 +177,7 @@ 5.61 glBegin(GL_LINE_STRIP); 5.62 for(int i=0; i<segm; i++) { 5.63 float t = (float)i / (float)(segm - 1); 5.64 - Vector2 v = curve->interpolate(t); 5.65 + Vector3 v = curve->interpolate(t); 5.66 glVertex2f(v.x, v.y); 5.67 } 5.68 glEnd(); 5.69 @@ -180,10 +198,23 @@ 5.70 glColor3f(0.2, 1.0, 0.2); 5.71 } 5.72 } 5.73 - Vector2 pt = curve->get_point(i); 5.74 + Vector2 pt = curve->get_point2(i); 5.75 glVertex2f(pt.x, pt.y); 5.76 } 5.77 glEnd(); 5.78 + 5.79 + // draw the projected mouse point on the selected curve 5.80 + /* 5.81 + if(curve == sel_curve) { 5.82 + Vector3 pp = curve->proj_point(Vector3(mouse_pointer.x, mouse_pointer.y, 0.0)); 5.83 + 5.84 + glPointSize(5.0); 5.85 + glBegin(GL_POINTS); 5.86 + glColor3f(1, 0.8, 0.2); 5.87 + glVertex2f(pp.x, pp.y); 5.88 + glEnd(); 5.89 + } 5.90 + */ 5.91 glPointSize(1.0); 5.92 } 5.93 5.94 @@ -215,40 +246,64 @@ 5.95 } 5.96 break; 5.97 5.98 - case 'l': 5.99 - case 'L': 5.100 + case '1': 5.101 + case '2': 5.102 + case '3': 5.103 if(sel_curve) { 5.104 - sel_curve->set_type(CURVE_LINEAR); 5.105 + sel_curve->set_type((CurveType)((int)CURVE_LINEAR + key - '1')); 5.106 post_redisplay(); 5.107 } 5.108 if(new_curve) { 5.109 - new_curve->set_type(CURVE_LINEAR); 5.110 + new_curve->set_type((CurveType)((int)CURVE_LINEAR + key - '1')); 5.111 post_redisplay(); 5.112 } 5.113 break; 5.114 5.115 case 'b': 5.116 case 'B': 5.117 + show_bounds = !show_bounds; 5.118 + post_redisplay(); 5.119 + break; 5.120 + 5.121 + case 'n': 5.122 + case 'N': 5.123 if(sel_curve) { 5.124 - sel_curve->set_type(CURVE_BSPLINE); 5.125 - post_redisplay(); 5.126 - } 5.127 - if(new_curve) { 5.128 - new_curve->set_type(CURVE_BSPLINE); 5.129 + sel_curve->normalize(); 5.130 post_redisplay(); 5.131 } 5.132 break; 5.133 5.134 - case 'h': 5.135 - case 'H': 5.136 - if(sel_curve) { 5.137 - sel_curve->set_type(CURVE_HERMITE); 5.138 - post_redisplay(); 5.139 + case 'e': 5.140 + case 'E': 5.141 + // TODO: GUI for filename at least 5.142 + if(!save_curves("test.curves", &curves[0], (int)curves.size())) { 5.143 + fprintf(stderr, "failed to export curves\n"); 5.144 } 5.145 - if(new_curve) { 5.146 - new_curve->set_type(CURVE_HERMITE); 5.147 - post_redisplay(); 5.148 + printf("exported %d curves\n", (int)curves.size()); 5.149 + break; 5.150 + 5.151 + case 'l': 5.152 + case 'L': 5.153 + { 5.154 + std::list<Curve*> clist = load_curves("test.curves"); 5.155 + if(clist.empty()) { 5.156 + fprintf(stderr, "failed to import curves\n"); 5.157 + } 5.158 + 5.159 + for(size_t i=0; i<curves.size(); i++) { 5.160 + delete curves[i]; 5.161 + } 5.162 + curves.clear(); 5.163 + 5.164 + int num = 0; 5.165 + std::list<Curve*>::iterator it = clist.begin(); 5.166 + while(it != clist.end()) { 5.167 + curves.push_back(*it++); 5.168 + ++num; 5.169 + } 5.170 + printf("imported %d curves\n", num); 5.171 } 5.172 + post_redisplay(); 5.173 break; 5.174 } 5.175 } 5.176 @@ -335,7 +390,7 @@ 5.177 int pidx = curves[i]->nearest_point(pos); 5.178 if(pidx == -1) continue; 5.179 5.180 - Vector2 cp = curves[i]->get_point(pidx); 5.181 + Vector2 cp = curves[i]->get_point2(pidx); 5.182 if((cp - pos).length_sq() < thres * thres) { 5.183 *curveret = curves[i]; 5.184 *pidxret = pidx; 5.185 @@ -347,6 +402,28 @@ 5.186 return false; 5.187 } 5.188 5.189 +static bool hit_test(const Vector2 &pos, Curve **curveret, int *pidxret) 5.190 +{ 5.191 + float thres = 0.02 / view_scale; 5.192 + 5.193 + if(point_hit_test(pos, curveret, pidxret)) { 5.194 + return true; 5.195 + } 5.196 + 5.197 + Vector3 pos3 = Vector3(pos.x, pos.y, 0.0f); 5.198 + for(size_t i=0; i<curves.size(); i++) { 5.199 + float x; 5.200 + if((x = curves[i]->distance_sq(pos3)) < thres * thres) { 5.201 + *curveret = curves[i]; 5.202 + *pidxret = -1; 5.203 + return true; 5.204 + } 5.205 + } 5.206 + *curveret = 0; 5.207 + *pidxret = -1; 5.208 + return false; 5.209 +} 5.210 + 5.211 static Vector2 snap(const Vector2 &p) 5.212 { 5.213 switch(snap_mode) { 5.214 @@ -407,10 +484,8 @@ 5.215 if(!dx && !dy) return; 5.216 5.217 Vector2 uv = pixel_to_uv(x, y); 5.218 -#ifdef DRAW_MOUSE_POINTER 5.219 mouse_pointer = uv; 5.220 - post_redisplay(); 5.221 -#endif 5.222 + //post_redisplay(); 5.223 5.224 /* when entering a new curve, have the last (extra) point following 5.225 * the mouse until it's entered by a click (see on_click). 5.226 @@ -422,7 +497,10 @@ 5.227 5.228 if(!new_curve && !bnstate) { 5.229 // not dragging, highlight curve under mouse 5.230 - point_hit_test(uv, &hover_curve, &sel_pidx); 5.231 + hit_test(uv, &hover_curve, &hover_pidx); 5.232 + if(hover_curve == sel_curve) { 5.233 + sel_pidx = hover_pidx; 5.234 + } 5.235 post_redisplay(); 5.236 5.237 } else { 5.238 @@ -482,6 +560,7 @@ 5.239 if(hover_curve) { 5.240 // if we're hovering: click selects 5.241 sel_curve = hover_curve; 5.242 + sel_pidx = hover_pidx; 5.243 hover_curve = 0; 5.244 } else if(sel_curve) { 5.245 // if we have a selected curve: click adds point (enter new_curve mode) 5.246 @@ -520,9 +599,11 @@ 5.247 // in selected curve mode: delete control point or unselect 5.248 Curve *hit_curve; 5.249 int hit_pidx; 5.250 - if(point_hit_test(uv, &hit_curve, &hit_pidx) && hit_curve == sel_curve) { 5.251 - hit_curve->remove_point(hit_pidx); 5.252 - sel_pidx = -1; 5.253 + if(hit_test(uv, &hit_curve, &hit_pidx) && hit_curve == sel_curve) { 5.254 + if(hit_pidx != -1) { 5.255 + hit_curve->remove_point(hit_pidx); 5.256 + sel_pidx = -1; 5.257 + } 5.258 } else { 5.259 sel_curve = 0; 5.260 sel_pidx = -1;
6.1 --- a/src/curve.cc Thu Dec 17 16:41:42 2015 +0200 6.2 +++ b/src/curve.cc Sun Dec 20 09:06:04 2015 +0200 6.3 @@ -1,9 +1,39 @@ 6.4 #include <float.h> 6.5 +#include <assert.h> 6.6 +#include <algorithm> 6.7 #include "curve.h" 6.8 6.9 Curve::Curve(CurveType type) 6.10 { 6.11 this->type = type; 6.12 + bbvalid = true; 6.13 +} 6.14 + 6.15 +Curve::Curve(const Vector4 *cp, int numcp, CurveType type) 6.16 + : Curve(type) 6.17 +{ 6.18 + this->cp.resize(numcp); 6.19 + for(int i=0; i<numcp; i++) { 6.20 + this->cp[i] = cp[i]; 6.21 + } 6.22 +} 6.23 + 6.24 +Curve::Curve(const Vector3 *cp, int numcp, CurveType type) 6.25 + : Curve(type) 6.26 +{ 6.27 + this->cp.resize(numcp); 6.28 + for(int i=0; i<numcp; i++) { 6.29 + this->cp[i] = Vector4(cp[i].x, cp[i].y, cp[i].z, 1.0f); 6.30 + } 6.31 +} 6.32 + 6.33 +Curve::Curve(const Vector2 *cp, int numcp, CurveType type) 6.34 + : Curve(type) 6.35 +{ 6.36 + this->cp.resize(numcp); 6.37 + for(int i=0; i<numcp; i++) { 6.38 + this->cp[i] = Vector4(cp[i].x, cp[i].y, 0.0f, 1.0f); 6.39 + } 6.40 } 6.41 6.42 void Curve::set_type(CurveType type) 6.43 @@ -16,9 +46,20 @@ 6.44 return type; 6.45 } 6.46 6.47 +void Curve::add_point(const Vector4 &p) 6.48 +{ 6.49 + cp.push_back(p); 6.50 + inval_bounds(); 6.51 +} 6.52 + 6.53 +void Curve::add_point(const Vector3 &p, float weight) 6.54 +{ 6.55 + add_point(Vector4(p.x, p.y, p.z, weight)); 6.56 +} 6.57 + 6.58 void Curve::add_point(const Vector2 &p, float weight) 6.59 { 6.60 - cp.push_back(Vector3(p.x, p.y, weight)); 6.61 + add_point(Vector4(p.x, p.y, 0.0f, weight)); 6.62 } 6.63 6.64 bool Curve::remove_point(int idx) 6.65 @@ -27,23 +68,14 @@ 6.66 return false; 6.67 } 6.68 cp.erase(cp.begin() + idx); 6.69 + inval_bounds(); 6.70 return true; 6.71 } 6.72 6.73 -int Curve::nearest_point(const Vector2 &p) 6.74 +void Curve::clear() 6.75 { 6.76 - int res = -1; 6.77 - float bestsq = FLT_MAX; 6.78 - 6.79 - for(size_t i=0; i<cp.size(); i++) { 6.80 - float d = (get_point(i) - p).length_sq(); 6.81 - if(d < bestsq) { 6.82 - bestsq = d; 6.83 - res = i; 6.84 - } 6.85 - } 6.86 - 6.87 - return res; 6.88 + cp.clear(); 6.89 + inval_bounds(); 6.90 } 6.91 6.92 bool Curve::empty() const 6.93 @@ -56,29 +88,45 @@ 6.94 return (int)cp.size(); 6.95 } 6.96 6.97 -Vector3 &Curve::operator [](int idx) 6.98 +Vector4 &Curve::operator [](int idx) 6.99 +{ 6.100 + inval_bounds(); 6.101 + return cp[idx]; 6.102 +} 6.103 + 6.104 +const Vector4 &Curve::operator [](int idx) const 6.105 { 6.106 return cp[idx]; 6.107 } 6.108 6.109 -const Vector3 &Curve::operator [](int idx) const 6.110 +const Vector4 &Curve::get_point(int idx) const 6.111 { 6.112 return cp[idx]; 6.113 } 6.114 6.115 -const Vector3 &Curve::get_homo_point(int idx) const 6.116 +Vector3 Curve::get_point3(int idx) const 6.117 { 6.118 - return cp[idx]; 6.119 + return Vector3(cp[idx].x, cp[idx].y, cp[idx].z); 6.120 } 6.121 6.122 -Vector2 Curve::get_point(int idx) const 6.123 +Vector2 Curve::get_point2(int idx) const 6.124 { 6.125 return Vector2(cp[idx].x, cp[idx].y); 6.126 } 6.127 6.128 float Curve::get_weight(int idx) const 6.129 { 6.130 - return cp[idx].z; 6.131 + return cp[idx].w; 6.132 +} 6.133 + 6.134 +bool Curve::set_point(int idx, const Vector3 &p, float weight) 6.135 +{ 6.136 + if(idx < 0 || idx >= (int)cp.size()) { 6.137 + return false; 6.138 + } 6.139 + cp[idx] = Vector4(p.x, p.y, p.z, weight); 6.140 + inval_bounds(); 6.141 + return true; 6.142 } 6.143 6.144 bool Curve::set_point(int idx, const Vector2 &p, float weight) 6.145 @@ -86,7 +134,8 @@ 6.146 if(idx < 0 || idx >= (int)cp.size()) { 6.147 return false; 6.148 } 6.149 - cp[idx] = Vector3(p.x, p.y, weight); 6.150 + cp[idx] = Vector4(p.x, p.y, 0.0, weight); 6.151 + inval_bounds(); 6.152 return true; 6.153 } 6.154 6.155 @@ -95,7 +144,17 @@ 6.156 if(idx < 0 || idx >= (int)cp.size()) { 6.157 return false; 6.158 } 6.159 - cp[idx].z = weight; 6.160 + cp[idx].w = weight; 6.161 + return true; 6.162 +} 6.163 + 6.164 +bool Curve::move_point(int idx, const Vector3 &p) 6.165 +{ 6.166 + if(idx < 0 || idx >= (int)cp.size()) { 6.167 + return false; 6.168 + } 6.169 + cp[idx] = Vector4(p.x, p.y, p.z, cp[idx].w); 6.170 + inval_bounds(); 6.171 return true; 6.172 } 6.173 6.174 @@ -104,22 +163,211 @@ 6.175 if(idx < 0 || idx >= (int)cp.size()) { 6.176 return false; 6.177 } 6.178 - cp[idx] = Vector3(p.x, p.y, cp[idx].z); 6.179 + cp[idx] = Vector4(p.x, p.y, 0.0f, cp[idx].w); 6.180 + inval_bounds(); 6.181 return true; 6.182 } 6.183 6.184 -Vector2 Curve::interpolate(float t, CurveType type) const 6.185 + 6.186 +int Curve::nearest_point(const Vector3 &p) const 6.187 { 6.188 - if(cp.empty()) { 6.189 - return Vector2(0, 0); 6.190 + int res = -1; 6.191 + float bestsq = FLT_MAX; 6.192 + 6.193 + for(size_t i=0; i<cp.size(); i++) { 6.194 + float d = (get_point3(i) - p).length_sq(); 6.195 + if(d < bestsq) { 6.196 + bestsq = d; 6.197 + res = i; 6.198 + } 6.199 + } 6.200 + return res; 6.201 +} 6.202 + 6.203 +int Curve::nearest_point(const Vector2 &p) const 6.204 +{ 6.205 + int res = -1; 6.206 + float bestsq = FLT_MAX; 6.207 + 6.208 + for(size_t i=0; i<cp.size(); i++) { 6.209 + float d = (get_point2(i) - p).length_sq(); 6.210 + if(d < bestsq) { 6.211 + bestsq = d; 6.212 + res = i; 6.213 + } 6.214 + } 6.215 + return res; 6.216 +} 6.217 + 6.218 + 6.219 +void Curve::inval_bounds() const 6.220 +{ 6.221 + bbvalid = false; 6.222 +} 6.223 + 6.224 +void Curve::calc_bounds() const 6.225 +{ 6.226 + calc_bbox(&bbmin, &bbmax); 6.227 + bbvalid = true; 6.228 +} 6.229 + 6.230 +void Curve::get_bbox(Vector3 *bbmin, Vector3 *bbmax) const 6.231 +{ 6.232 + if(!bbvalid) { 6.233 + calc_bounds(); 6.234 + } 6.235 + *bbmin = this->bbmin; 6.236 + *bbmax = this->bbmax; 6.237 +} 6.238 + 6.239 +void Curve::calc_bbox(Vector3 *bbmin, Vector3 *bbmax) const 6.240 +{ 6.241 + if(empty()) { 6.242 + *bbmin = *bbmax = Vector3(0, 0, 0); 6.243 + return; 6.244 + } 6.245 + 6.246 + Vector3 bmin = cp[0]; 6.247 + Vector3 bmax = bmin; 6.248 + for(size_t i=1; i<cp.size(); i++) { 6.249 + const Vector4 &v = cp[i]; 6.250 + for(int j=0; j<3; j++) { 6.251 + if(v[j] < bmin[j]) bmin[j] = v[j]; 6.252 + if(v[j] > bmax[j]) bmax[j] = v[j]; 6.253 + } 6.254 + } 6.255 + *bbmin = bmin; 6.256 + *bbmax = bmax; 6.257 +} 6.258 + 6.259 +void Curve::normalize() 6.260 +{ 6.261 + if(!bbvalid) { 6.262 + calc_bounds(); 6.263 + } 6.264 + 6.265 + Vector3 bsize = bbmax - bbmin; 6.266 + Vector3 boffs = (bbmin + bbmax) * 0.5; 6.267 + 6.268 + Vector3 bscale; 6.269 + bscale.x = bsize.x == 0.0f ? 1.0f : 1.0f / bsize.x; 6.270 + bscale.y = bsize.y == 0.0f ? 1.0f : 1.0f / bsize.y; 6.271 + bscale.z = bsize.z == 0.0f ? 1.0f : 1.0f / bsize.z; 6.272 + 6.273 + for(size_t i=0; i<cp.size(); i++) { 6.274 + cp[i].x = (cp[i].x - boffs.x) * bscale.x; 6.275 + cp[i].y = (cp[i].y - boffs.y) * bscale.y; 6.276 + cp[i].z = (cp[i].z - boffs.z) * bscale.z; 6.277 + } 6.278 + inval_bounds(); 6.279 +} 6.280 + 6.281 +Vector3 Curve::proj_point(const Vector3 &p, float refine_thres) const 6.282 +{ 6.283 + // first step through the curve a few times and find the nearest of them 6.284 + int num_cp = size(); 6.285 + int num_steps = num_cp * 5; // arbitrary number; sounds ok 6.286 + float dt = 1.0f / (float)(num_steps - 1); 6.287 + 6.288 + float best_distsq = FLT_MAX; 6.289 + float best_t = 0.0f; 6.290 + Vector3 best_pp; 6.291 + 6.292 + float t = 0.0f; 6.293 + for(int i=0; i<num_steps; i++) { 6.294 + Vector3 pp = interpolate(t); 6.295 + float distsq = (pp - p).length_sq(); 6.296 + if(distsq < best_distsq) { 6.297 + best_distsq = distsq; 6.298 + best_pp = pp; 6.299 + best_t = t; 6.300 + } 6.301 + t += dt; 6.302 + } 6.303 + 6.304 + // refine by gradient descent 6.305 + float dist = best_distsq; 6.306 + t = best_t; 6.307 + dt *= 0.05; 6.308 + for(;;) { 6.309 + float tn = t + dt; 6.310 + float tp = t - dt; 6.311 + 6.312 + float dn = (interpolate(tn) - p).length_sq(); 6.313 + float dp = (interpolate(tp) - p).length_sq(); 6.314 + 6.315 + if(fabs(dn - dp) < refine_thres * refine_thres) { 6.316 + break; 6.317 + } 6.318 + 6.319 + if(dn < dist) { 6.320 + t = tn; 6.321 + dist = dn; 6.322 + } else if(dp < dist) { 6.323 + t = tp; 6.324 + dist = dp; 6.325 + } else { 6.326 + break; // found the minimum 6.327 + } 6.328 + } 6.329 + 6.330 + return interpolate(t); 6.331 +} 6.332 + 6.333 +float Curve::distance(const Vector3 &p) const 6.334 +{ 6.335 + return (proj_point(p) - p).length(); 6.336 +} 6.337 + 6.338 +float Curve::distance_sq(const Vector3 &p) const 6.339 +{ 6.340 + return fabs((proj_point(p) - p).length_sq()); 6.341 +} 6.342 + 6.343 + 6.344 +Vector3 Curve::interpolate_segment(int a, int b, float t) const 6.345 +{ 6.346 + int num_cp = size(); 6.347 + 6.348 + if(t < 0.0) t = 0.0; 6.349 + if(t > 1.0) t = 1.0; 6.350 + 6.351 + Vector4 res; 6.352 + if(type == CURVE_LINEAR || num_cp == 2) { 6.353 + res = lerp(cp[a], cp[b], t); 6.354 + } else { 6.355 + int prev = a <= 0 ? a : a - 1; 6.356 + int next = b >= num_cp - 1 ? b : b + 1; 6.357 + 6.358 + if(type == CURVE_HERMITE) { 6.359 + res = catmull_rom_spline(cp[prev], cp[a], cp[b], cp[next], t); 6.360 + } else { 6.361 + res = bspline(cp[prev], cp[a], cp[b], cp[next], t); 6.362 + if(res.w != 0.0f) { 6.363 + res.x /= res.w; 6.364 + res.y /= res.w; 6.365 + res.z /= res.w; 6.366 + } 6.367 + } 6.368 + } 6.369 + 6.370 + return Vector3(res.x, res.y, res.z); 6.371 +} 6.372 + 6.373 +Vector3 Curve::interpolate(float t) const 6.374 +{ 6.375 + if(empty()) { 6.376 + return Vector3(0, 0, 0); 6.377 } 6.378 6.379 int num_cp = (int)cp.size(); 6.380 if(num_cp == 1) { 6.381 - return Vector2(cp[0].x, cp[0].y); 6.382 + return Vector3(cp[0].x, cp[0].y, cp[0].z); 6.383 } 6.384 6.385 - Vector3 res; 6.386 + if(t < 0.0) t = 0.0; 6.387 + if(t > 1.0) t = 1.0; 6.388 + 6.389 int idx0 = std::min((int)floor(t * (num_cp - 1)), num_cp - 2); 6.390 int idx1 = idx0 + 1; 6.391 6.392 @@ -128,35 +376,17 @@ 6.393 float t1 = (float)idx1 * dt; 6.394 6.395 t = (t - t0) / (t1 - t0); 6.396 - if(t < 0.0) t = 0.0; 6.397 - if(t > 1.0) t = 1.0; 6.398 6.399 - if(type == CURVE_LINEAR || num_cp <= 2) { 6.400 - res = lerp(cp[idx0], cp[idx1], t); 6.401 - } else { 6.402 - int idx_prev = idx0 <= 0 ? idx0 : idx0 - 1; 6.403 - int idx_next = idx1 >= num_cp - 1 ? idx1 : idx1 + 1; 6.404 + return interpolate_segment(idx0, idx1, t); 6.405 +} 6.406 6.407 - if(type == CURVE_HERMITE) { 6.408 - res = catmull_rom_spline(cp[idx_prev], cp[idx0], cp[idx1], cp[idx_next], t); 6.409 - } else { 6.410 - res = bspline(cp[idx_prev], cp[idx0], cp[idx1], cp[idx_next], t); 6.411 - if(res.z != 0.0f) { 6.412 - res.x /= res.z; 6.413 - res.y /= res.z; 6.414 - } 6.415 - } 6.416 - } 6.417 - 6.418 +Vector2 Curve::interpolate2(float t) const 6.419 +{ 6.420 + Vector3 res = interpolate(t); 6.421 return Vector2(res.x, res.y); 6.422 } 6.423 6.424 -Vector2 Curve::interpolate(float t) const 6.425 -{ 6.426 - return interpolate(t, type); 6.427 -} 6.428 - 6.429 -Vector2 Curve::operator ()(float t) const 6.430 +Vector3 Curve::operator ()(float t) const 6.431 { 6.432 return interpolate(t); 6.433 }
7.1 --- a/src/curve.h Thu Dec 17 16:41:42 2015 +0200 7.2 +++ b/src/curve.h Sun Dec 20 09:06:04 2015 +0200 7.3 @@ -12,37 +12,74 @@ 7.4 7.5 class Curve { 7.6 private: 7.7 - std::vector<Vector3> cp; 7.8 + std::vector<Vector4> cp; 7.9 CurveType type; 7.10 7.11 + // bounding box 7.12 + mutable Vector3 bbmin, bbmax; 7.13 + mutable bool bbvalid; 7.14 + 7.15 + void calc_bounds() const; 7.16 + void inval_bounds() const; 7.17 + 7.18 public: 7.19 Curve(CurveType type = CURVE_HERMITE); 7.20 + Curve(const Vector4 *cp, int numcp, CurveType type = CURVE_HERMITE); // homogenous 7.21 + Curve(const Vector3 *cp, int numcp, CurveType type = CURVE_HERMITE); // 3D points, w=1 7.22 + Curve(const Vector2 *cp, int numcp, CurveType type = CURVE_HERMITE); // 2D points, z=0, w=1 7.23 7.24 void set_type(CurveType type); 7.25 CurveType get_type() const; 7.26 7.27 + void add_point(const Vector4 &p); 7.28 + void add_point(const Vector3 &p, float weight = 1.0f); 7.29 void add_point(const Vector2 &p, float weight = 1.0f); 7.30 bool remove_point(int idx); 7.31 7.32 - int nearest_point(const Vector2 &p); 7.33 + void clear(); // remove all control points 7.34 + bool empty() const; // true if 0 control points 7.35 + int size() const; // returns number of control points 7.36 + // access operators for control points 7.37 + Vector4 &operator [](int idx); 7.38 + const Vector4 &operator [](int idx) const; 7.39 + const Vector4 &get_point(int idx) const; 7.40 7.41 - bool empty() const; 7.42 - int size() const; 7.43 - Vector3 &operator [](int idx); 7.44 - const Vector3 &operator [](int idx) const; 7.45 - 7.46 - const Vector3 &get_homo_point(int idx) const; // homogeneous point 7.47 - Vector2 get_point(int idx) const; 7.48 + Vector3 get_point3(int idx) const; 7.49 + Vector2 get_point2(int idx) const; 7.50 float get_weight(int idx) const; 7.51 7.52 + bool set_point(int idx, const Vector3 &p, float weight = 1.0f); 7.53 bool set_point(int idx, const Vector2 &p, float weight = 1.0f); 7.54 bool set_weight(int idx, float weight); 7.55 // move point without changing its weight 7.56 + bool move_point(int idx, const Vector3 &p); 7.57 bool move_point(int idx, const Vector2 &p); 7.58 + 7.59 + int nearest_point(const Vector3 &p) const; 7.60 + // nearest control point on the 2D plane z=0 7.61 + int nearest_point(const Vector2 &p) const; 7.62 7.63 - Vector2 interpolate(float t, CurveType type) const; 7.64 - Vector2 interpolate(float t) const; 7.65 - Vector2 operator ()(float t) const; 7.66 + /* get_bbox returns the axis-aligned bounding box of the curve's 7.67 + * control points. 7.68 + * NOTE: hermite curves can go outside of the bounding box of their control points 7.69 + * NOTE: lazy calculation of bounds is performed, use calc_bbox in multithreaded programs 7.70 + */ 7.71 + void get_bbox(Vector3 *bbmin, Vector3 *bbmax) const; 7.72 + void calc_bbox(Vector3 *bbmin, Vector3 *bbmax) const; 7.73 + // normalize the curve's bounds to coincide with the unit cube 7.74 + void normalize(); 7.75 + 7.76 + // project a point to the curve (nearest point on the curve) 7.77 + Vector3 proj_point(const Vector3 &p, float refine_thres = 0.01) const; 7.78 + // equivalent to (proj_point(p) - p).length() 7.79 + float distance(const Vector3 &p) const; 7.80 + // equivalent to fabs((proj_point(p) - p).length_sq()) 7.81 + float distance_sq(const Vector3 &p) const; 7.82 + 7.83 + Vector3 interpolate_segment(int a, int b, float t) const; 7.84 + Vector3 interpolate(float t) const; 7.85 + Vector2 interpolate2(float t) const; 7.86 + Vector3 operator ()(float t) const; 7.87 }; 7.88 7.89 #endif // CURVE_H_
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/curvefile.cc Sun Dec 20 09:06:04 2015 +0200 8.3 @@ -0,0 +1,204 @@ 8.4 +#include <stdlib.h> 8.5 +#include <ctype.h> 8.6 +#include <string> 8.7 +#include "curvefile.h" 8.8 + 8.9 +static bool save_curve(FILE *fp, const Curve *curve); 8.10 + 8.11 +bool save_curves(const char *fname, const Curve * const *curves, int count) 8.12 +{ 8.13 + FILE *fp = fopen(fname, "wb"); 8.14 + if(!fp) return false; 8.15 + 8.16 + bool res = save_curves(fp, curves, count); 8.17 + fclose(fp); 8.18 + return res; 8.19 +} 8.20 + 8.21 +bool save_curves(FILE *fp, const Curve * const *curves, int count) 8.22 +{ 8.23 + fprintf(fp, "GCURVES\n"); 8.24 + 8.25 + for(int i=0; i<count; i++) { 8.26 + if(!save_curve(fp, curves[i])) { 8.27 + return false; 8.28 + } 8.29 + } 8.30 + return true; 8.31 +} 8.32 + 8.33 +static const char *curve_type_str(CurveType type) 8.34 +{ 8.35 + switch(type) { 8.36 + case CURVE_LINEAR: 8.37 + return "polyline"; 8.38 + case CURVE_HERMITE: 8.39 + return "hermite"; 8.40 + case CURVE_BSPLINE: 8.41 + return "bspline"; 8.42 + } 8.43 + abort(); 8.44 +} 8.45 + 8.46 +static bool save_curve(FILE *fp, const Curve *curve) 8.47 +{ 8.48 + fprintf(fp, "curve {\n"); 8.49 + fprintf(fp, " type %s\n", curve_type_str(curve->get_type())); 8.50 + fprintf(fp, " cpcount %d\n", curve->size()); 8.51 + for(int i=0; i<curve->size(); i++) { 8.52 + Vector4 cp = curve->get_point(i); 8.53 + fprintf(fp, " cp %g %g %g %g\n", cp.x, cp.y, cp.z, cp.w); 8.54 + } 8.55 + fprintf(fp, "}\n"); 8.56 + return true; 8.57 +} 8.58 + 8.59 +std::list<Curve*> load_curves(const char *fname) 8.60 +{ 8.61 + std::list<Curve*> res; 8.62 + FILE *fp = fopen(fname, "r"); 8.63 + if(!fp) return res; 8.64 + 8.65 + res = load_curves(fp); 8.66 + fclose(fp); 8.67 + return res; 8.68 +} 8.69 + 8.70 +static std::string next_token(FILE *fp) 8.71 +{ 8.72 + std::string s; 8.73 + int c; 8.74 + while((c = fgetc(fp)) != -1) { 8.75 + if(!isspace(c)) { 8.76 + ungetc(c, fp); 8.77 + break; 8.78 + } 8.79 + } 8.80 + 8.81 + if(feof(fp)) return s; 8.82 + while((c = fgetc(fp)) != -1) { 8.83 + if(isspace(c)) { 8.84 + ungetc(c, fp); 8.85 + break; 8.86 + } 8.87 + s.push_back(c); 8.88 + } 8.89 + return s; 8.90 +} 8.91 + 8.92 +static bool expect_str(FILE *fp, const char *s) 8.93 +{ 8.94 + std::string tok = next_token(fp); 8.95 + if(tok != std::string(s)) { 8.96 + if(tok.empty() && feof(fp)) { 8.97 + fprintf(stderr, "expected: %s\n", s); 8.98 + } 8.99 + return false; 8.100 + } 8.101 + return true; 8.102 +} 8.103 + 8.104 +static bool expect_float(FILE *fp, float *ret) 8.105 +{ 8.106 + std::string tok = next_token(fp); 8.107 + const char *cs = tok.c_str(); 8.108 + char *endp; 8.109 + *ret = strtod(cs, &endp); 8.110 + if(endp != cs + tok.length()) { 8.111 + if(!(tok.empty() && feof(fp))) { 8.112 + fprintf(stderr, "number expected\n"); 8.113 + } 8.114 + return false; 8.115 + } 8.116 + return true; 8.117 +} 8.118 + 8.119 +static bool expect_int(FILE *fp, int *ret) 8.120 +{ 8.121 + std::string tok = next_token(fp); 8.122 + const char *cs = tok.c_str(); 8.123 + char *endp; 8.124 + *ret = strtol(cs, &endp, 0); 8.125 + if(endp != cs + tok.length()) { 8.126 + if(!(tok.empty() && feof(fp))) { 8.127 + fprintf(stderr, "integer expected\n"); 8.128 + } 8.129 + return false; 8.130 + } 8.131 + return true; 8.132 +} 8.133 + 8.134 +static Curve *curve_block(FILE *fp) 8.135 +{ 8.136 + if(!expect_str(fp, "curve") || !expect_str(fp, "{")) { 8.137 + return 0; 8.138 + } 8.139 + 8.140 + Curve *curve = new Curve; 8.141 + int cpcount = -1; 8.142 + std::string tok; 8.143 + while(!(tok = next_token(fp)).empty() && tok != "}") { 8.144 + if(tok == "cpcount") { 8.145 + if(cpcount != -1 || !expect_int(fp, &cpcount) || cpcount <= 0) { 8.146 + goto err; 8.147 + } 8.148 + } else if(tok == "type") { 8.149 + tok = next_token(fp); 8.150 + if(tok == "polyline") { 8.151 + curve->set_type(CURVE_LINEAR); 8.152 + } else if(tok == "hermite") { 8.153 + curve->set_type(CURVE_HERMITE); 8.154 + } else if(tok == "bspline") { 8.155 + curve->set_type(CURVE_BSPLINE); 8.156 + } else { 8.157 + goto err; 8.158 + } 8.159 + } else { 8.160 + if(tok != "cp") { 8.161 + goto err; 8.162 + } 8.163 + Vector4 cp; 8.164 + for(int i=0; i<4; i++) { 8.165 + if(!expect_float(fp, &cp[i])) { 8.166 + goto err; 8.167 + } 8.168 + } 8.169 + curve->add_point(Vector3(cp.x, cp.y, cp.z), cp.w); 8.170 + } 8.171 + } 8.172 + 8.173 + if(curve->size() != cpcount) { 8.174 + fprintf(stderr, "warning: curve cpcount was %d, but read %d control points\n", cpcount, curve->size()); 8.175 + } 8.176 + 8.177 + return curve; 8.178 +err: 8.179 + fprintf(stderr, "failed to parse curve block\n"); 8.180 + delete curve; 8.181 + return 0; 8.182 +} 8.183 + 8.184 +std::list<Curve*> load_curves(FILE *fp) 8.185 +{ 8.186 + std::list<Curve*> curves; 8.187 + if(!expect_str(fp, "GCURVES")) { 8.188 + fprintf(stderr, "load_curves: failed to load, invalid file format\n"); 8.189 + return curves; 8.190 + } 8.191 + 8.192 + Curve *curve; 8.193 + while((curve = curve_block(fp))) { 8.194 + curves.push_back(curve); 8.195 + } 8.196 + 8.197 + if(!feof(fp)) { 8.198 + std::list<Curve*>::iterator it = curves.begin(); 8.199 + while(it != curves.end()) { 8.200 + delete *it++; 8.201 + } 8.202 + return curves; 8.203 + } 8.204 + 8.205 + return curves; 8.206 +} 8.207 +
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/curvefile.h Sun Dec 20 09:06:04 2015 +0200 9.3 @@ -0,0 +1,14 @@ 9.4 +#ifndef CURVEFILE_H_ 9.5 +#define CURVEFILE_H_ 9.6 + 9.7 +#include <stdio.h> 9.8 +#include <list> 9.9 +#include "curve.h" 9.10 + 9.11 +bool save_curves(const char *fname, const Curve * const *curves, int count); 9.12 +bool save_curves(FILE *fp, const Curve * const *curves, int count); 9.13 + 9.14 +std::list<Curve*> load_curves(const char *fname); 9.15 +std::list<Curve*> load_curves(FILE *fp); 9.16 + 9.17 +#endif // CURVEFILE_H_ 9.18 \ No newline at end of file
10.1 --- a/src/main.cc Thu Dec 17 16:41:42 2015 +0200 10.2 +++ b/src/main.cc Sun Dec 20 09:06:04 2015 +0200 10.3 @@ -47,11 +47,6 @@ 10.4 glutSwapBuffers(); 10.5 } 10.6 10.7 -static void reshape(int x, int y) 10.8 -{ 10.9 - app_reshape(x, y); 10.10 -} 10.11 - 10.12 static void keydown(unsigned char key, int x, int y) 10.13 { 10.14 app_keyboard(key, true);
11.1 --- a/src/opengl.h Thu Dec 17 16:41:42 2015 +0200 11.2 +++ b/src/opengl.h Sun Dec 20 09:06:04 2015 +0200 11.3 @@ -1,14 +1,6 @@ 11.4 #ifndef OPENGL_H_ 11.5 #define OPENGL_H_ 11.6 11.7 -#ifdef WIN32 11.8 -#include <windows.h> 11.9 -#endif 11.10 - 11.11 -#ifdef __APPLE__ 11.12 -#include <OpenGL/gl.h> 11.13 -#else 11.14 -#include <GL/gl.h> 11.15 -#endif 11.16 +#include <GL/glew.h> 11.17 11.18 #endif // OPENGL_H_
12.1 --- a/src/widgets.cc Thu Dec 17 16:41:42 2015 +0200 12.2 +++ b/src/widgets.cc Sun Dec 20 09:06:04 2015 +0200 12.3 @@ -2,6 +2,11 @@ 12.4 #include <stdlib.h> 12.5 #include <string.h> 12.6 #include <stdarg.h> 12.7 +#ifdef _MSC_VER 12.8 +#include <malloc.h> 12.9 +#else 12.10 +#include <alloca.h> 12.11 +#endif 12.12 #include <drawtext.h> 12.13 #include "opengl.h" 12.14 #include "widgets.h"