]> git.sesse.net Git - casparcg/commitdiff
* added geometry to frames for custom rendering
authorniklaspandersson <niklas.p.andersson@svt.se>
Thu, 1 Aug 2013 08:03:20 +0000 (10:03 +0200)
committerniklaspandersson <niklas.p.andersson@svt.se>
Thu, 1 Aug 2013 08:03:20 +0000 (10:03 +0200)
* new text-producer using freetype
* new photoshop-parser for the scene-producer

29 files changed:
accelerator/ogl/image/image_kernel.cpp
accelerator/ogl/image/image_kernel.h
accelerator/ogl/image/image_mixer.cpp
accelerator/ogl/image/image_shader.cpp
core/core.vcxproj
core/core.vcxproj.filters
core/frame/draw_frame.h
core/frame/frame.cpp
core/frame/frame.h
core/frame/geometry.cpp [new file with mode: 0644]
core/frame/geometry.h [new file with mode: 0644]
core/producer/scene/scene_producer.cpp
core/producer/scene/scene_producer.h
core/producer/text/text_producer.cpp [new file with mode: 0644]
core/producer/text/text_producer.h [new file with mode: 0644]
core/producer/text/utils/color.h [new file with mode: 0644]
core/producer/text/utils/string_metrics.h [new file with mode: 0644]
core/producer/text/utils/texture_atlas.cpp [new file with mode: 0644]
core/producer/text/utils/texture_atlas.h [new file with mode: 0644]
core/producer/text/utils/texture_font.cpp [new file with mode: 0644]
core/producer/text/utils/texture_font.h [new file with mode: 0644]
modules/psd/layer.cpp
modules/psd/psd.cpp
modules/psd/psd.vcxproj
protocol/amcp/AMCPCommandsImpl.cpp
shell/server.cpp
shell/shell.vcxproj
test/psd-test/psd-test.cpp
test/psd-test/psd-test.vcxproj

index 482d486b14c0b65433b7caf8ba9fd3e7cc728fbd..a266cd28fc62f725524acfffcb3f43d7ace66ff9 100644 (file)
@@ -217,16 +217,60 @@ struct image_kernel::impl
                
                glMatrixMode(GL_MODELVIEW);
                glPushMatrix();
-                       glTranslated(f_p[0], f_p[1], 0);
-                       glScaled(f_s[0], f_s[1], 1);
+                       glTranslated(f_p[0], f_p[1], 0.0);
+                       glScaled(f_s[0], f_s[1], 1.0);
+
+                       switch(params.geometry.type())
+                       {
+                       case core::frame_geometry::quad:
+                               {
+                                       const std::vector<float>& data = params.geometry.data();
+                                       float v_left = data[0], v_top = data[1], t_left = data[2], t_top = data[3];
+                                       float v_right = data[4], v_bottom = data[5], t_right = data[6], t_bottom = data[7];
+
+                                       glBegin(GL_QUADS);
+                                               glMultiTexCoord2d(GL_TEXTURE0, t_left, t_top);          glVertex2d(v_left, v_top);
+                                               glMultiTexCoord2d(GL_TEXTURE0, t_right, t_top);         glVertex2d(v_right, v_top);
+                                               glMultiTexCoord2d(GL_TEXTURE0, t_right, t_bottom);      glVertex2d(v_right, v_bottom);
+                                               glMultiTexCoord2d(GL_TEXTURE0, t_left, t_bottom);       glVertex2d(v_left, v_bottom);
+                                       glEnd();
+                               }
+                               break;
+
+                       case core::frame_geometry::quad_list:
+                               {
+                                       glClientActiveTexture(GL_TEXTURE0);
+                                       
+                                       glDisableClientState(GL_EDGE_FLAG_ARRAY);
+                                       glDisableClientState(GL_COLOR_ARRAY);
+                                       glDisableClientState(GL_INDEX_ARRAY);
+                                       glDisableClientState(GL_NORMAL_ARRAY);
+
+                                       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+                                       glEnableClientState(GL_VERTEX_ARRAY);
+                                       
+                                       glTexCoordPointer(2, GL_FLOAT, 4*sizeof(float), &(params.geometry.data().data()[2]));
+                                       glVertexPointer(2, GL_FLOAT, 4*sizeof(float), params.geometry.data().data());
+                                       
+                                       glDrawArrays(GL_QUADS, 0, (GLsizei)params.geometry.data().size()/4);    //each vertex is four floats.
+                                       
+                                       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+                                       glDisableClientState(GL_VERTEX_ARRAY);
+                               }
+                               break;
+
+                       default:
+                               break;
+                       }
+
 
                        // Draw
-                       glBegin(GL_QUADS);
+                       /*glBegin(GL_QUADS);
                                glMultiTexCoord2d(GL_TEXTURE0, 0.0, 0.0); glVertex2d(0, 0);
                                glMultiTexCoord2d(GL_TEXTURE0, 1.0, 0.0); glVertex2d(1, 0);
                                glMultiTexCoord2d(GL_TEXTURE0, 1.0, 1.0); glVertex2d(1, 1);
                                glMultiTexCoord2d(GL_TEXTURE0, 0.0, 1.0); glVertex2d(0, 1);
-                       glEnd();
+                       glEnd();*/
                glPopMatrix();
                
                // Cleanup
index fe4dc96e41df19e1d0c1934e37ec5070069c2850..bf5eedd0908d2a05d65bc6423915db7651aae0d9 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <core/frame/pixel_format.h>
 #include <core/frame/frame_transform.h>
+#include <core/frame/geometry.h>
 
 namespace caspar { namespace accelerator { namespace ogl {
        
@@ -46,6 +47,7 @@ struct draw_params sealed
        core::pixel_format_desc                                         pix_desc;
        std::vector<spl::shared_ptr<class texture>>     textures;
        core::image_transform                                           transform;
+       core::frame_geometry                                            geometry;
        core::blend_mode                                                        blend_mode;
        keyer                                                                           keyer;
        std::shared_ptr<class texture>                          background;
index 56dcaa20dc5e3bc09993b2ea9251e120b11b379b..a6120ee674c8269d2ffeb42451cb2eb9e5590d99 100644 (file)
@@ -36,6 +36,7 @@
 #include <core/frame/frame_transform.h>
 #include <core/frame/pixel_format.h>
 #include <core/video_format.h>
+#include <core/frame/geometry.h>
 
 #include <asmlib.h>
 
@@ -59,6 +60,7 @@ struct item
        core::pixel_format_desc                                                         pix_desc;
        std::vector<future_texture>                                                     textures;
        core::image_transform                                                           transform;
+       core::frame_geometry                                                            geometry;
 
        item()
                : pix_desc(core::pixel_format::invalid)
@@ -226,6 +228,7 @@ private:
                draw_params draw_params;
                draw_params.pix_desc    = std::move(item.pix_desc);
                draw_params.transform   = std::move(item.transform);
+               draw_params.geometry    = item.geometry;
 
                BOOST_FOREACH(auto& future_texture, item.textures)
                        draw_params.textures.push_back(future_texture.get());
@@ -278,6 +281,7 @@ private:
                draw_params.transform                   = core::image_transform();
                draw_params.blend_mode                  = blend_mode;
                draw_params.background                  = target_texture;
+               draw_params.geometry                    = core::frame_geometry::default();
 
                kernel_.draw(std::move(draw_params));
        }
@@ -322,6 +326,7 @@ public:
                item item;
                item.pix_desc   = frame.pixel_format_desc();
                item.transform  = transform_stack_.back();
+               item.geometry   = frame.geometry();
                
                // NOTE: Once we have copied the arrays they are no longer valid for reading!!! Check for alternative solution e.g. transfer with AMD_pinned_memory.
                for(int n = 0; n < static_cast<int>(item.pix_desc.planes.size()); ++n)
index f2230ede5c3085fc9c67e6c89e3e6fa1bbed1a15..0899e181108cf9f61c636852ea21710b69d075c6 100644 (file)
@@ -125,8 +125,8 @@ std::string get_vertex()
 //     "       gl_TexCoord[1] = gl_MultiTexCoord1;                                                                                             \n"
        "       vec4 pos = ftransform();                                                                                                                \n"
        "       gl_TexCoord[1] = vec4(pos.xy, 0.0, 0.0);                                                                                \n"
-       "       pos.x = pos.x*2 - 1;                                                                                                                    \n"
-       "       pos.y = pos.y*2 - 1;                                                                                                                    \n"
+       "       pos.x = pos.x*2.0 - 1.0;                                                                                                                \n"
+       "       pos.y = pos.y*2.0 - 1.0;                                                                                                                \n"
        "       gl_Position    = pos;                                                                                                                   \n"
        "}                                                                                                                                                                      \n";
 }
index 49c53d206efea398dec453614e845fc4d8931c66..5803438eb233d9a82538cd1cc1ee21c26bec0828 100644 (file)
     <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)tmp\$(Configuration)\</IntDir>\r
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)tmp\$(Configuration)\</IntDir>\r
-    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\;..\dependencies64\boost\;..\dependencies64\tbb\include\;..\dependencies64\sfml\include\;..\dependencies64\glew\include\;..\dependencies64\asmlib\;$(IncludePath)</IncludePath>\r
-    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\;..\dependencies64\boost\;..\dependencies64\tbb\include\;..\dependencies64\sfml\include\;..\dependencies64\glew\include\;..\dependencies64\asmlib\;$(IncludePath)</IncludePath>\r
+    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\;..\dependencies64\boost\;..\dependencies64\tbb\include\;..\dependencies64\sfml\include\;..\dependencies64\glew\include\;..\dependencies64\asmlib\;..\dependencies64\freetype\include;..\dependencies64\freeimage\include\;$(IncludePath)</IncludePath>\r
+    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\;..\dependencies64\boost\;..\dependencies64\tbb\include\;..\dependencies64\sfml\include\;..\dependencies64\glew\include\;..\dependencies64\asmlib\;..\dependencies64\freetype\include;..\dependencies64\freeimage\include\;$(IncludePath)</IncludePath>\r
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)bin\$(Configuration)\</OutDir>\r
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)bin\$(Configuration)\</OutDir>\r
     <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectName)</TargetName>\r
     <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectName)</TargetName>\r
+    <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LibraryPath)</LibraryPath>\r
+    <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LibraryPath)</LibraryPath>\r
   </PropertyGroup>\r
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
     <PreBuildEvent>\r
@@ -81,6 +83,9 @@
       </Command>\r
     </PostBuildEvent>\r
     <Lib />\r
+    <Lib>\r
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
+    </Lib>\r
   </ItemDefinitionGroup>\r
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
     <PreBuildEvent>\r
     </PostBuildEvent>\r
     <Lib>\r
       <LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>\r
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
     </Lib>\r
   </ItemDefinitionGroup>\r
   <ItemGroup>\r
     <ClInclude Include="frame\frame_factory.h" />\r
     <ClInclude Include="frame\frame_transform.h" />\r
     <ClInclude Include="frame\frame_visitor.h" />\r
+    <ClInclude Include="frame\geometry.h" />\r
     <ClInclude Include="frame\pixel_format.h" />\r
     <ClInclude Include="interaction\interaction_aggregator.h" />\r
     <ClInclude Include="interaction\interaction_event.h" />\r
     <ClInclude Include="producer\draw\freehand_producer.h" />\r
     <ClInclude Include="producer\scene\const_producer.h" />\r
     <ClInclude Include="producer\scene\scene_producer.h" />\r
+    <ClInclude Include="producer\text\text_producer.h" />\r
+    <ClInclude Include="producer\text\utils\color.h" />\r
+    <ClInclude Include="producer\text\utils\string_metrics.h" />\r
+    <ClInclude Include="producer\text\utils\texture_atlas.h" />\r
+    <ClInclude Include="producer\text\utils\texture_font.h" />\r
     <ClInclude Include="video_channel.h" />\r
     <ClInclude Include="consumer\output.h" />\r
     <ClInclude Include="consumer\frame_consumer.h" />\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
+    <ClCompile Include="frame\geometry.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
     <ClCompile Include="mixer\image\blend_modes.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
+    <ClCompile Include="producer\text\text_producer.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
+    <ClCompile Include="producer\text\utils\texture_atlas.cpp">\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>\r
+    </ClCompile>\r
+    <ClCompile Include="producer\text\utils\texture_font.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\..\StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\..\StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
     <ClCompile Include="video_channel.cpp" />\r
     <ClCompile Include="consumer\frame_consumer.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
index a086d666828b1eab9cd1462467e7a64aa69c6f3b..ff5b36bfc29b6a310b14a7b12e7af72a1fe759b3 100644 (file)
     <Filter Include="source\producer\draw">\r
       <UniqueIdentifier>{0138e754-c089-46e6-9540-cf5cf4818381}</UniqueIdentifier>\r
     </Filter>\r
+    <Filter Include="source\producer\text">\r
+      <UniqueIdentifier>{3fcfe649-213d-4ecd-a2d4-95ec24a6b152}</UniqueIdentifier>\r
+    </Filter>\r
     <Filter Include="source\producer\scene">\r
       <UniqueIdentifier>{a949a4cd-ede1-41fb-89bb-2fc1c4dc386a}</UniqueIdentifier>\r
     </Filter>\r
+    <Filter Include="source\producer\text\utils">\r
+      <UniqueIdentifier>{fc435676-34ca-46fe-bbcf-2fbad8e3cd21}</UniqueIdentifier>\r
+    </Filter>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="producer\transition\transition_producer.h">\r
     <ClInclude Include="producer\scene\const_producer.h">\r
       <Filter>source\producer\scene</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="frame\geometry.h">\r
+      <Filter>source\frame</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="producer\text\text_producer.h">\r
+      <Filter>source\producer\text</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="producer\text\utils\texture_font.h">\r
+      <Filter>source\producer\text\utils</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="producer\text\utils\texture_atlas.h">\r
+      <Filter>source\producer\text\utils</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="producer\text\utils\color.h">\r
+      <Filter>source\producer\text\utils</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="producer\text\utils\string_metrics.h">\r
+      <Filter>source\producer\text\utils</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="producer\transition\transition_producer.cpp">\r
     <ClCompile Include="producer\scene\const_producer.cpp">\r
       <Filter>source\producer\scene</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="frame\geometry.cpp">\r
+      <Filter>source\frame</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="producer\text\text_producer.cpp">\r
+      <Filter>source\producer\text</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="producer\text\utils\texture_font.cpp">\r
+      <Filter>source\producer\text\utils</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="producer\text\utils\texture_atlas.cpp">\r
+      <Filter>source\producer\text\utils</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 6f188a858abcd5606ecf895a4f51d11b3bd5b75f..672097c13af83c758e87bed7c95d6151e3bb7668 100644 (file)
@@ -72,7 +72,8 @@ public:
        // Properties
 
        const core::frame_transform&    transform() const;
-       core::frame_transform&                  transform();                    
+       core::frame_transform&                  transform();
+
 private:
        struct impl;
        spl::unique_ptr<impl> impl_;
index 9587953320660fd964372629689d9de01a5ad039..9a17f7cc3c7940f9fbe9664b9c28e4b2f337dae5 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <core/frame/frame_visitor.h>
 #include <core/frame/pixel_format.h>
+#include <core/frame/geometry.h>
 
 #include <boost/lexical_cast.hpp>
 #include <boost/thread/future.hpp>
@@ -40,12 +41,14 @@ struct mutable_frame::impl : boost::noncopyable
        core::audio_buffer                                                      audio_data_;
        const core::pixel_format_desc                           desc_;
        const void*                                                                     tag_;
+       core::frame_geometry                                            geometry_;
        
        impl(std::vector<array<std::uint8_t>> buffers, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) 
                : buffers_(std::move(buffers))
                , audio_data_(std::move(audio_buffer))
                , desc_(desc)
                , tag_(tag)
+               , geometry_(frame_geometry::default())
        {
                BOOST_FOREACH(auto& buffer, buffers_)
                        if(!buffer.data())
@@ -72,6 +75,8 @@ std::size_t mutable_frame::width() const{return impl_->desc_.planes.at(0).width;
 std::size_t mutable_frame::height() const{return impl_->desc_.planes.at(0).height;}                                            
 const void* mutable_frame::stream_tag()const{return impl_->tag_;}                              
 const void* mutable_frame::data_tag()const{return impl_.get();}        
+const frame_geometry& mutable_frame::geometry() const { return impl_->geometry_; }
+void mutable_frame::set_geometry(const frame_geometry& g) { impl_->geometry_ = g; }
 
 const const_frame& const_frame::empty()
 {
@@ -87,11 +92,13 @@ struct const_frame::impl : boost::noncopyable
        core::audio_buffer                                                      audio_data_;
        const core::pixel_format_desc                           desc_;
        const void*                                                                     tag_;
+       core::frame_geometry                                            geometry_;
 
        impl(const void* tag)
                : desc_(core::pixel_format::invalid)
                , tag_(tag)     
                , id_(0)
+               , geometry_(frame_geometry::default())
        {
        }
        
@@ -100,6 +107,7 @@ struct const_frame::impl : boost::noncopyable
                , desc_(desc)
                , tag_(tag)
                , id_(reinterpret_cast<int>(this))
+               , geometry_(frame_geometry::default())
        {
                if(desc.format != core::pixel_format::bgra)
                        CASPAR_THROW_EXCEPTION(not_implemented());
@@ -112,6 +120,7 @@ struct const_frame::impl : boost::noncopyable
                , desc_(other.pixel_format_desc())
                , tag_(other.stream_tag())
                , id_(reinterpret_cast<int>(this))
+               , geometry_(other.geometry())
        {
                for(std::size_t n = 0; n < desc_.planes.size(); ++n)
                {
@@ -171,5 +180,7 @@ std::size_t const_frame::height()const{return impl_->height();}
 std::size_t const_frame::size()const{return impl_->size();}                                            
 const void* const_frame::stream_tag()const{return impl_->tag_;}                                
 const void* const_frame::data_tag()const{return impl_.get();}  
+const frame_geometry& const_frame::geometry() const { return impl_->geometry_; }
+void const_frame::set_geometry(const frame_geometry& g) { impl_->geometry_ = g; }
 
 }}
\ No newline at end of file
index 454b6e5c36222ec0a1739145048e2b2c9609bf57..882ffad8f91db9dc14be2cd5d24b9c7b0e92e03e 100644 (file)
@@ -22,6 +22,7 @@ FORWARD1(boost, template<typename> class shared_future);
 namespace caspar { namespace core {
        
 typedef std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>> audio_buffer;
+class frame_geometry;
 
 class mutable_frame sealed
 {
@@ -61,6 +62,9 @@ public:
                                                                
        const void* stream_tag() const;
        const void* data_tag() const;
+
+       const core::frame_geometry& geometry() const;
+       void set_geometry(const frame_geometry& g);
                        
 private:
        struct impl;
@@ -106,6 +110,9 @@ public:
        const void* stream_tag() const;
        const void* data_tag() const;
 
+       const core::frame_geometry& geometry() const;
+       void set_geometry(const frame_geometry& g);
+
        bool operator==(const const_frame& other);
        bool operator!=(const const_frame& other);
        bool operator<(const const_frame& other);
diff --git a/core/frame/geometry.cpp b/core/frame/geometry.cpp
new file mode 100644 (file)
index 0000000..f99c909
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+
+#include "..\StdAfx.h"
+
+#include "geometry.h"
+
+namespace caspar { namespace core {
+
+struct frame_geometry::impl
+{
+       impl() : type_(frame_geometry::none) {}
+       impl(frame_geometry::geometry_type t, std::vector<float> d) : type_(t), data_(std::move(d)) {}
+       
+       frame_geometry::geometry_type type_;
+       std::vector<float> data_;
+};
+
+frame_geometry::frame_geometry() : impl_(new impl()) {}
+frame_geometry::frame_geometry(const frame_geometry& rhs) : impl_(rhs.impl_) {}
+frame_geometry::frame_geometry(geometry_type t, std::vector<float> d) : impl_(new impl(t, std::move(d))) {}
+
+const frame_geometry& frame_geometry::operator=(const frame_geometry& rhs) { impl_ = rhs.impl_; return *this; }
+
+frame_geometry::geometry_type frame_geometry::type() { return impl_->type_; }
+const std::vector<float>& frame_geometry::data() { return impl_->data_; }
+       
+const frame_geometry& frame_geometry::default()
+{
+       const float d[] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f};
+       static frame_geometry g(frame_geometry::quad, std::move(std::vector<float>(d, d+8)));
+
+       return g;
+}
+
+}}
\ No newline at end of file
diff --git a/core/frame/geometry.h b/core/frame/geometry.h
new file mode 100644 (file)
index 0000000..eaecce0
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#pragma once
+
+#include <common/memory.h>
+#include <vector>
+
+namespace caspar { namespace core {
+
+class frame_geometry
+{
+public:
+       enum geometry_type
+       {
+               none,
+               quad,
+               quad_list
+       };
+
+       frame_geometry();
+       frame_geometry(const frame_geometry&);
+       frame_geometry(geometry_type, std::vector<float>);
+       const frame_geometry& operator=(const frame_geometry&);
+
+       geometry_type type();
+       const std::vector<float>& data();
+       
+       static const frame_geometry& default();
+
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
+}}
\ No newline at end of file
index 65f4dc567dd8ad42eb9be1f18dfeb19d10f56150..f31d3304a60f98a81b4e9a9d2b2c09084ae3cb55 100644 (file)
 
 #include "../../stdafx.h"
 
+#include <common/future.h>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string.hpp>
+
 #include "scene_producer.h"
 
 #include "../../frame/draw_frame.h"
@@ -32,6 +36,10 @@ layer::layer(const spl::shared_ptr<frame_producer>& producer)
        : producer(producer)
 {
 }
+layer::layer(const std::wstring& name, const spl::shared_ptr<frame_producer>& producer)
+       : name(name), producer(producer)
+{
+}
 
 adjustments::adjustments()
        : opacity(1.0)
@@ -51,6 +59,15 @@ struct scene_producer::impl
        {
        }
 
+       layer& create_layer(
+                       const spl::shared_ptr<frame_producer>& producer, int x, int y, const std::wstring& name)
+       {
+               layer& layer = create_layer(producer, x, y);
+               layer.name.set(name);
+
+               return layer;
+       }
+
        layer& create_layer(
                        const spl::shared_ptr<frame_producer>& producer, int x, int y)
        {
@@ -148,6 +165,30 @@ struct scene_producer::impl
                return boost::optional<interaction_target>();
        }
 
+       boost::unique_future<std::wstring> call(const std::wstring& params) 
+       {
+               std::wstring result;
+               
+               std::vector<std::wstring> words;
+               boost::split(words, params, [](wchar_t c) { return c == L' '; }, boost::token_compress_on);
+
+               if(words.size() >= 2)
+               {
+                       struct layer_comparer
+                       {
+                               const std::wstring& str;
+                               explicit layer_comparer(const std::wstring& s) : str(s) {}
+                               bool operator()(const layer& val) { return boost::iequals(val.name.get(), str); }
+                       };
+
+                       auto it = std::find_if(layers_.begin(), layers_.end(), layer_comparer(words[0]));
+                       if(it != layers_.end())
+                               (*it).producer.get()->call(words[1]);
+               }
+
+               return async(launch::deferred, [=]{return result;});
+       }
+
        std::wstring print() const
        {
                return L"scene[]";
@@ -189,6 +230,12 @@ layer& scene_producer::create_layer(
        return impl_->create_layer(producer, x, y);
 }
 
+layer& scene_producer::create_layer(
+               const spl::shared_ptr<frame_producer>& producer, int x, int y, const std::wstring& name)
+{
+       return impl_->create_layer(producer, x, y, name);
+}
+
 layer& scene_producer::create_layer(
                const spl::shared_ptr<frame_producer>& producer)
 {
@@ -232,6 +279,11 @@ boost::property_tree::wptree scene_producer::info() const
        return impl_->info();
 }
 
+boost::unique_future<std::wstring> scene_producer::call(const std::wstring& params) 
+{
+       return impl_->call(params);
+}
+
 void scene_producer::subscribe(const monitor::observable::observer_ptr& o)
 {
        impl_->subscribe(o);
@@ -247,7 +299,7 @@ spl::shared_ptr<frame_producer> create_dummy_scene_producer(const spl::shared_pt
        if (params.size() < 1 || params.at(0) != L"[SCENE]")
                return core::frame_producer::empty();
 
-       auto scene = spl::make_shared<scene_producer>(1280, 720);
+       auto scene = spl::make_shared<scene_producer>(format_desc.width, format_desc.height);
 
        binding<double> text_width(10);
        binding<double> padding(1);
index e444f031d66b1e4aaa5cf95d778056a1cb40d0b5..cfb7ccc78b9661feae8ce86cd99a9c86bad91c8c 100644 (file)
@@ -49,7 +49,8 @@ struct layer
        binding<bool> hidden;
        binding<bool> is_key;
 
-       layer(const spl::shared_ptr<frame_producer>& producer);
+       explicit layer(const spl::shared_ptr<frame_producer>& producer);
+       layer(const std::wstring& name, const spl::shared_ptr<frame_producer>& producer);
 };
 
 class scene_producer : public frame_producer_base
@@ -64,11 +65,14 @@ public:
        bool collides(double x, double y) const override;
        std::wstring print() const override;
        std::wstring name() const override;
+       boost::unique_future<std::wstring>      call(const std::wstring& params) override;
        boost::property_tree::wptree info() const override;
        void subscribe(const monitor::observable::observer_ptr& o) override;
        void unsubscribe(const monitor::observable::observer_ptr& o) override;
        layer& create_layer(
                        const spl::shared_ptr<frame_producer>& producer, int x, int y);
+       layer& create_layer(
+                       const spl::shared_ptr<frame_producer>& producer, int x, int y, const std::wstring& name);
        layer& create_layer(const spl::shared_ptr<frame_producer>& producer);
        binding<int64_t> frame();
 private:
diff --git a/core/producer/text/text_producer.cpp b/core/producer/text/text_producer.cpp
new file mode 100644 (file)
index 0000000..7f0e949
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#include "../../stdafx.h"
+
+#include "text_producer.h"
+
+#include <core/producer/frame_producer.h>
+#include <core/frame/geometry.h>
+#include <core/frame/frame.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/pixel_format.h>
+#include <core/monitor/monitor.h>
+
+#include <core/consumer/frame_consumer.h>
+#include <modules/image/consumer/image_consumer.h>
+
+#include <common/except.h>
+#include <common/array.h>
+#include <common/env.h>
+#include <common/future.h>
+#include <memory>
+
+#include <asmlib.h>
+#include <FreeImage.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/filesystem.hpp>
+
+#include "utils\texture_atlas.h"
+#include "utils\texture_font.h"
+
+namespace caspar { namespace core {
+
+std::wstring find_font_file(const std::wstring& font_name)
+{
+       std::wstring filename = L"c:\\windows\\fonts\\" + font_name;    //TODO: move font-folder setting to settings
+       if(boost::filesystem::exists(filename + L".otf"))
+               return filename + L".otf";
+       if(boost::filesystem::exists(filename + L".ttf"))
+               return filename + L".ttf";
+       if(boost::filesystem::exists(filename + L".fon"))
+               return filename + L".fon";
+
+       //TODO: Searching by filename is not enough to identify some fonts. we need to extract the font-names somehow
+       return L"";
+}
+
+struct text_producer::impl
+{
+       spl::shared_ptr<core::frame_factory>    frame_factory_;
+       constraints constraints_;
+       int x_, y_, parent_width_, parent_height_;
+       std::wstring text_;
+       draw_frame frame_;
+       text::texture_atlas atlas_;
+       text::texture_font font_;
+
+public:
+       explicit impl(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, const text::text_info& text_info, long parent_width, long parent_height) 
+               : frame_factory_(frame_factory)
+               , constraints_(parent_width, parent_height)
+               , x_(x), y_(y), parent_width_(parent_width), parent_height_(parent_height)
+               , atlas_(512,512,4)
+               , font_(atlas_, find_font_file(text_info.font), text_info.size)
+       {
+               font_.load_glyphs(text::Basic_Latin, text_info.color);
+
+               //generate frame
+               generate_frame(str);
+
+               CASPAR_LOG(info) << print() << L" Initialized";
+       }
+
+       void generate_frame(const std::wstring& str)
+       {
+               core::pixel_format_desc pfd(core::pixel_format::bgra);
+               pfd.planes.push_back(core::pixel_format_desc::plane((int)atlas_.width(), (int)atlas_.height(), (int)atlas_.depth()));
+
+               std::vector<float> vertex_stream(std::move(font_.create_vertex_stream(str, x_, y_, parent_width_, parent_height_)));
+               auto frame = frame_factory_->create_frame(vertex_stream.data(), pfd);
+               memcpy(frame.image_data().data(), atlas_.data(), frame.image_data().size());
+               frame.set_geometry(frame_geometry(frame_geometry::quad_list, std::move(vertex_stream)));
+
+               frame_ = core::draw_frame(std::move(frame));
+       }
+
+       text::string_metrics measure_string(const std::wstring& str)
+       {
+               return font_.measure_string(str);
+       }
+
+       // frame_producer
+                       
+       draw_frame receive_impl()
+       {
+               return frame_;
+       }
+
+       boost::unique_future<std::wstring> call(const std::wstring& param)
+       {
+               std::wstring result;
+               generate_frame(param);
+
+               return async(launch::deferred, [=]{return result;});
+       }
+
+       constraints& pixel_constraints()
+       {
+               return constraints_;
+       }
+       
+       std::wstring print() const
+       {
+               return L"text[" + text_ + L"]";
+       }
+
+       std::wstring name() const
+       {
+               return L"text";
+       }
+       
+       boost::property_tree::wptree info() const
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"text");
+               info.add(L"text", text_);
+               return info;
+       }
+};
+
+text_producer::text_producer(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, const text::text_info& text_info, long parent_width, long parent_height)
+       : impl_(new impl(frame_factory, x, y, str, text_info, parent_width, parent_height))
+{}
+
+draw_frame text_producer::receive_impl() { return impl_->receive_impl(); }
+boost::unique_future<std::wstring> text_producer::call(const std::wstring& param) { return impl_->call(param); }
+text::string_metrics text_producer::measure_string(const std::wstring& str) { return impl_->measure_string(str); }
+
+constraints& text_producer::pixel_constraints() { return impl_->pixel_constraints(); }
+std::wstring text_producer::print() const { return impl_->print(); }
+std::wstring text_producer::name() const { return impl_->name(); }
+boost::property_tree::wptree text_producer::info() const { return impl_->info(); }
+void text_producer::subscribe(const monitor::observable::observer_ptr& o) {}
+void text_producer::unsubscribe(const monitor::observable::observer_ptr& o) {}
+
+
+
+spl::shared_ptr<frame_producer> do_create_text_producer(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, const text::text_info& text_info, long parent_width, long parent_height)
+{
+       return spl::make_shared<text_producer>(frame_factory, x, y, str, text_info, parent_width, parent_height);
+}
+
+spl::shared_ptr<frame_producer> create_text_producer(const spl::shared_ptr<frame_factory>& frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params)
+{
+       if(params.size() < 2 || params.at(0) != L"[TEXT]")
+               return core::frame_producer::empty();
+
+       int x = 0, y = 0;
+       if(params.size() >= 4)
+       {
+               x = boost::lexical_cast<int>(params.at(2));
+               y = boost::lexical_cast<int>(params.at(3));
+       }
+
+       text::text_info text_info;
+       text_info.font = L"verdana";
+       text_info.size = 30;
+       text_info.color = text::color<float>(1.0f, 0, 0, 1.0f);
+       return do_create_text_producer(frame_factory, x, y, params.at(1), text_info, format_desc.width, format_desc.height);
+}
+
+}}
\ No newline at end of file
diff --git a/core/producer/text/text_producer.h b/core/producer/text/text_producer.h
new file mode 100644 (file)
index 0000000..a5242fb
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Niklas P Andersson, niklas.p.andersson@svt.se
+*/
+
+#pragma once
+
+#include "../frame_producer.h"
+
+#include <common/memory.h>
+
+#include <boost/property_tree/ptree_fwd.hpp>
+#include <string>
+#include <vector>
+
+#include "utils/color.h"
+#include "utils/string_metrics.h"
+
+namespace caspar { namespace core {
+       namespace text 
+       {
+               struct text_info
+               {
+                       std::wstring font;
+                       float size;
+                       color<float> color;
+               };
+       }
+
+class text_producer : public frame_producer_base
+{
+public:
+       text_producer(const spl::shared_ptr<frame_factory>& frame_factory, int x, int y, const std::wstring& str, const text::text_info& text_info, long parent_width, long parent_height);
+       draw_frame receive_impl() override;
+       boost::unique_future<std::wstring> call(const std::wstring& param) override;
+
+       text::string_metrics measure_string(const std::wstring& str);
+
+       constraints& pixel_constraints() override;
+       std::wstring print() const override;
+       std::wstring name() const override;
+       boost::property_tree::wptree info() const override;
+       void subscribe(const monitor::observable::observer_ptr& o) override;
+       void unsubscribe(const monitor::observable::observer_ptr& o) override;
+
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+
+spl::shared_ptr<frame_producer> do_create_text_producer(const spl::shared_ptr<class frame_factory>& frame_factory, int x, int y, const std::wstring& str, const text::text_info& text_info, long parent_width, long parent_height);
+spl::shared_ptr<frame_producer> create_text_producer(const spl::shared_ptr<class frame_factory>& frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params);
+
+
+}}
diff --git a/core/producer/text/utils/color.h b/core/producer/text/utils/color.h
new file mode 100644 (file)
index 0000000..1200287
--- /dev/null
@@ -0,0 +1,28 @@
+#pragma once
+
+namespace caspar { namespace core { namespace text {
+
+template<typename T>
+struct color
+{
+       color() {}
+       color(const color& other) : r(other.r), g(other.g), b(other.b), a(other.a) {}
+       color(T red, T green, T blue, T alpha) : r(red), g(green), b(blue), a(alpha) {}
+
+       const color&operator=(const color& other)
+       {
+               r = other.r;
+               g = other.g;
+               b = other.b;
+               a = other.a;
+
+               return *this;
+       }
+
+       T r;
+       T g;
+       T b;
+       T a;
+};
+
+}}}
\ No newline at end of file
diff --git a/core/producer/text/utils/string_metrics.h b/core/producer/text/utils/string_metrics.h
new file mode 100644 (file)
index 0000000..f0f9fa3
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+
+namespace caspar { namespace core { namespace text {
+
+       struct string_metrics
+       {
+               string_metrics() : width(0), bearingY(0), height(0) {}
+               int width;
+               int bearingY;
+               int height;
+       };
+}}}
\ No newline at end of file
diff --git a/core/producer/text/utils/texture_atlas.cpp b/core/producer/text/utils/texture_atlas.cpp
new file mode 100644 (file)
index 0000000..c7fe473
--- /dev/null
@@ -0,0 +1,233 @@
+/* ============================================================================
+ * Freetype GL - A C OpenGL Freetype engine
+ * Platform:    Any
+ * WWW:         http://code.google.com/p/freetype-gl/
+ * ----------------------------------------------------------------------------
+ * Copyright 2011,2012 Nicolas P. Rougier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are
+ * those of the authors and should not be interpreted as representing official
+ * policies, either expressed or implied, of Nicolas P. Rougier.
+ * ============================================================================
+ */
+
+#include <list>
+#include <vector>
+#include "texture_atlas.h"
+
+namespace caspar { namespace core { namespace text {
+
+
+struct texture_atlas::impl
+{
+private:
+       struct node
+       {
+               int x;
+               int y;
+               int width;
+       };
+
+       typedef std::list<node> node_list;
+       typedef std::list<node>::iterator node_iterator;
+
+public:
+       impl(const size_t width, const size_t height, const size_t depth) : width_(width), height_(height), depth_(depth), used_(0), data_(width*height*depth, 0)
+       {
+               // We want a one pixel border around the whole atlas to avoid any artefact when sampling texture
+               node n = {1, 1, (int)width_ - 2};
+               nodes_.push_back(n);
+       }
+
+       rect get_region(int width, int height)
+       {
+               int y, best_height, best_width;
+    
+               rect region = {0,0,(int)width,(int)height};
+
+               best_height = INT_MAX;
+               best_width = INT_MAX;
+               node_iterator best_it = nodes_.end();
+
+               auto it = nodes_.begin();
+               for(; it != nodes_.end(); ++it)
+               {
+                       y = fit(it, width, height);
+                       if( y >= 0 )
+                       {
+                               if( ( (y + height) < best_height ) ||
+                                       ( ((y + height) == best_height) && ((*it).width < best_width)) )
+                               {
+                                       best_height = y + height;
+                                       best_it = it;
+                                       best_width = (*it).width;
+                                       region.x = (*it).x;
+                                       region.y = (int)y;
+                               }
+                       }
+               }
+   
+               if(best_it == nodes_.end())
+               {
+                       region.x = -1;
+                       region.y = -1;
+                       region.width = 0;
+                       region.height = 0;
+                       return region;
+               }
+
+               node new_node;
+               new_node.x = region.x;
+               new_node.y = region.y + (int)height;
+               new_node.width = (int)width;
+
+               best_it = nodes_.insert(best_it, new_node);
+
+               for(auto it = ++best_it; it != nodes_.end(); ++it)
+               {
+                       auto prev = it; --prev;
+
+                       if ((*it).x < ((*prev).x + (*prev).width) )
+                       {
+                               int shrink = (*prev).x + (*prev).width - (*it).x;
+                               (*it).x += shrink;
+                               (*it).width -= shrink;
+                               if ((*it).width <= 0)
+                               {
+                                       nodes_.erase(it);
+                                       it = prev;
+                               }
+                               else
+                                       break;
+                       }
+                       else
+                               break;
+               }
+
+               merge();
+               used_ += width * height;
+               return region;
+       }
+
+       //the data parameter points to bitmap-data that is 8-bit grayscale.
+       void set_region(const size_t x, const size_t y, const size_t width, const size_t height, const unsigned char *src, const size_t stride, const color<float>& col)
+       {
+               //this assumes depth_ is set to 4
+               for(size_t i=0; i<height; ++i)
+               {
+                       for(size_t j=0; j<width; ++j)
+                       {
+                               unsigned char* pixel = &data_[((y+i)*width_ + x + j)*depth_];
+                               unsigned char value = src[i*stride + j];
+                               pixel[0] = (unsigned char)(value*col.b);
+                               pixel[1] = (unsigned char)(value*col.g);
+                               pixel[2] = (unsigned char)(value*col.r);
+                               pixel[3] = (unsigned char)(value*col.a);
+                       }
+               }
+       }
+
+       void clear()
+       {
+               nodes_.clear();
+               used_ = 0;
+
+               node n = {1,1,(int)width_-2};
+               nodes_.push_back(n);
+               data_.assign(width_*height_*depth_, 0);
+       }
+
+       size_t depth() { return depth_; }
+       size_t width() { return width_; }
+       size_t height() { return height_; }
+       unsigned char* data() { return data_.data(); }
+
+private:
+       int fit(node_iterator it, const size_t width, const size_t height)
+       {
+               int x, y, width_left;
+
+               x = (*it).x;
+               y = (*it).y;
+               width_left = (int)width;
+
+               if ((x + width) > (width_ - 1))
+                       return -1;
+
+               while( width_left > 0 && it != nodes_.end())
+               {
+                       if((*it).y > y)
+                               y = (*it).y;
+                       if((y + height) > (height_ - 1))
+                               return -1;
+
+                       width_left -= (*it).width;
+                       ++it;
+               }
+
+               return y;
+       }
+
+       void merge()
+       {
+               auto it = nodes_.begin();
+               while(true)
+               {
+                       auto next = it; ++next;
+                       if(next == nodes_.end())
+                               break;
+
+                       if((*it).y == (*next).y)
+                       {
+                               (*it).width += (*next).width;
+                               nodes_.erase(next);
+                       }
+                       else
+                               ++it;
+               }
+       }
+
+       node_list nodes_;
+
+       size_t width_;
+       size_t height_;
+       size_t depth_;
+
+       std::vector<unsigned char> data_;
+       size_t used_;
+};
+
+texture_atlas::texture_atlas(const size_t w, const size_t h, const size_t d) : impl_(new impl(w, h, d)) {}
+rect texture_atlas::get_region(int width, int height) { return impl_->get_region(width, height); }
+void texture_atlas::set_region(const size_t x, const size_t y, const size_t width, const size_t height, const unsigned char *src, const size_t stride, const color<float>& col)
+       { impl_->set_region(x, y, width, height, src, stride, col); }
+
+void texture_atlas::clear() { impl_->clear(); }
+
+size_t texture_atlas::width() { return impl_->width(); }
+size_t texture_atlas::height() { return impl_->height(); }
+size_t texture_atlas::depth() { return impl_->depth(); }
+unsigned char* texture_atlas::data() { return impl_->data(); }
+
+}}}
\ No newline at end of file
diff --git a/core/producer/text/utils/texture_atlas.h b/core/producer/text/utils/texture_atlas.h
new file mode 100644 (file)
index 0000000..ff1ffeb
--- /dev/null
@@ -0,0 +1,98 @@
+/* ============================================================================
+ * Freetype GL - A C OpenGL Freetype engine
+ * Platform:    Any
+ * WWW:         http://code.google.com/p/freetype-gl/
+ * ----------------------------------------------------------------------------
+ * Copyright 2011,2012 Nicolas P. Rougier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are
+ * those of the authors and should not be interpreted as representing official
+ * policies, either expressed or implied, of Nicolas P. Rougier.
+ * ============================================================================
+ *
+ * This source is based on the article by Jukka Jylänki :
+ * "A Thousand Ways to Pack the Bin - A Practical Approach to
+ * Two-Dimensional Rectangle Bin Packing", February 27, 2010.
+ *
+ * More precisely, this is an implementation of the Skyline Bottom-Left
+ * algorithm based on C++ sources provided by Jukka Jylänki at:
+ * http://clb.demon.fi/files/RectangleBinPack/
+ *
+ *  ============================================================================
+ */
+#pragma once
+
+
+/**
+ * @file   texture-atlas.h
+ * @author Nicolas Rougier (Nicolas.Rougier@inria.fr)
+ *
+ * @defgroup texture-atlas Texture atlas
+ *
+ * A texture atlas is used to pack several small regions into a single texture.
+ *
+ * The actual implementation is based on the article by Jukka Jylänki : "A
+ * Thousand Ways to Pack the Bin - A Practical Approach to Two-Dimensional
+ * Rectangle Bin Packing", February 27, 2010.
+ * More precisely, this is an implementation of the Skyline Bottom-Left
+ * algorithm based on C++ sources provided by Jukka Jylänki at:
+ * http://clb.demon.fi/files/RectangleBinPack/
+ *
+ *
+ */
+
+#include "common/memory.h"
+#include "color.h"
+
+namespace caspar { namespace core { namespace text {
+
+struct rect
+{
+       int x;
+       int y;
+       int width;
+       int height;
+};
+
+class texture_atlas
+{
+public:
+       texture_atlas(const size_t w, const size_t h, const size_t d);
+
+       rect get_region(int width, int height);
+       void set_region(const size_t x, const size_t y, const size_t width, const size_t height, const unsigned char *data, const size_t stride, const color<float>& col);
+       void clear();
+
+       size_t depth();
+       size_t width();
+       size_t height();
+
+       unsigned char* data();
+
+private:
+       struct impl;
+       caspar::spl::shared_ptr<impl> impl_;
+};
+
+}}}
diff --git a/core/producer/text/utils/texture_font.cpp b/core/producer/text/utils/texture_font.cpp
new file mode 100644 (file)
index 0000000..ad15f38
--- /dev/null
@@ -0,0 +1,476 @@
+#include "..\..\..\StdAfx.h"
+
+#include "texture_atlas.h"
+#include "texture_font.h"
+
+#include <map>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+namespace caspar { namespace core { namespace text {
+
+struct freetype_exception : virtual caspar_exception
+{
+       freetype_exception() {}
+       explicit freetype_exception(const char* msg) : caspar_exception(msg) {}
+};
+
+struct unicode_range
+{
+       int first;
+       int last;
+};
+
+unicode_range get_range(unicode_block block);
+
+
+struct texture_font::impl
+{
+private:
+       struct glyph_info
+       {
+               glyph_info(int w, int h, float l, float t, float r, float b) : width(w), height(h), left(l), top(t), right(r), bottom(b)
+               {}
+
+               float left, top, right, bottom;
+               int width, height;
+       };
+
+       FT_Library              lib_;
+       FT_Face                 face_;
+       texture_atlas   atlas_;
+       float                   size_;
+       std::map<int, glyph_info> glyphs_;
+
+public:
+       impl::impl(texture_atlas& atlas, const std::wstring& filename, float size) : lib_(nullptr), face_(nullptr), atlas_(atlas), size_(size)
+       {
+               try
+               {
+                       FT_Error err;
+                       err = FT_Init_FreeType(&lib_);
+                       if(err) throw freetype_exception("Failed to initialize freetype");
+
+                       err = FT_New_Face(lib_, u8(filename).c_str(), 0, &face_);
+                       if(err) throw freetype_exception("Failed to load font");
+
+                       err = FT_Set_Char_Size(face_, (FT_F26Dot6)(size*64), 0, 72, 72);
+                       if(err) throw freetype_exception("Failed to set font size");
+               }
+               catch(std::exception& ex)
+               {
+                       if(face_ != nullptr)
+                               FT_Done_Face(face_);
+                       if(lib_ != nullptr)
+                               FT_Done_FreeType(lib_);
+
+                       throw ex;
+               }
+       }
+
+       ~impl()
+       {
+               if(face_ != nullptr)
+                       FT_Done_Face(face_);
+               if(lib_ != nullptr)
+                       FT_Done_FreeType(lib_);
+       }
+
+       int count_glyphs_in_range(unicode_block block)
+       { 
+               unicode_range range = get_range(block);
+
+               //TODO: extract info from freetype
+
+               //very pesimistic, assumes a glyph for each charcode
+               return range.last - range.first;
+       }
+
+       void impl::load_glyphs(unicode_block block, const color<float>& col)
+       {
+               FT_Error err;
+               int flags = FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL;
+               unicode_range range = get_range(block);
+
+               for(int i = range.first; i <= range.last; ++i)
+               {
+                       FT_UInt glyph_index = FT_Get_Char_Index(face_, i);
+                       if(!glyph_index)        //ignore codes that doesn't have a glyph for now. Might want to map these to a special glyph later.
+                               continue;
+                       
+                       err = FT_Load_Glyph(face_, glyph_index, flags);
+                       if(err) continue;       //igonore glyphs that fail to load
+
+                       const FT_Bitmap& bitmap = face_->glyph->bitmap; //shorthand notation
+
+                       auto region = atlas_.get_region(bitmap.width+1, bitmap.rows+1);
+                       if(region.x < 0)
+                       {
+                               //the glyph doesn't fit in the texture-atlas. ignore it for now.
+                               //we might want to restart with a bigger atlas in the future
+                               continue;
+                       }
+
+                       atlas_.set_region(region.x, region.y, bitmap.width, bitmap.rows, bitmap.buffer, bitmap.pitch, col);
+                       glyphs_.insert(std::pair<int, glyph_info>(i, glyph_info(bitmap.width, bitmap.rows, 
+                                                                               region.x / (float)atlas_.width(), 
+                                                                               region.y / (float)atlas_.height(), 
+                                                                               (region.x + bitmap.width) / (float)atlas_.width(), 
+                                                                               (region.y + bitmap.rows) / (float)atlas_.height())));
+               }
+       }
+
+       std::vector<float> create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height)
+       {
+               //TODO: detect glyphs that aren't in the atlas and load them (and maybe that entire unicode_block on the fly
+
+               std::vector<float> result(16*str.length(), 0);
+
+               bool use_kerning = (face_->face_flags & FT_FACE_FLAG_KERNING) == FT_FACE_FLAG_KERNING;
+               int index = 0;
+               FT_UInt previous = 0;
+               float pos_x = (float)x;
+               float pos_y = (float)y;
+
+               auto end = str.end();
+               for(auto it = str.begin(); it != end; ++it, ++index)
+               {
+                       auto glyph_it = glyphs_.find(*it);
+                       if(glyph_it != glyphs_.end())
+                       {       
+                               const glyph_info& coords = glyph_it->second;
+
+                               FT_UInt glyph_index = FT_Get_Char_Index(face_, (*it));
+
+                               if(use_kerning && previous && glyph_index)
+                               {
+                                       FT_Vector delta;
+                                       FT_Get_Kerning(face_, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
+
+                                       pos_x += delta.x / 64.0f;
+                               }
+
+                               FT_Load_Glyph(face_, glyph_index, FT_LOAD_NO_BITMAP | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL);
+
+                               float left = (pos_x + face_->glyph->metrics.horiBearingX/64.0f) / parent_width ;
+                               float right = ((pos_x + face_->glyph->metrics.horiBearingX/64.0f) + coords.width) / parent_width;
+
+                               float top = (pos_y - face_->glyph->metrics.horiBearingY/64.0f) / parent_height;
+                               float bottom = ((pos_y - face_->glyph->metrics.horiBearingY/64.0f) + coords.height) / parent_height;
+
+                               //vertex 1 top left
+                               result[index*16 + 0] = left;                    //vertex.x
+                               result[index*16 + 1] = top;                             //vertex.y
+                               result[index*16 + 2] = coords.left;             //texcoord.r
+                               result[index*16 + 3] = coords.top;              //texcoord.s
+
+                               //vertex 2 top right
+                               result[index*16 + 4] = right;                   //vertex.x
+                               result[index*16 + 5] = top;                             //vertex.y
+                               result[index*16 + 6] = coords.right;    //texcoord.r
+                               result[index*16 + 7] = coords.top;              //texcoord.s
+
+                               //vertex 3 bottom right
+                               result[index*16 + 8] = right;                   //vertex.x
+                               result[index*16 + 9] = bottom;                  //vertex.y
+                               result[index*16 + 10] = coords.right;   //texcoord.r
+                               result[index*16 + 11] = coords.bottom;  //texcoord.s
+
+                               //vertex 4 bottom left
+                               result[index*16 + 12] = left;                   //vertex.x
+                               result[index*16 + 13] = bottom;                 //vertex.y
+                               result[index*16 + 14] = coords.left;    //texcoord.r
+                               result[index*16 + 15] = coords.bottom;  //texcoord.s
+
+                               pos_x += face_->glyph->advance.x / 64.0f;
+                               previous = glyph_index;
+                       }
+               }
+               return result;
+       }
+
+       string_metrics measure_string(const std::wstring& str)
+       {
+               string_metrics result;
+               
+               bool use_kerning = (face_->face_flags & FT_FACE_FLAG_KERNING) == FT_FACE_FLAG_KERNING;
+               int index = 0;
+               FT_UInt previous = 0;
+               float pos_x = 0;
+//             float pos_y = 0;
+
+               auto end = str.end();
+               for(auto it = str.begin(); it != end; ++it, ++index)
+               {
+                       auto glyph_it = glyphs_.find(*it);
+                       if(glyph_it != glyphs_.end())
+                       {       
+                               const glyph_info& coords = glyph_it->second;
+
+                               FT_UInt glyph_index = FT_Get_Char_Index(face_, (*it));
+
+                               if(use_kerning && previous && glyph_index)
+                               {
+                                       FT_Vector delta;
+                                       FT_Get_Kerning(face_, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
+
+                                       pos_x += delta.x / 64.0f;
+                               }
+
+                               FT_Load_Glyph(face_, glyph_index, FT_LOAD_NO_BITMAP | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_NORMAL);
+
+                               int bearingY = face_->glyph->metrics.horiBearingY >> 6;
+                               if(bearingY > result.bearingY)
+                                       result.bearingY = bearingY;
+
+                               if(coords.height > result.height)
+                                       result.height = coords.height;
+
+                               pos_x += face_->glyph->advance.x / 64.0f;
+                               previous = glyph_index;
+                       }
+               }
+
+               result.width = (int)(pos_x+.5f);
+               return result;
+       }
+}; 
+
+texture_font::texture_font(texture_atlas& atlas, const std::wstring& filename, float size) : impl_(new impl(atlas, filename, size)) {}
+void texture_font::load_glyphs(unicode_block range, const color<float>& col) { impl_->load_glyphs(range, col); }
+std::vector<float> texture_font::create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height) { return impl_->create_vertex_stream(str, x, y, parent_width, parent_height); }
+string_metrics texture_font::measure_string(const std::wstring& str) { return impl_->measure_string(str); }
+
+unicode_range get_range(unicode_block block)
+{
+       //TODO: implement
+       unicode_range range = {0x0000, 0x007F};
+       return range;
+}
+
+}}}
+
+//unicode blocks
+/*
+               range(0x0000, 0x007F); 
+               range(0x0080, 0x00FF); 
+               range(0x0100, 0x017F); 
+               range(0x0180, 0x024F); 
+               range(0x0250, 0x02AF); 
+               range(0x02B0, 0x02FF); 
+               range(0x0300, 0x036F); 
+               range(0x0370, 0x03FF); 
+               range(0x0400, 0x04FF); 
+               range(0x0500, 0x052F); 
+               range(0x0530, 0x058F); 
+               range(0x0590, 0x05FF); 
+               range(0x0600, 0x06FF); 
+               range(0x0700, 0x074F); 
+               range(0x0750, 0x077F); 
+               range(0x0780, 0x07BF); 
+               range(0x07C0, 0x07FF); 
+               range(0x0800, 0x083F); 
+               range(0x0840, 0x085F); 
+               range(0x08A0, 0x08FF); 
+               range(0x0900, 0x097F); 
+               range(0x0980, 0x09FF); 
+               range(0x0A00, 0x0A7F); 
+               range(0x0A80, 0x0AFF); 
+               range(0x0B00, 0x0B7F); 
+               range(0x0B80, 0x0BFF); 
+               range(0x0C00, 0x0C7F); 
+               range(0x0C80, 0x0CFF); 
+               range(0x0D00, 0x0D7F); 
+               range(0x0D80, 0x0DFF); 
+               range(0x0E00, 0x0E7F); 
+               range(0x0E80, 0x0EFF); 
+               range(0x0F00, 0x0FFF); 
+               range(0x1000, 0x109F); 
+               range(0x10A0, 0x10FF); 
+               range(0x1100, 0x11FF); 
+               range(0x1200, 0x137F); 
+               range(0x1380, 0x139F); 
+               range(0x13A0, 0x13FF); 
+               range(0x1400, 0x167F); 
+               range(0x1680, 0x169F); 
+               range(0x16A0, 0x16FF); 
+               range(0x1700, 0x171F); 
+               range(0x1720, 0x173F); 
+               range(0x1740, 0x175F); 
+               range(0x1760, 0x177F); 
+               range(0x1780, 0x17FF); 
+               range(0x1800, 0x18AF); 
+               range(0x18B0, 0x18FF); 
+               range(0x1900, 0x194F); 
+               range(0x1950, 0x197F); 
+               range(0x1980, 0x19DF); 
+               range(0x19E0, 0x19FF); 
+               range(0x1A00, 0x1A1F); 
+               range(0x1A20, 0x1AAF); 
+               range(0x1B00, 0x1B7F); 
+               range(0x1B80, 0x1BBF); 
+               range(0x1BC0, 0x1BFF); 
+               range(0x1C00, 0x1C4F); 
+               range(0x1C50, 0x1C7F); 
+               range(0x1CC0, 0x1CCF); 
+               range(0x1CD0, 0x1CFF); 
+               range(0x1D00, 0x1D7F); 
+               range(0x1D80, 0x1DBF); 
+               range(0x1DC0, 0x1DFF); 
+               range(0x1E00, 0x1EFF); 
+               range(0x1F00, 0x1FFF); 
+               range(0x2000, 0x206F); 
+               range(0x2070, 0x209F); 
+               range(0x20A0, 0x20CF); 
+               range(0x20D0, 0x20FF); 
+               range(0x2100, 0x214F); 
+               range(0x2150, 0x218F); 
+               range(0x2190, 0x21FF); 
+               range(0x2200, 0x22FF); 
+               range(0x2300, 0x23FF); 
+               range(0x2400, 0x243F); 
+               range(0x2440, 0x245F); 
+               range(0x2460, 0x24FF); 
+               range(0x2500, 0x257F); 
+               range(0x2580, 0x259F); 
+               range(0x25A0, 0x25FF); 
+               range(0x2600, 0x26FF); 
+               range(0x2700, 0x27BF); 
+               range(0x27C0, 0x27EF); 
+               range(0x27F0, 0x27FF); 
+               range(0x2800, 0x28FF); 
+               range(0x2900, 0x297F); 
+               range(0x2980, 0x29FF); 
+               range(0x2A00, 0x2AFF); 
+               range(0x2B00, 0x2BFF); 
+               range(0x2C00, 0x2C5F); 
+               range(0x2C60, 0x2C7F); 
+               range(0x2C80, 0x2CFF); 
+               range(0x2D00, 0x2D2F); 
+               range(0x2D30, 0x2D7F); 
+               range(0x2D80, 0x2DDF); 
+               range(0x2DE0, 0x2DFF); 
+               range(0x2E00, 0x2E7F); 
+               range(0x2E80, 0x2EFF); 
+               range(0x2F00, 0x2FDF); 
+               range(0x2FF0, 0x2FFF); 
+               range(0x3000, 0x303F); 
+               range(0x3040, 0x309F); 
+               range(0x30A0, 0x30FF); 
+               range(0x3100, 0x312F); 
+               range(0x3130, 0x318F); 
+               range(0x3190, 0x319F); 
+               range(0x31A0, 0x31BF); 
+               range(0x31C0, 0x31EF); 
+               range(0x31F0, 0x31FF); 
+               range(0x3200, 0x32FF); 
+               range(0x3300, 0x33FF); 
+               range(0x3400, 0x4DBF); 
+               range(0x4DC0, 0x4DFF); 
+               range(0x4E00, 0x9FFF); 
+               range(0xA000, 0xA48F); 
+               range(0xA490, 0xA4CF); 
+               range(0xA4D0, 0xA4FF); 
+               range(0xA500, 0xA63F); 
+               range(0xA640, 0xA69F); 
+               range(0xA6A0, 0xA6FF); 
+               range(0xA700, 0xA71F); 
+               range(0xA720, 0xA7FF); 
+               range(0xA800, 0xA82F); 
+               range(0xA830, 0xA83F); 
+               range(0xA840, 0xA87F); 
+               range(0xA880, 0xA8DF); 
+               range(0xA8E0, 0xA8FF); 
+               range(0xA900, 0xA92F); 
+               range(0xA930, 0xA95F); 
+               range(0xA960, 0xA97F); 
+               range(0xA980, 0xA9DF); 
+               range(0xAA00, 0xAA5F); 
+               range(0xAA60, 0xAA7F); 
+               range(0xAA80, 0xAADF); 
+               range(0xAAE0, 0xAAFF); 
+               range(0xAB00, 0xAB2F); 
+               range(0xABC0, 0xABFF); 
+               range(0xAC00, 0xD7AF); 
+               range(0xD7B0, 0xD7FF); 
+               range(0xD800, 0xDB7F); 
+               range(0xDB80, 0xDBFF); 
+               range(0xDC00, 0xDFFF); 
+               range(0xE000, 0xF8FF); 
+               range(0xF900, 0xFAFF); 
+               range(0xFB00, 0xFB4F); 
+               range(0xFB50, 0xFDFF); 
+               range(0xFE00, 0xFE0F); 
+               range(0xFE10, 0xFE1F); 
+               range(0xFE20, 0xFE2F); 
+               range(0xFE30, 0xFE4F); 
+               range(0xFE50, 0xFE6F); 
+               range(0xFE70, 0xFEFF); 
+               range(0xFF00, 0xFFEF); 
+               range(0xFFF0, 0xFFFF); 
+               range(0x10000, 0x1007F); 
+               range(0x10080, 0x100FF); 
+               range(0x10100, 0x1013F); 
+               range(0x10140, 0x1018F); 
+               range(0x10190, 0x101CF); 
+               range(0x101D0, 0x101FF); 
+               range(0x10280, 0x1029F); 
+               range(0x102A0, 0x102DF); 
+               range(0x10300, 0x1032F); 
+               range(0x10330, 0x1034F); 
+               range(0x10380, 0x1039F); 
+               range(0x103A0, 0x103DF); 
+               range(0x10400, 0x1044F); 
+               range(0x10450, 0x1047F); 
+               range(0x10480, 0x104AF); 
+               range(0x10800, 0x1083F); 
+               range(0x10840, 0x1085F); 
+               range(0x10900, 0x1091F); 
+               range(0x10920, 0x1093F); 
+               range(0x10980, 0x1099F); 
+               range(0x109A0, 0x109FF); 
+               range(0x10A00, 0x10A5F); 
+               range(0x10A60, 0x10A7F); 
+               range(0x10B00, 0x10B3F); 
+               range(0x10B40, 0x10B5F); 
+               range(0x10B60, 0x10B7F); 
+               range(0x10C00, 0x10C4F); 
+               range(0x10E60, 0x10E7F); 
+               range(0x11000, 0x1107F); 
+               range(0x11080, 0x110CF); 
+               range(0x110D0, 0x110FF); 
+               range(0x11100, 0x1114F); 
+               range(0x11180, 0x111DF); 
+               range(0x11680, 0x116CF); 
+               range(0x12000, 0x123FF); 
+               range(0x12400, 0x1247F); 
+               range(0x13000, 0x1342F); 
+               range(0x16800, 0x16A3F); 
+               range(0x16F00, 0x16F9F); 
+               range(0x1B000, 0x1B0FF); 
+               range(0x1D000, 0x1D0FF); 
+               range(0x1D100, 0x1D1FF); 
+               range(0x1D200, 0x1D24F); 
+               range(0x1D300, 0x1D35F); 
+               range(0x1D360, 0x1D37F); 
+               range(0x1D400, 0x1D7FF); 
+               range(0x1EE00, 0x1EEFF); 
+               range(0x1F000, 0x1F02F); 
+               range(0x1F030, 0x1F09F); 
+               range(0x1F0A0, 0x1F0FF); 
+               range(0x1F100, 0x1F1FF); 
+               range(0x1F200, 0x1F2FF); 
+               range(0x1F300, 0x1F5FF); 
+               range(0x1F600, 0x1F64F); 
+               range(0x1F680, 0x1F6FF); 
+               range(0x1F700, 0x1F77F); 
+               range(0x20000, 0x2A6DF); 
+               range(0x2A700, 0x2B73F); 
+               range(0x2B740, 0x2B81F); 
+               range(0x2F800, 0x2FA1F); 
+               range(0xE0000, 0xE007F); 
+               range(0xE0100, 0xE01EF); 
+               range(0xF0000, 0xFFFFF); 
+               range(0x100000, 0x10FFFF);
+*/
\ No newline at end of file
diff --git a/core/producer/text/utils/texture_font.h b/core/producer/text/utils/texture_font.h
new file mode 100644 (file)
index 0000000..7261469
--- /dev/null
@@ -0,0 +1,255 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include <common/memory.h>
+
+#include "string_metrics.h"
+
+namespace caspar { namespace core { namespace text {
+
+class texture_atlas;
+enum unicode_block;
+
+class texture_font
+{
+       texture_font();
+       texture_font(const texture_font&);
+       const texture_font& operator=(const texture_font&);
+
+public:
+       texture_font(texture_atlas&, const std::wstring& filename, float size);
+       void load_glyphs(unicode_block block, const color<float>& col);
+       std::vector<float> create_vertex_stream(const std::wstring& str, int x, int y, int parent_width, int parent_height);
+       string_metrics measure_string(const std::wstring& str);
+
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
+enum unicode_block
+{
+       Basic_Latin,
+       Latin_1_Supplement,
+       Latin_Extended_A,
+       Latin_Extended_B,
+       IPA_Extensions,
+       Spacing_Modifier_Letters,
+       Combining_Diacritical_Marks,
+       Greek_and_Coptic,
+       Cyrillic,
+       Cyrillic_Supplement,
+       Armenian,
+       Hebrew,
+       Arabic,
+       Syriac,
+       Arabic_Supplement,
+       Thaana,
+       NKo,
+       Samaritan,
+       Mandaic,
+       Arabic_Extended_A,
+       Devanagari,
+       Bengali,
+       Gurmukhi,
+       Gujarati,
+       Oriya,
+       Tamil,
+       Telugu,
+       Kannada,
+       Malayalam,
+       Sinhala,
+       Thai,
+       Lao,
+       Tibetan,
+       Myanmar,
+       Georgian,
+       Hangul_Jamo,
+       Ethiopic,
+       Ethiopic_Supplement,
+       Cherokee,
+       Unified_Canadian_Aboriginal_Syllabics,
+       Ogham,
+       Runic,
+       Tagalog,
+       Hanunoo,
+       Buhid,
+       Tagbanwa,
+       Khmer,
+       Mongolian,
+       Unified_Canadian_Aboriginal_Syllabics_Extended,
+       Limbu,
+       Tai_Le,
+       New_Tai_Lue,
+       Khmer_Symbols,
+       Buginese,
+       Tai_Tham,
+       Balinese,
+       Sundanese,
+       Batak,
+       Lepcha,
+       Ol_Chiki,
+       Sundanese_Supplement,
+       Vedic_Extensions,
+       Phonetic_Extensions,
+       Phonetic_Extensions_Supplement,
+       Combining_Diacritical_Marks_Supplement,
+       Latin_Extended_Additional,
+       Greek_Extended,
+       General_Punctuation,
+       Superscripts_and_Subscripts,
+       Currency_Symbols,
+       Combining_Diacritical_Marks_for_Symbols,
+       Letterlike_Symbols,
+       Number_Forms,
+       Arrows,
+       Mathematical_Operators,
+       Miscellaneous_Technical,
+       Control_Pictures,
+       Optical_Character_Recognition,
+       Enclosed_Alphanumerics,
+       Box_Drawing,
+       Block_Elements,
+       Geometric_Shapes,
+       Miscellaneous_Symbols,
+       Dingbats,
+       Miscellaneous_Mathematical_Symbols_A,
+       Supplemental_Arrows_A,
+       Braille_Patterns,
+       Supplemental_Arrows_B,
+       Miscellaneous_Mathematical_Symbols_B,
+       Supplemental_Mathematical_Operators,
+       Miscellaneous_Symbols_and_Arrows,
+       Glagolitic,
+       Latin_Extended_C,
+       Coptic,
+       Georgian_Supplement,
+       Tifinagh,
+       Ethiopic_Extended,
+       Cyrillic_Extended_A,
+       Supplemental_Punctuation,
+       CJK_Radicals_Supplement,
+       Kangxi_Radicals,
+       Ideographic_Description_Characters,
+       CJK_Symbols_and_Punctuation,
+       Hiragana,
+       Katakana,
+       Bopomofo,
+       Hangul_Compatibility_Jamo,
+       Kanbun,
+       Bopomofo_Extended,
+       CJK_Strokes,
+       Katakana_Phonetic_Extensions,
+       Enclosed_CJK_Letters_and_Months,
+       CJK_Compatibility,
+       CJK_Unified_Ideographs_Extension_A,
+       Yijing_Hexagram_Symbols,
+       CJK_Unified_Ideographs,
+       Yi_Syllables,
+       Yi_Radicals,
+       Lisu,
+       Vai,
+       Cyrillic_Extended_B,
+       Bamum,
+       Modifier_Tone_Letters,
+       Latin_Extended_D,
+       Syloti_Nagri,
+       Common_Indic_Number_Forms,
+       Phags_pa,
+       Saurashtra,
+       Devanagari_Extended,
+       Kayah_Li,
+       Rejang,
+       Hangul_Jamo_Extended_A,
+       Javanese,
+       Cham,
+       Myanmar_Extended_A,
+       Tai_Viet,
+       Meetei_Mayek_Extensions,
+       Ethiopic_Extended_A,
+       Meetei_Mayek,
+       Hangul_Syllables,
+       Hangul_Jamo_Extended_B,
+       High_Surrogates,
+       High_Private_Use_Surrogates,
+       Low_Surrogates,
+       Private_Use_Area,
+       CJK_Compatibility_Ideographs,
+       Alphabetic_Presentation_Forms,
+       Arabic_Presentation_Forms_A,
+       Variation_Selectors,
+       Vertical_Forms,
+       Combining_Half_Marks,
+       CJK_Compatibility_Forms,
+       Small_Form_Variants,
+       Arabic_Presentation_Forms_B,
+       Halfwidth_and_Fullwidth_Forms,
+       Specials,
+       Linear_B_Syllabary,
+       Linear_B_Ideograms,
+       Aegean_Numbers,
+       Ancient_Greek_Numbers,
+       Ancient_Symbols,
+       Phaistos_Disc,
+       Lycian,
+       Carian,
+       Old_Italic,
+       Gothic,
+       Ugaritic,
+       Old_Persian,
+       Deseret,
+       Shavian,
+       Osmanya,
+       Cypriot_Syllabary,
+       Imperial_Aramaic,
+       Phoenician,
+       Lydian,
+       Meroitic_Hieroglyphs,
+       Meroitic_Cursive,
+       Kharoshthi,
+       Old_South_Arabian,
+       Avestan,
+       Inscriptional_Parthian,
+       Inscriptional_Pahlavi,
+       Old_Turkic,
+       Rumi_Numeral_Symbols,
+       Brahmi,
+       Kaithi,
+       Sora_Sompeng,
+       Chakma,
+       Sharada,
+       Takri,
+       Cuneiform,
+       Cuneiform_Numbers_and_Punctuation,
+       Egyptian_Hieroglyphs,
+       Bamum_Supplement,
+       Miao,
+       Kana_Supplement,
+       Byzantine_Musical_Symbols,
+       Musical_Symbols,
+       Ancient_Greek_Musical_Notation,
+       Tai_Xuan_Jing_Symbols,
+       Counting_Rod_Numerals,
+       Mathematical_Alphanumeric_Symbols,
+       Arabic_Mathematical_Alphabetic_Symbols,
+       Mahjong_Tiles,
+       Domino_Tiles,
+       Playing_Cards,
+       Enclosed_Alphanumeric_Supplement,
+       Enclosed_Ideographic_Supplement,
+       Miscellaneous_Symbols_And_Pictographs,
+       Emoticons,
+       Transport_And_Map_Symbols,
+       Alchemical_Symbols,
+       CJK_Unified_Ideographs_Extension_B,
+       CJK_Unified_Ideographs_Extension_C,
+       CJK_Unified_Ideographs_Extension_D,
+       CJK_Compatibility_Ideographs_Supplement,
+       Tags,
+       Variation_Selectors_Supplement,
+       Supplementary_Private_Use_Area_A,
+       Supplementary_Private_Use_Area_B
+};
+
+}}}
\ No newline at end of file
index b225407cdb730140a9ff4f026df0dd5e99d016dd..4f29f3ece30861a463396a5d84946090d722be9d 100644 (file)
@@ -206,11 +206,11 @@ void layer::read_channel_data(BEFileInputStream& stream)
        
        if(rect_.width() > 0 && rect_.height() > 0)
        {
-               img = std::make_shared<image8bit>(rect_.width(), rect_.height(), std::min<unsigned char>(channels_.size() - masks_, 4));
+               img = std::make_shared<image8bit>(rect_.width(), rect_.height(), 4);
                //std::clog << std::dec << "has image: [width: " << rect_.width() << " height: " << rect_.height() << "]" << std::endl;
 
                if(!has_transparency)
-                       std::memset(img->data(), (unsigned long)(255<<24), rect_.width()*rect_.height());
+                       std::memset(img->data(), 255, img->width()*img->height()*img->channel_count());
        }
 
        if(masks_ > 0 && mask_.rect_.width() > 0 && mask_.rect_.height() > 0)
index fabc629e95273df33324072e2423f4fb8d66db12..0169fdea54694576ff3895e063097e2e17f42707 100644 (file)
 #include <core/frame/pixel_format.h>
 #include <core/frame/frame_factory.h>
 #include <core/producer/frame_producer.h>
+#include <core/producer/text/text_producer.h>
 #include <core/producer/scene/scene_producer.h>
 #include <core/producer/scene/const_producer.h>
 #include <core/frame/draw_frame.h>
 
 #include <common/env.h>
+#include <common/memory.h>
 
 #include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
 
 namespace caspar { namespace psd {
 
@@ -41,6 +44,43 @@ void init()
        core::register_producer_factory(create_producer);
 }
 
+core::text::text_info get_text_info(const boost::property_tree::wptree& ptree)
+{
+       core::text::text_info result;
+       int font_index = ptree.get(L"EngineDict.StyleRun.RunArray..StyleSheet.StyleSheetData.Font", 0);
+       result.size = ptree.get(L"EngineDict.StyleRun.RunArray..StyleSheet.StyleSheetData.FontSize", 30.0f);
+
+       int child_index = 0;
+       auto color_node = ptree.get_child(L"EngineDict.StyleRun.RunArray..StyleSheet.StyleSheetData.FillColor.Values");
+       for(auto it = color_node.begin(); it != color_node.end(); ++it, ++child_index)
+       {
+               auto& value_node = (*it).second;
+               float value = value_node.get_value(0.0f);
+               switch(child_index)
+               {
+               case 0: result.color.a = value; break;
+               case 1: result.color.r = value; break;
+               case 2: result.color.g = value; break;
+               case 3: result.color.b = value; break;
+               }
+       }
+
+       //find fontname
+       child_index = 0;
+       auto fontset_node = ptree.get_child(L"ResourceDict.FontSet");
+       for(auto it = fontset_node.begin(); it != fontset_node.end(); ++it, ++child_index)
+       {
+               auto& font_node = (*it).second;
+               if(child_index == font_index)
+               {
+                       result.font = font_node.get(L"Name", L"");
+                       break;
+               }
+       }
+
+       return result;
+}
+
 spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
 {
        std::wstring filename = env::media_folder() + L"\\" + params[0] + L".psd";
@@ -56,10 +96,20 @@ spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core
        auto layers_end = doc.layers().end();
        for(auto it = doc.layers().begin(); it != layers_end; ++it)
        {
-               if((*it)->is_text())
+               if((*it)->is_text() && (*it)->visible())
                {
+                       std::wstring str = (*it)->text_data().get(L"EngineDict.Editor.Text", L"");
+                       
+                       core::text::text_info text_info(std::move(get_text_info((*it)->text_data())));
+                       auto layer_producer = spl::make_shared<core::text_producer>(frame_factory, 0, 0, str, text_info, doc.width(), doc.height());
+                       
+                       core::text::string_metrics metrics = layer_producer->measure_string(str);
+                       
+                       auto& new_layer = root->create_layer(layer_producer, (*it)->rect().left - 2, (*it)->rect().top + metrics.bearingY, (*it)->name());      //the 2 offset is just a hack for now. don't know why our text is rendered 2 px to the right of that in photoshop
+                       new_layer.adjustments.opacity.set((*it)->opacity() / 255.0);
+                       new_layer.hidden.set(!(*it)->visible());
                }
-               else if((*it)->image())
+               else if((*it)->image() && (*it)->visible())
                {
                        core::pixel_format_desc pfd(core::pixel_format::bgra);
                        pfd.planes.push_back(core::pixel_format_desc::plane((*it)->rect().width(), (*it)->rect().height(), 4));
index 2b0fbfef7a4ac9e33d97be1c9f443b4557e04d5d..51c83bd0f7733bbafbe6081e3209064218a7b5ea 100644 (file)
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+      <WholeProgramOptimization>false</WholeProgramOptimization>
+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+      <OmitFramePointers>true</OmitFramePointers>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
index de5f5c0750b16de81412293935937dd46db2081c..de9f01008a0275c6a5b2eccfcb3c4e87057a206d 100644 (file)
@@ -436,10 +436,6 @@ bool MixerCommand::DoExecute()
                                transform.image_transform.fill_translation[1]   = y;
                                transform.image_transform.fill_scale[0]                 = x_s;
                                transform.image_transform.fill_scale[1]                 = y_s;
-                               transform.image_transform.clip_translation[0]   = x;
-                               transform.image_transform.clip_translation[1]   = y;
-                               transform.image_transform.clip_scale[0]                 = x_s;
-                               transform.image_transform.clip_scale[1]                 = y_s;
                                return transform;
                        }, duration, tween));
                }
index 75133274a25039966b5e1aa5dc6f652627d6231e..3d6926cd6777630efd2ca870d126f0564414d577 100644 (file)
@@ -34,6 +34,7 @@
 #include <core/producer/stage.h>
 #include <core/producer/frame_producer.h>
 #include <core/producer/scene/scene_producer.h>
+#include <core/producer/text/text_producer.h>
 #include <core/consumer/output.h>
 
 #include <modules/bluefish/bluefish.h>
@@ -104,6 +105,7 @@ struct server::impl : boost::noncopyable
                CASPAR_LOG(info) << L"Initialized psd module.";
 
                register_producer_factory(&core::scene::create_dummy_scene_producer);
+               register_producer_factory(&core::create_text_producer);
 
                setup_channels(env::properties());
                CASPAR_LOG(info) << L"Initialized channels.";
index 4c23ff52c9bf16a36dd7c3bef79a80abe9a31a98..44be3361b724d455ad6066eddce38b0ab401b28a 100644 (file)
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)tmp\$(Configuration)\</IntDir>\r
     <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\dependencies64\boost\;..\dependencies64\ffmpeg\include\;..\dependencies64\glew\include;..\dependencies64\sfml\include\;..\dependencies64\tbb\include\;$(IncludePath)</IncludePath>\r
     <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\dependencies64\boost\;..\dependencies64\ffmpeg\include\;..\dependencies64\glew\include;..\dependencies64\sfml\include\;..\dependencies64\tbb\include\;$(IncludePath)</IncludePath>\r
-    <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\dependencies64\boost\stage\lib;..\dependencies64\ffmpeg\lib\;..\dependencies64\glew\lib;..\dependencies64\sfml\lib\;..\dependencies64\tbb\lib\;..\dependencies64\freeimage\lib\;..\dependencies64\sfml\extlibs\lib\;..\dependencies64\openal\lib\;..\dependencies64\asmlib\;$(LibraryPath)</LibraryPath>\r
-    <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\dependencies64\boost\stage\lib;..\dependencies64\ffmpeg\lib\;..\dependencies64\glew\lib;..\dependencies64\sfml\lib\;..\dependencies64\tbb\lib\;..\dependencies64\freeimage\lib\;..\dependencies64\sfml\extlibs\lib\;..\dependencies64\openal\lib\;..\dependencies64\asmlib\;$(LibraryPath)</LibraryPath>\r
+    <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\dependencies64\boost\stage\lib;..\dependencies64\ffmpeg\lib\;..\dependencies64\glew\lib;..\dependencies64\sfml\extlibs\lib;..\dependencies64\sfml\lib\;..\dependencies64\tbb\lib\;..\dependencies64\freeimage\lib\;..\dependencies64\openal\lib\;..\dependencies64\asmlib\;$(LibraryPath)</LibraryPath>\r
+    <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\dependencies64\boost\stage\lib;..\dependencies64\ffmpeg\lib\;..\dependencies64\glew\lib;..\dependencies64\sfml\lib\;..\dependencies64\tbb\lib\;..\dependencies64\freeimage\lib\;..\dependencies64\openal\lib\;..\dependencies64\asmlib\;..\dependencies64\freetype\objs\win32\vc2010;$(LibraryPath)</LibraryPath>\r
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)bin\$(Configuration)\</OutDir>\r
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)bin\$(Configuration)\</OutDir>\r
     <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionName)</TargetName>\r
       <ForcedIncludeFiles>common/compiler/vs/disable_silly_warnings.h</ForcedIncludeFiles>\r
     </ClCompile>\r
     <Link>\r
-      <AdditionalDependencies>alibcof64.lib;sfml-system-d.lib;sfml-window-d.lib;sfml-graphics-d.lib;sfml-audio-d.lib;Winmm.lib;Ws2_32.lib;avformat.lib;avcodec.lib;avutil.lib;avfilter.lib;swscale.lib;swresample.lib;tbb.lib;OpenGL32.lib;FreeImaged.lib;glew32.lib;freetype248_D.lib;openal32.lib</AdditionalDependencies>\r
+      <AdditionalDependencies>alibcof64.lib;freetype248_d.lib;sfml-system-d.lib;sfml-window-d.lib;sfml-graphics-d.lib;sfml-audio-d.lib;Winmm.lib;Ws2_32.lib;avformat.lib;avcodec.lib;avutil.lib;avfilter.lib;swscale.lib;swresample.lib;tbb.lib;OpenGL32.lib;FreeImaged.lib;glew32.lib;openal32.lib</AdditionalDependencies>\r
       <Version>\r
       </Version>\r
       <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
@@ -207,7 +207,7 @@ copy "$(ProjectDir)casparcg.config" "$(OutDir)"</Command>
     </ClCompile>\r
     <Link>\r
       <OptimizeReferences>true</OptimizeReferences>\r
-      <AdditionalDependencies>alibcof64.lib;sfml-system.lib;sfml-window.lib;sfml-graphics.lib;Winmm.lib;Ws2_32.lib;avformat.lib;avcodec.lib;avutil.lib;avfilter.lib;swscale.lib;swresample.lib;tbb.lib;OpenGL32.lib;glew32.lib;freetype248.lib;openal32.lib;freeimage.lib</AdditionalDependencies>\r
+      <AdditionalDependencies>alibcof64.lib;freetype250.lib;sfml-system.lib;sfml-window.lib;sfml-graphics.lib;Winmm.lib;Ws2_32.lib;avformat.lib;avcodec.lib;avutil.lib;avfilter.lib;swscale.lib;swresample.lib;tbb.lib;OpenGL32.lib;glew32.lib;openal32.lib;freeimage.lib</AdditionalDependencies>\r
       <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
       <GenerateDebugInformation>true</GenerateDebugInformation>\r
       <ProgramDatabaseFile>$(TargetDir)$(TargetName).pdb</ProgramDatabaseFile>\r
index 8bbe94bdbbad84c5f6431e866016fa66efbeee37..c42b6eba4a95f157876e609db2bd2a81588eadd3 100644 (file)
 #include <iostream>
 
 #include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/json_parser.hpp>
+#include <boost/property_tree/detail/file_parser_error.hpp>
+#include <boost/property_tree/xml_parser.hpp>
 
 
 int _tmain(int argc, _TCHAR* argv[])
 {
        caspar::psd::psd_document doc;
-       doc.parse(L"C:\\Lokala Filer\\Utveckling\\CasparCG\\Server 2.1\\test\\data\\test1.psd");
-
-       int a = 42;
-
-       //std::wstringstream trace;
-
-       //trace << L"<doc filename='" << doc.filename() << L"' color_mode='" << caspar::psd::color_mode_to_string(doc.color_mode()) << L"' color_depth='" << doc.color_depth() << L"' channel_count='" << doc.channels_count() << L"' width='" << doc.width() << L"' height='" << doc.height() << L"'>" << std::endl;
-
-       //
-       //auto end = doc.layers().end();
-       //for(auto it = doc.layers().begin(); it != end; ++it)
-       //{
-       //      caspar::psd::layer_ptr layer = (*it);
-       //      trace << L"     <layer name='" << layer->name() << L"' opacity='" << layer->opacity() << L"'>" << std::endl;
-       //      if(layer->image())
-       //              trace << L"             <bounding-box left='" << layer->rect().left << "' top='" << layer->rect().top << "' right='" << layer->rect().right << "' bottom='" << layer->rect().bottom << "' />" << std::endl;
-       //      if(layer->mask())
-       //              trace << L"             <mask default-value='" << layer->default_mask_value() << "' left='" << layer->mask_rect().left << "' top='" << layer->mask_rect().top << "' right='" << layer->mask_rect().right << "' bottom='" << layer->mask_rect().bottom << "' />" << std::endl;
-       //      trace << L"     </layer>" << std::endl;
-       //}
-
-       //trace << L"</doc>" << std::endl;
-
-       //std::cout << caspar::u8(trace.str());
+       doc.parse(L"C:\\Lokala Filer\\Utveckling\\CasparCG\\Server 2.1\\shell\\media\\test1.psd");
+
+       std::wstringstream trace;
+
+       trace << L"<doc filename='" << doc.filename() << L"' color_mode='" << caspar::psd::color_mode_to_string(doc.color_mode()) << L"' color_depth='" << doc.color_depth() << L"' channel_count='" << doc.channels_count() << L"' width='" << doc.width() << L"' height='" << doc.height() << L"'>" << std::endl;
+       
+       auto end = doc.layers().end();
+       for(auto it = doc.layers().begin(); it != end; ++it)
+       {
+               caspar::psd::layer_ptr layer = (*it);
+               trace << L"     <layer name='" << layer->name() << L"' opacity='" << layer->opacity() << L"' flags='" << std::hex << layer->flags() << std::dec << "'>" << std::endl;
+               if(layer->image())
+                       trace << L"             <bounding-box left='" << layer->rect().left << "' top='" << layer->rect().top << "' right='" << layer->rect().right << "' bottom='" << layer->rect().bottom << "' />" << std::endl;
+               if(layer->mask())
+                       trace << L"             <mask default-value='" << layer->mask_info().default_value_ << "' flags='" <<  std::hex << (unsigned short) layer->mask_info().flags_ << std::dec << "' left='" << layer->mask_info().rect_.left << "' top='" << layer->mask_info().rect_.top << "' right='" << layer->mask_info().rect_.right << "' bottom='" << layer->mask_info().rect_.bottom << "' />" << std::endl;
+               if(layer->is_text())
+               {
+                       boost::property_tree::xml_writer_settings<wchar_t> w(' ', 3);
+                       boost::property_tree::write_xml(trace, (*it)->text_data(), w);
+               }
+               trace << L"     </layer>" << std::endl;
+       }
+
+       trace << L"</doc>" << std::endl;
+       
+       std::ofstream log("psd-log.txt");
+       log << caspar::u8(trace.str());
+       std::cout << caspar::u8(trace.str());
+       
        return 0;
 }
 
index ce8fabb3e017e98fd46e406b8cc2b81c3812390d..cb90ce27560cd5efe09347d70bca0de8da0a1d44 100644 (file)
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <LinkIncremental>true</LinkIncremental>
-    <LibraryPath>C:\Lokala Filer\Utveckling\CasparCG\Server 2.1\dependencies64\boost\stage\lib;$(LibraryPath)</LibraryPath>
-    <IncludePath>C:\Lokala Filer\Utveckling\CasparCG\Server 2.1\dependencies64\boost;$(IncludePath)</IncludePath>
+    <LibraryPath>..\..\dependencies64\boost\stage\lib;$(LibraryPath)</LibraryPath>
+    <IncludePath>..\..\dependencies64\boost;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <LinkIncremental>false</LinkIncremental>
+    <IncludePath>..\..\dependencies64\boost;$(IncludePath)</IncludePath>
+    <LibraryPath>..\..\dependencies64\boost\stage\lib;$(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSdkDir)lib\x64;</LibraryPath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <ClCompile>