无尽的夜空,唯有月光撒满窗前

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  14 Posts :: 0 Stories :: 2 Comments :: 0 Trackbacks

常用链接

留言簿

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

2012年3月5日 #

     摘要: 成员函数指针与高效C++委托 (delegate)翻译: adie日期: Jun,2011原文作者: Don Clugston原文地址: http://www.codeproject.com/KB/cpp/FastDelegate.aspx下载实例源代码 - 18.5 Kb下载开发包库文件 - 18.6 Kb概要很遗憾, C++ 标准中没能提供面向对象的函数指针. 面...  阅读全文
posted @ 2012-03-05 13:32 skyline 阅读(2666) | 评论 (1)编辑 收藏

2012年3月2日 #

Tech Talk

A Portable typeof Operator

By Bill Gibbons, Pixo, Inc.
Copyright 2000 © Bill Gibbons
All rights reserved.

The Problem

Sometimes it is useful to declare a variable with a type that is not known directly, but is known to be "the type of this expression". For example:

void f(LibClass *p)
{
typeof(p->val) val = val;
/* ... */
}

where "typeof(p->val)" yields a type that is used to declare the local "val". This is particularly useful in templates, where many of the types in use are not known ahead of time.

Some compilers implement a typeof keyword as an extension, but code that uses such an extension is not portable. This article describes a portable way to write a typeof operator.

Almost Enough

C++ has almost enough functionality to do typeof. Function templates can be used to extract a type from an expression and declare a typedef of that type:

template<class T> void f(T)
{
typedef T TheType;
/* . . . */
}
void g() { f(123); } // TheType is "int"

Here the typedef "TheType" in the instantiated function template "f<int>" has the same type as the expression "123". But, there is no way to export the type from the function, so by itself this is not useful for implementing typeof.

Similarly, overloading can be used to select a function that contains a typedef that matches the type:

but there is no way to extract the type.

void f(char) { typedef int TheType; }
void f(short)
( typedef short TheType; }

void g() { f('x'); } // TheType is "char"

Class templates can be used to map a value or type to another value or type:

template<class T> struct U;// no definition needed
template<> struct U<char>
{ typedef unsigned char type; };
template<> struct U<short>
{ typedef unsigned short type; };

void f()
{
U<char>::type a; //unsigned char
U<short>::type b; //unsigned short
}

But you cannot use a class template to extract a type from an expression, as you can with function templates or overloading. (If the expression is a name with external linkage it is possible to implement typeof with class templates, but this is not very useful.)

Function templates and overloaded functions can also map an expression of one type into an expression of another type, as in:

unsigned char U(char x) { return x; }
unsigned short U(short x)
{ return x; }

void f()
{
short s = 0;
s; // expression "s" has type "short"
U(s); // expression "U(s)" has type "unsigned short"
}

This is also not sufficient, although it turns out to be part of the solution.

We need some way to map the type of an expression to something that can be used as a template argument. The only construct in the language that can do this is sizeof. It happens that sizeof is sufficient.

The Solution

The trick is to map each type to a unique integer value using overloaded functions and sizeof. Then template specializations can map the integer value to the right type:

  • The expression is passed to an overloaded function.
  • The return type of the particular function selected is "pointer to array of char", with the array size being unique to the type.
  • The sizeof operator extracts the array size as a constant. The function is never actually called and so does not need a definition.
  • The constant is used to select a class template among a set of specializations; the selected class template contains a typedef with the right type.

Simple Example

The following example shows a simple typeof that handles expressions of type short, int and long.

template<int N> struct typeof_c; // No definition, only specializations
template<> struct typeof_c<1> { typedef short V; };
template<> struct typeof_c<2> { typedef int V; };
template<> struct typeof_c<3> { typedef long V; };

typedef char CharArrayOf1[1];
typedef char CharArrayOf2[2];
typedef char CharArrayOf3[3];

typedef CharArrayOf1 *PtrCharArrayOf1;
typedef CharArrayOf2 *PtrCharArrayOf2;
typedef CharArrayOf3 *PtrCharArrayOf3;

PtrCharArrayOf1 typeof_f(short); // No definitions needed
PtrCharArrayOf2 typeof_f(int);
PtrCharArrayOf3 typeof_f(long);

#define typeof(x) typeof_c<sizeof(*typeof_f(x))>::V

Consider what happens to "typeof(123L)":

  • The macro expands to "typeof_c<sizeof(*typeof_f(123L))>::V".
  • The call "typeof_f(123L)" selects the following declaration from the set of overloaded function declarations:

PtrCharArrayOf3 typeof_f(long);

  • The type of "typeof_f(123L)" is "PtrCharArrayOf3", or pointer to array of char length 3.
  • The type of "*typeof_f(123L)" is "an array of char length 3".
  • "sizeof(*typeof_f(123L))" is an integral constant expression with the value 3. Since the operand of sizeof is not evaluated there is no need to have a definition for typeof_f.
  • The template-id "typeof_c<sizeof(*typeof_f(123L))>" is effectively "typeof_c<3>" which selects the specialization

template<> struct typeof_c<3> { typedef long V; };

  • The qualified-id "typeof_c < sizeof(*typeof_f(123L)) >::V" is the above typedef which has type long.
  • So "typeof(123L)" refers to a typedef of type long.

Note that all of these operations happen at compile time. The generated code will be the same as if the type were written as "long" instead of "typeof(123L)".

Improvements

The typedefs in the preceding example are not really necessary and they pollute the global namespace. We can eliminate them at the risk of confusing human readers (and maybe a few compilers):

char(*typeof_f(short))[1]; // fct returns ptr to array of char len 1
char(*typeof_f(int ))[2]; // length 2
char(*typeof_f(long ))[3]; // length 3

If we declare the parameters as references to const instead of using simple pass by value, it becomes possible to use expressions which cannot be passed by value - for example, objects of classes with private copy constructors. So in the general case, given type T, we want to write the typeof_f declaration for T as:

char(*typeof_f(const T&))[nnn];

Declaring the required specializations and functions can be handled much more easily with a macro:

#define REGISTER_TYPEOF(N,T) \
template<> struct typeof_c<N> { typedef T V; }; \
char(*typeof_f(const T&))[N];

However, we run into trouble with some compound types. For example, if we expand:

REGISTER_TYPEOF( 3, void (*)() )

we get:

template<> struct typeof_c<3> { typedef void (*)() V; };
char(*typeof_f(const void(*)()&))[3];

Both of these declarations are ill-formed because combining C++ types is not as simple as substituting a type for a type name. We can make the macro work again by introducing another class template:

template<class T> struct WrapType { typedef T U; };

This template takes advantage of the fact that when you instantiate a template with a compound type, e.g.

WrapType<void (*)()>

you create a simple name (the template parameter, in this case, T) for the type. We can't get to T directly from outside the template but we can get to typedef U that has the same type. In example:

WrapType<void (*)()> :: U

has type "void (*)()". So if we replace instances of T in the macro with "WrapType<T>::U" we have the original type but in a form that we can use to build other types.

Our macro now looks like this:

#define REGISTER_TYPEOF(N,T) \
template<> struct typeof_c<N> { typedef WrapType<T>::U V; }; \
char (*typeof_f(const WrapType<T>::U &))[N];

See the program listing at the end for a more complete example using the above macro and several test types.

Limitations

This approach does require that each type that might be used in typeof be explicitly registered with the
REGISTER_TYPEOF macro. This limits, or at least places additional burden, on the use of this technique in general-purpose template libraries.

#define REGISTER_TYPEOF(T) \
template<> struct typeof_c<__LINE__> \
{ typedef WrapType<T>::U V; }; \
char (*typeof_f(const WrapType<T>::U &))[__LINE__];

The need to assign a distinct ordinal to each type could be a nuisance. If all the REGISTER_TYPEOF uses are in a single include file the macro could be simplified by using __LINE__ instead of N:

It does not matter that the ordinals may be large and/or discontiguous; the only restriction is that they be positive and distinct.

If the type of the expression given to typeof has not been registered, the resulting error message may be cryptic; but it should at least refer to typeof_f that should give a clue to the problem.

Conclusion

For applications that need a typeof operator this technique provides most of the power of a compiler extension while keeping the code portable. This general approach of using function overloading and sizeof to extract expression type information can be used in other places.

The implementation of this technique can be somewhat obscure but the uses (such as reference to typeof) can be kept simple. Since all of these operations occur at compile time there is no runtime cost for using them.

A complete source code example can be found on page 4 of the printed version of the newsletter.

Editorial

By Reg. Charney

Bigger and Better

As you have probably noticed, things have changed again!. Based on the possibility of new sponsor, we have expanded things to increase this newsletter by 50% and to add color, at least to the first and last page. We have also been able to expand the length and content of our technical offerings.

We are also planning to include several new sections. They include a book review section, and a technical summary section. The technical summary will try to summarize technical topics on a number of the C, C++ and Java reflectors that exist on the net. Let us know what more you would like.

Not all rosy

As this issue is about to go to press, one of our new potential sponsors has backed out - or more accurately, failed to pay the invoice, answer emails, or respond to phone messages. It is a disappointment, as you can imagine. It is also too late to change the content or layout of this issue. However, with your assistance, we can grow stronger from the experience.

If you know firms that are committed to open source development or in the betterment of the professional programming community and the people they hire, please let them know about the ACCU and in this newsletter. Also, please tell me and I will contact them. We need sponsors and also advertisers. The benefits package that we are offering sponsors is quite impressive.

Electronic Newsletter

We can now send you future issues of this newsletter as PDF files. To subscribe, please email me at

accent-subscribe_AT_CharneyDay.com

Past issues are also available as PDF files, including versions in A4 format for our international readers. In the body of the message say if you want the A4 format and/or past issues.

Trends

By Reg. Charney

Languages

Again, Java leads the pack in normalized demand. However, this month HTML, Perl and XML all are in greater demand than C/C++. In fact, the rate of demand for the languages has changed dramatically. The change in demand for XML outstrips all other languages with Perl, the glue for Internet applications, an unexpected second. Perl's importance can be seen as a growth in tools for infrastructure implementation. Note also that one of the few increasing changes in demand is in Python, another glue language.

Figure #1

Figure #2

Platforms

In terms of demand, you already know most of the big players - Windows and Unix. The surprise occurs in the changing demand for platform-specific skills. The big winner here is Linux followed closely by Windows 2000. This says that there is a pent up demand for Linux skills that is outstripping all other platforms. Only Windows 2000 comes close, but that is to be expected, based on the huge installed base of Windows software already in the market and which firms need to upgrade.

Figure #3

Figure #4

The second clear fact is that Solaris dominates the Unix marketplace and demand for expertise in it continues to grow, but at half the speed of Windows 2000 and Linux.

How We Calculate

The source for these charts come from Internet online job sites. Thus, these numbers represent demand for new hires, not who are currently employed doing what. However, some estimates can be made from these figures, but that is a subject of another article.

These online sites are searched by keywords and the number of "hits" are recorded. Often, defining a skill is fuzzy. For example, the category "Windows 98" is actually the Boolean expression "Windows98 or Win98 or 98". Thus, an ad asking for experience with "W98" would be missed. Since getting some measurements is better than nothing, we compute raw demand for a skill. I often skip this chart because it is not very interesting-just a series of numbers without much context.

The first interesting chart is the Normalized Demand set of charts. This is the demand for a particular skill divided by the demand for all skills in that category. The second chart of interest is the change in demand for a skill since the last time we did a measurement of that skill. You can think of these charts as Skill Velocity Charts - how fast is the demand for the skill changing. The last chart is the Skill Acceleration chart that represents the change in changing demand over the last period we are measuring. It measures how fast demand is changing for each skill set within a category.

posted @ 2012-03-02 10:26 skyline 阅读(411) | 评论 (0)编辑 收藏

2012年2月4日 #

http://cavestory.org/downloads_editors.php

http://nxengine.sourceforge.net/

http://clb.demon.fi/projects/even-more-rectangle-bin-packing

posted @ 2012-02-04 11:15 skyline 阅读(238) | 评论 (0)编辑 收藏

2012年2月1日 #

使用 cURL 和 libcurl 通过 Internet 进行对话

将 libcurl 与 C 以及 Python 结合使用

Tim M. Jones, 顾问工程师,  

简介: cURL 是一个命令行工具,可以对文件传输使用许多协议,包括 HTTP、FTP、Secure Copy (SCP)、Telnet 等等。但是,除了可以用命令行通过 Internet 与端点对话外,还可以使用 libcurl 编写简单或复杂的程序,以自动化执行应用层的协议任务。本文将介绍 cURL 命令行工具,然后向您展示如何使用 libcurl 以及 C 和 Python 构建一个 HTTP 客户端。

本文的标签: java, web

发布日期: 2009 年 10 月 29 日
级别: 初级 其他语言版本: 英文
访问情况 : 5708 次浏览
评论: 0 (查看 | 添加评论 - 登录)

平均分 3 星 共 2 个评分 平均分 (2个评分)
为本文评分

开发 HTTP 和 FTP 之类依赖于应用层协议的应用程序并不复杂,但也不简单。进一步讲,这不是应用程序的重点,因为大部分情况下,协议之上的内容才是真正重要的内容。因此,libcurl 引起了许多人的兴趣,因为它的重点是应用程序而不是开发的各个方面。注意,很少有应用程序开发自己的 TCP/IP 堆栈,所以老话重提:尽可能重用以最小化开发安排并提高应用程序的可靠性。

本文首先简单介绍应用层协议,然后介绍 cURL、libcurl 并解释它们的用法。

Web 协议

如今构建应用程序已与过去大不相同。现在的应用程序需要能够通过网络或 Internet 进行通讯(提供人类可用的网络 API 或接口),还要能支持用户脚本化以提高灵活性。现代应用程序通常使用 HTTP 公开 Web 接口,并通过 Simple Mail Transport Protocol (SMTP) 提供警告通知。这些协议允许您将 Web 浏览器指向设备以获得配置或状态信息,并从设备或常用的电子邮件客户端接收标准电子邮件(分别通过 HTTP 和 SMTP)。

这些 Web 服务通常构建在网络堆栈的套接字层上(见图 1)。套接字层实现一个最先出现在 Berkeley Software Distribution (BSD) 操作系统上的 API,并提取底层传输和网络层协议的详细信息。


图 1. 网络堆栈和 libcurl
图 1. 网络堆栈和 libcurl

Web 服务发生在客户端和服务器之间的协议对话中。在 HTTP 上下文中,服务器是终端设备,客户端是位于端点上的浏览器。对于 SMTP,服务器是邮件网关或端点用户,客户端是终端设备。在某些情况下,协议对话发生在两个步骤(请求和响应)中,但另一些情况下,需要协商和通讯的通信量更多。这种协商可能增加了大量复杂性,这可以通过 API 进行抽象,比如 libcurl。

cURL 简介

cURL 的起源与发展

cURL 是 Daniel Stenberg 发明的,但是 600 多名开发人员也做出了巨大的贡献。它无疑是许多应用程序都使用的有用技术之一。

cURL 最初的设计初衷是使用不同的协议(比如 FTP、HTTP、SCP 等)在端点之间移动文件。它最初是一个命令行实用工具,但现在也是一个绑定了 30 多种语言的库。因此,现在不仅可以通过 shell 使用 cURL,您还可以构建合并了这个重要功能的应用程序。libcurl 库也是可以移植的,支持 Linux®、IBM®AIX®操作系统、BSD、Solaris 以及许多其他 UNIX®变体。

获取和安装 cURL/libcurl

获取和安装 libcurl 非常简单,取决于您所运行的 Linux 发行版。如果运行的是 Ubuntu,您可以使用 apt-get轻松安装这些包。以下行演示了如何为 libcurl 安装 libcurl 和 Python 绑定:

 $ sudo apt-get install libcurl3
 $ sudo apt-get install python-pycurl
                        

apt-get实用工具确保该过程满足所有的依赖关系。

在命令行中使用 cURL

cURL 最开始是一个命令行工具,可以使用 Uniform Resource Locator (URL) 语法执行数据传输。考虑到它在命令行上的流行度,后来创建了一个可以在应用程序中生成这些行为的库。如今,命令行 cURL 是 cURL 库的包装器。本文首先研究 cURL 作为命令行的功能,然后深入探讨如何将它作为库使用。

cURL 的两种常见用法是使用 HTTP 和 FTP 协议进行文件传输。cURL 为这些协议提供一个简单的接口。要使用 HTTP 从网站获取文件,只需告诉 cURL 您要将网页写入到其中的本地文件的文件名、网站的 URL 以及要获取的文件。让我们看一下清单 1 中的简单命令行示例。


清单 1. 使用 cURL 从网站获取文件的示例
                          
 $ curl -o test html www.exampledomain.com
  % Total    % Received % Xferd  Average Speed    Time    Time     Time    Current 
                                 Dload  Upload    Total   Spent    Left    Speed 
 100 43320  100 43320    0     0  55831       0 --:--:-- --:--:-- --:--:--  89299 
 $ 

注意,由于我指定了域而不是文件,我将获得根文件(index.html)。要使用 cURL 将该文件移动到 FTP 站点,可以使用 -T选项指定要上传的文件,然后提供 FTP 站点的 URL 以及文件的路径。


清单 2. 使用 cURL 将文件上传到 FTP 站点的示例
                          
 $ curl -T test.html ftp://user:password@ftp.exampledomain.com/ftpdir/
  % Total    % Received % Xferd  Average Speed    Time    Time     Time    Current 
                                 Dload  Upload    Total   Spent    Left    Speed 
 100 43320    0     0  100 43320      0  38946   0:00:01 0:00:01  --:--:--    124k 
 $ 

是不是很简单?学习了一些模式之后您会发现,cURL 使用起来非常简单。但是您可以使用的选项非常多 -在 cURL 命令行中请求帮助(使用 --help)可以得到 129 行选项。如果您觉得这还不算太多,那么还有一大批其他控制选项(从详细度到安全性),以及特定于协议的配置项。

从开发人员的角度看,这还不算是 cURL 最令人兴奋的地方。让我们深入了解 cURL 库,学习如何向应用程序添加文件传输协议。

作为库的 cURL

如果您有 10 年以上的脚本语言经验,您就会注意到它们的标记有很大的变化。Python、Ruby、Perl 等这些脚本语言不仅包含套接字层(C 或 C++ 中也有),还包含了应用层协议 API。这些脚本语言合并了高级功能,可以创建 HTTP 服务器或客户端。libcurl 库为 C 和 C++ 之类的语言添加了类似的功能,但是它可以在不同的语言之间移植。在所有它支持的语言中都能找到与 libcurl 相当的行为,但是由于这些语言的差异很大(设想一下 C 和 Scheme),提供这些行为的方式也很不相同。

libcurl 库以 API 的形式封装清单 1和清单 2中描述的行为,因此它可以被高级语言使用(如今已超过 30 种)。本文提供了 libcurl 的两个示例。第一个示例研究使用 c 构建的简单 HTTP 客户端(适合构建 Web 爬行器),第二个示例是一个使用 Python 创建的简单 HTTP 客户端。

基于 C 的 HTTP 客户端

C API 在 libcurl 功能上提供了两个 API。easy 接口是一个简单的同步 API(意味着当您使用请求调用 libcurl 时,将能够满足您的请求,直到完成或发生错误)。多接口可以进一步控制 libcurl,您的应用程序可以执行多个同步传输,并控制 libcurl 何时何地移动数据。

该示例使用 easy 接口。该 API 还能控制数据移动过程(使用回调),但正如其名称所示,使用起来非常简单。清单 3 提供了 HTTP 的 C 语言示例。


清单 3. 使用 libcurl easy 接口的 C HTTP 客户端
                          
 #include <stdio.h> 
 #include <string.h> 
 #include <curl/curl.h> 

 #define MAX_BUF         65536 

 char wr_buf[MAX_BUF+1]; 
 int  wr_index; 

 /* 
 * Write data callback function (called within the context of 
 * curl_easy_perform. 
 */ 
 size_t write_data( void *buffer, size_t size, size_t nmemb, void *userp ) 
 { 
  int segsize = size * nmemb; 

  /* Check to see if this data exceeds the size of our buffer. If so, 
   * set the user-defined context value and return 0 to indicate a 
   * problem to curl. 
   */ 
  if ( wr_index + segsize > MAX_BUF ) { 
    *(int *)userp = 1; 
    return 0; 
  } 

  /* Copy the data from the curl buffer into our buffer */ 
  memcpy( (void *)&wr_buf[wr_index], buffer, (size_t)segsize ); 

  /* Update the write index */ 
  wr_index += segsize; 

  /* Null terminate the buffer */ 
  wr_buf[wr_index] = 0; 

  /* Return the number of bytes received, indicating to curl that all is okay */ 
  return segsize; 
 } 


 /* 
 * Simple curl application to read the index.html file from a Web site. 
 */ 
 int main( void ) 
 { 
  CURL *curl; 
  CURLcode ret; 
  int  wr_error; 

  wr_error = 0; 
  wr_index = 0; 

  /* First step, init curl */ 
  curl = curl_easy_init(); 
  if (!curl) { 
    printf("couldn't init curl\n"); 
    return 0; 
  } 

  /* Tell curl the URL of the file we're going to retrieve */ 
  curl_easy_setopt( curl, CURLOPT_URL, "www.exampledomain.com" ); 

  /* Tell curl that we'll receive data to the function write_data, and 
   * also provide it with a context pointer for our error return. 
   */ 
  curl_easy_setopt( curl, CURLOPT_WRITEDATA, (void *)&wr_error ); 
  curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_data ); 

  /* Allow curl to perform the action */ 
  ret = curl_easy_perform( curl ); 

  printf( "ret = %d (write_error = %d)\n", ret, wr_error ); 

  /* Emit the page if curl indicates that no errors occurred */ 
  if ( ret == 0 ) printf( "%s\n", wr_buf ); 

  curl_easy_cleanup( curl ); 

  return 0; 
 } 

最上方是必需的 include文件,包括 cURL 根文件。接下来,我定义了两个用于传输的变量。第一个变量是 wr_buf,表示将在其中写入传入数据的缓冲区。wr_index表示缓冲区的当前写入索引。

转到 main函数,该函数使用 easy API 进行设置。所有 cURL 调用都通过维护特定请求状态的句柄进行操作。这称为 CURL指针引用。本例还创建一个特殊的返回码,称为 CURLcode。在使用任何 libcurl 函数之前,您需要调用 curl_easy_init获取 CURL句柄。接下来,注意 curl_easy_setopt调用的数量。它们为特定的操作配置句柄。对于这些调用,您提供句柄、命令和选项。首先,本例使用 CURLOPT_URL指定要获取的 URL。然后,它使用 CURL_WRITEDATA提供一个上下文变量(在本例中,它是内部的 write 错误变量)。最后,它使用 CURLOPT_WRITEFUNCTION指定数据可用时应该调用的函数。在启动 API 之后,API 将使用它读取的数据多次调用该函数。

要开始传输,调用 curl_easy_perform。它的工作是根据之前的配置执行传输。调用该函数时,在完成传输或发生错误之前该函数不会返回。main的最后一步是提交返回状态,提交页面读取,最后使用 curl_easy_cleanup清除(当使用句柄执行完操作后)。

现在看看 write_data函数。该函数是针对特定操作收到数据时调用的回调。注意,当您从网站读取数据时,将写入该数据(write_data)。将向回调提供一个缓冲区(包含可用数据)、成员数量和大小(缓冲中可用数据总量)、上下文指针。第一个任务是确保缓冲区(wr_buf)的空间足以写入数据。如果不够,它将设置上下文指针并返回 0,表示出现问题。否则,它将 cURL 缓冲区的数据复制到您的缓冲区,并增加索引,指向要写入的下一个位置。本例还终止字符串,稍后可以对其使用 printf。最后,它返回 libcurl 操作的字节数量。这将告诉 libcurl 数据被提取,它也可以丢弃该数据。这就是从网站将文件读取到内存的相对简单的方法。

基于 Python 的 HTTP 客户端

本节提供的示例类似于基于 C 的 HTTP 客户端,不过它使用的是 Python。Python 是一种非常有用的面向对象的脚本语言,在原型化和构建生产软件方面非常突出。示例假设您较熟悉 Python,但使用不多,因此不要期望过高。

这个简单的 Python HTTP 客户端使用 pycurl,如清单 4 所示。


清单 4. 使用 libcurl 的 pycurl接口的 Python HTTP 客户端
                          
 import sys 
 import pycurl 

 wr_buf = ''

 def write_data( buf ): 
         global wr_buf 
         wr_buf += buf 

 def main(): 
         c = pycurl.Curl() 
         c.setopt( pycurl.URL, 'http://www.exampledomain.com' ) 
         c.setopt( pycurl.WRITEFUNCTION, write_data ) 

         c.perform() 

         c.close() 

 main() 
 sys.stdout.write(wr_buf) 

使用 Python 进行原型化

原型化是 Python 的优势之一。它只需很少的代码就可以实现大量功能。使用 C 也许能获得更好的性能,但是如果您的目的是快速编码以证明某个概念,那么高级脚本语言是无可替代的,比如 Python。

这比 C 语言版本简单的多。它首先导入必需的模块(用于标准系统的 syspycurl模块)。接下来,它定义 write 缓冲区(wr_buf)。像 C 程序中一样,我声明一个 write_data函数。注意,该函数只有一个参数:从 HTTP 服务器中读取的数据缓冲区。我将该缓冲区连接到全局 write 缓冲区。main函数首先创建一个 Curl句柄,然后使用 setopt方法为传输定义 URLWRITEFUNCTION。它调用 perform方法启动传输并关闭句柄。最后,它调用 main函数,并将 write 缓冲区提交到 stdout。注意,在这种情况下,您不需要错误上下文指针,因为您使用了 Python 字符串连接,这就是说您不会使用大小固定的字符串。

结束语

本文仅仅简单介绍了 libcurl,介绍了它支持的多种协议和语言。希望这能够展示它如何轻松构建使用应用层协议(如 HTTP)的应用程序。libcurl 网站(见 参考资料)提供了很多示例和有用的文档。下一次开发 Web 浏览器、爬行器或其他有应用层协议要求的应用程序时,试试 libcurl。它一定能大大减少您的开发时间,并找回编码的乐趣。


参考资料

学习

  • cURL是一个命令行工具和库,实现了各种客户端协议。它支持 12 种以上的协议,包括 FTP、HTTP、Telnet 以及其他安全变体。许多平台上都能找到 cURL,包括 Linux、AIX、BSD 和 Solaris,它支持 30 多种语言。

  • PycURL是 libcurl API 之上的一个薄层,PycURL 速度非常快。使用 PycURL,您可以使用 libcurl 库开发 Python 应用程序。

  • 说到应用程序灵活性,您可以在 "用 Guile 编写脚本" 中了解更多有关将脚本功能集成到应用程序的内容。

  • 要收听有关软件开发人员的有趣采访和讨论,请查看 developerWorks 网络广播

  • 了解最新的 developerWorks 技术活动网络广播

  • 在 Twitter 上跟随 developerWorks

  • 查阅最近将在全球举办的面向 IBM 开放源码开发人员的研讨会、交易展览、网络广播和其他 活动

  • 访问 developerWorks 开源专区获得丰富的 how-to 信息、工具和项目更新,帮助您用开放源码技术进行开发,并与 IBM 产品结合使用。

  • 查看免费的 developerWorks On demand 演示,观看并了解 IBM 及开源技术和产品功能。

获得产品和技术

讨论

关于作者

M. Tim Jones

M. Tim Jones 是一名嵌入式软件工程师,他是 Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming(现在已经是第 2 版)、AI Application Programming(第 2 版)和 BSD Sockets Programming from a Multilanguage Perspective等书的作者。他的工程背景非常广泛,从同步宇宙飞船的内核开发到嵌入式系统架构设计,再到网络协议的开发。Tim 是位于科罗拉多州 Longmont 的 Emulex Corp. 的一名顾问工程师。

posted @ 2012-02-01 12:50 skyline 阅读(490) | 评论 (0)编辑 收藏

2012年1月13日 #

http://www.codeproject.com/KB/cpp/lambdastorage-nostdlib.aspx

C++11 Lambda Storage Without libc++

In the case that you need to store and pass lambdas around but can't use std::function, here's an alternative.
Sponsored Links

Introduction

This code project demonstrates how to write a lambda storage class that functions similarly to std::function, only for lambda functions. That is, you specify the return type and argment types of the function, and the class will store any lambda that matches, including those that capture variables. For those of you who doubt the usefulness of such a utility, what if your significant other tells you to stop using libc++ and there's no helping it? This is exactly for those sort of situations.

It also demonstrates that std::function can be implemented without relying on compiler hooks and whatnot.

Background

A number of C++11 (I think) features are required to do this. To get the simple function signature (return type and parameter types), the utility uses a unique method of variadic template specialization. The utility stores the lambda in a void pointer, and it uses a number of templatized lambda functions to retain lambda type information where necessary. I use nullptr to be especially prissy.

When we're done, if you really want to get crazy, you can even use move constructors, temporary value references, and other optimizations that are, quite frankly, completely beyond the scope of this article (i.e. my ability).

Simple Function Signature Templates

Like with std::function, it is possible to pass a function return type and arguments as template parameters. I found this technique referenced by a stack overflow post (here, which references the standard:http://stackoverflow.com/a/3535871 ). Basically, there are two steps that both seem to be necessary.

First, create a templatized class with one parameter:

template<typename T> class Lambda {}; 

Second, specialize the template using the simple function signature syntax:

template<typename Out, typename... In> class Lambda<Out(In...)> {};

Now, if you use Lambda like this:

Lambda<int(bool a, int *b)> 

"Out" will be "bool" and "In" will be "int *".

Storing and Managing Lambda Function Pointers

The utility cannot hold the lambda function in a function pointer because this would prevent it from storing lambdas with captured variables. The utility also cannot use auto, since even lambdas with exactly identical specifications are separate classes and are therefore not assignable. Therefore, the utility stores the lambda as a void pointer. Because the source lambda may go out of scope before the utility class is destroyed, the utility class cannot store a pointer to the original lambda but must duplicate and store its own pointer.

void *lambda;

template<typename LambdaType> Lambda<Out(In...)> &operator =(LambdaType const &lambda)
{
  this->lambda = new LambdaType(lambda);
  return *this;
}

(We know the copy constructor for the lambda expression exists because "auto a = [](){}; auto b = a;" is valid. QED And Baxter 11 Jan 2012)

With this alone, the utility loses all of the type information and is unable to delete or call the lambda function any more. To get around this, it can use template-generated lambda functions to do the type-specific operations:

void *lambda;
Out (*executeLambda)(void *, In...);
void (*deleteLambda)(void *);

template<typename LambdaType> Lambda<Out(In...)> &operator =(LambdaType const &lambda)
{
  if (this->lambda != nullptr) deleteLambda(this->lambda);
  this->lambda = new LambdaType(lambda);

  executeLambda = [](void *lambda, In... arguments) -> Out
  {
    return ((LambdaType *)lambda)->operator()(arguments...);
  };

  deleteLambda = [](void *lambda)
  {
    delete (LambdaType *)lambda;
  };

  return *this;
}

Out operator()(In ... in)
{
  assert(lambda != nullptr);
  return executeLambda(lambda, in...);
}

Note that the utility can use normal function pointers to store the conversion lambdas since they are non-capturing. Now, if we just add convenience constructors, copy constructors, a destructor, and any other finishing touches we'll be done.

Completed Code

Before showing the final utility, I just want to mention that the operator() above will break if the return type of the stored lambda is void. To get around this, I separated the execution code into a separate class with different specializations for void and non-void return types.

#include <cassert>

// LambdaExecutor is an internal class that adds the ability to execute to
// Lambdas.  This functionality is separated because it is the only thing
// that needed to be specialized (by return type).

// generateExecutor or receiveExecutor must be called after constructing,
// before use
template<typename T> class LambdaExecutor {};

template <typename Out, typename... In> class LambdaExecutor<Out(In...)> {
  public:
    Out operator()(In ... in)
    {
      assert(lambda != nullptr);
      return executeLambda(lambda, in...);
    }

  protected:
    LambdaExecutor(void *&lambda) : lambda(lambda) {}

    ~LambdaExecutor() {}

    template <typename T> void generateExecutor(T const &lambda)
    {
      executeLambda = [](void *lambda, In... arguments) -> Out
      {
        return ((T *)lambda)->operator()(arguments...);
      };
    }

    void receiveExecutor(LambdaExecutor<Out(In...)> const &other)
    {
      executeLambda = other.executeLambda;
    }

  private:
    void *&lambda;
    Out (*executeLambda)(void *, In...);
};

template <typename... In> class LambdaExecutor<void(In...)> {
  public:
    void operator()(In ... in)
    {
      assert(lambda != nullptr);
      executeLambda(lambda, in...);
    }

  protected:
    LambdaExecutor(void *&lambda) : lambda(lambda) {}

    ~LambdaExecutor() {}

    template <typename T> void generateExecutor(T const &lambda)
    {
      executeLambda = [](void *lambda, In... arguments)
      {
        return ((T *)lambda)->operator()(arguments...);
      };
    }

    void receiveExecutor(LambdaExecutor<void(In...)> const &other)
    {
      executeLambda = other.executeLambda;
    }

  private:
    void *&lambda;
    void (*executeLambda)(void *, In...);
};

// Lambda contains most of the lambda management code and can be used
// directly in external code.
template <typename T> class Lambda {};

template <typename Out, typename ...In> class Lambda<Out(In...)> : 
    public LambdaExecutor<Out(In...)> {
  public:
    Lambda() : LambdaExecutor<Out(In...)>(lambda),
        lambda(nullptr), deleteLambda(nullptr), copyLambda(nullptr)
    {
    }

    Lambda(Lambda<Out(In...)> const &other) : LambdaExecutor<Out(In...)>(lambda),
        lambda(other.copyLambda ? other.copyLambda(other.lambda) : nullptr),
        deleteLambda(other.deleteLambda), copyLambda(other.copyLambda)
    {
      receiveExecutor(other);
    }

    template<typename T>
    Lambda(T const &lambda) : LambdaExecutor<Out(In...)>(this->lambda), lambda(nullptr)
    {
      // Copy should set all variables
      copy(lambda);
    }

    ~Lambda()
    {
      if (deleteLambda != nullptr) deleteLambda(lambda);
    }

    Lambda<Out(In...)> &operator =(Lambda<Out(In...)> const &other)
    {
      this->lambda = other.copyLambda ? other.copyLambda(other.lambda) : nullptr;
      receiveExecutor(other);
      this->deleteLambda = other.deleteLambda;
      this->copyLambda = other.copyLambda;
      return *this;
    }

    template<typename T> Lambda<Out(In...)> &operator =(T const &lambda)
    {
      copy(lambda);
      return *this;
    }

    operator bool()
    {
      return lambda != nullptr;
    }

  private:
    template<typename T>
    void copy(T const &lambda)
    {
      if (this->lambda != nullptr) deleteLambda(this->lambda);
      this->lambda = new T(lambda);

      generateExecutor(lambda);

      deleteLambda = [](void *lambda)
      {
        delete (T *)lambda;
      };

      copyLambda = [](void *lambda) -> void *
      {
        return lambda ? new T(*(T *)lambda) : nullptr;
      };
    }

    void *lambda;
    void (*deleteLambda)(void *);
    void *(*copyLambda)(void *);
};

And Bob's your uncle. Peace out, homeboys!

Usage

Lambda<int(int)> storage = [](int a) { return a + 1; };
int z = 18000000;
storage = [z](int a) { return a + 1 + z; };
int y = storage(4); 
posted @ 2012-01-13 20:06 skyline 阅读(390) | 评论 (0)编辑 收藏

http://www.lonesock.net/soil.html

posted @ 2012-01-13 19:59 skyline 阅读(347) | 评论 (0)编辑 收藏

2012年1月12日 #

http://www.diybl.com/course/3_program/c/c_js/20100710/426527.html

搞了几个跨Linux与Windows的项目,碰到很多问题,记下来,以供查考。另外,因为水平的原因,肯定错误在所难免,请读者一定指正。

  如无其它说明,本文所指Linux均表示2.6内核Linux,GCC编译器,Windows均表示Windows XP系统,Visual Studio 2005 sp1编译环境。

  下面大概分几个方面进行罗列:

socket

  Linux要包含

#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
等头文件,而windows下则是包含 #include <winsock.h>

  Linux中socket为整形,Windows中为一个SOCKET。

  Linux中关闭socket为close,Windows中为closesocket。

  Linux中有变量socklen_t,Windows中直接为int。

  因为linux中的socket与普通的fd一样,所以可以在TCP的socket中,发送与接收数据时,直接使用read和write。而windows只能使用recv和send。

  设置socet选项,比如设置socket为非阻塞的。Linux下为

flag = fcntl (fd, F_GETFL);
fcntl (fd, F_SETFL, flag | O_NONBLOCK);
,Windows下为 flag = 1;
ioctlsocket (fd, FIONBIO, (unsigned long *) &flag);

  当非阻塞socket的TCP连接正在进行时,Linux的错误号为EINPROGRESS,Windows的错误号为WSAEWOULDBLOCK。

file

  Linux下面,文件换行是"\n",而windows下面是"\r\n"。

  Linux下面,目录分隔符是"/",而windows下面是"\"。

  Linux与Windows下面,均可以使用stat调用来查询文件信息。但是,Linux只支持2G大小,而Windows只支持4G大小。为了支持更大的文件查询,可以在Linux环境下加_FILE_OFFSET_BITS=64定义,在Windows下面使用_stat64调用,入参为 struct __stat64。

  Linux中可根据stat的st_mode判断文件类型,有S_ISREG、S_ISDIR等宏。Windows中没有,需要自己定义相应的宏,如

#define S_ISREG(m) (((m) & 0170000) == (0100000))
#define S_ISDIR(m) (((m) & 0170000) == (0040000))

  Linux中删除文件是unlink,Windows中为DeleteFile。

time

  Linux中,time_t结构是32位的无符号整形。而windows中,time_t结构是64位的整形。如果要在windows始time_t为32位无符号整形,可以加宏定义,_USE_32BIT_TIME_T。

  Linux中,sleep的单位为秒。Windows中,Sleep的单位为毫秒。即,Linux下sleep (1),在Windows环境下则需要Sleep (1000)。

  Windows中的timecmp宏,不支持大于等于或者小于等于。

  Windows中没有struct timeval结构的加减宏可以使用,需要手动定义:

#define MICROSECONDS (1000 * 1000)

#define timeradd(t1, t2, t3) do { \
(t3)->tv_sec = (t1)->tv_sec + (t2)->tv_sec; \
(t3)->tv_usec = (t1)->tv_usec + (t2)->tv_usec % MICROSECONDS; \
if ((t1)->tv_usec + (t2)->tv_usec > MICROSECONDS) (t3)->tv_sec ++; \
} while (0)

#define timersub(t1, t2, t3) do { \
(t3)->tv_sec = (t1)->tv_sec - (t2)->tv_sec; \
(t3)->tv_usec = (t1)->tv_usec - (t2)->tv_usec; \
if ((t1)->tv_usec - (t2)->tv_usec < 0) (t3)->tv_usec --, (t3)->tv_usec += MICROSECONDS; \
} while (0)

process

  Linux下可以直接使用system来调用外部程序。Windows最好使用WinExec,因为WinExec可以支持是打开还是隐藏程序窗口。用WinExec的第二个入参指明,如SW_SHOW/SW_HIDE。

杂项

  Linux为srandom和random函数,Windows为srand和rand函数。

  Linux为snprintf,Windows为_snprintf。

  同理,Linux中的strcasecmp,Windows为_stricmp。

错误处理

  Linux下面,通常使用全局变量errno来表示函数执行的错误号。Windows下要使用GetLastError ()调用来取得。

Linux环境下仅有的

  这些函数或者宏,Windows中完全没有,需要用户手动实现。

  atoll

long long
atoll (const char *p)
{
int minus = 0;
long long value = 0;
if (*p == '-')
{
minus ++;
p ++;
}
while (*p >= '0' && *p <= '9')
{
value *= 10;
value += *p - '0';
p ++;
}
return minus ? 0 - value : value;
}

gettimeofday

#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
#define EPOCHFILETIME 11644473600000000Ui64
#else
#define EPOCHFILETIME 11644473600000000ULL
#endif

struct timezone
{
int tz_minuteswest;
int tz_dsttime;
};

int
gettimeofday (struct timeval *tv, struct timezone *tz)
{
FILETIME ft;
LARGE_INTEGER li;
__int64 t;
static int tzflag;

if (tv)
{
GetSystemTimeAsFileTime (&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
t = li.QuadPart; /* In 100-nanosecond intervals */
t -= EPOCHFILETIME; /* Offset to the Epoch time */
t /= 10; /* In microseconds */
tv->tv_sec = (long) (t / 1000000);
tv->tv_usec = (long) (t % 1000000);
}

if (tz)
{
if (!tzflag)
{
_tzset ();
tzflag++;
}
tz->tz_minuteswest = _timezone / 60;
tz->tz_dsttime = _daylight;
}

return 0;
}

posted @ 2012-01-12 18:38 skyline 阅读(357) | 评论 (0)编辑 收藏

1、文字:http://www.cegui.org.uk/wiki/index.php/Formatting_Tags_in_CEGUI

posted @ 2012-01-12 10:07 skyline 阅读(289) | 评论 (0)编辑 收藏

2012年1月11日 #

http://hi.baidu.com/pro_lily/blog/item/d3e513272b701b038a82a18b.html

2011-02-18 21:34

1、 今天终于把png格式的图片进行透明纹理贴图给搞定了。读取png格式图片用的是FreeImage这个GUI,这段代码同样可以读其他格式的图片,代码如下:

FREE_IMAGE_FORMATfifmt = FreeImage_GetFileType("E:/VV-Ocean/texture/clouds_20070202-0240.png",0);

FIBITMAP*dib = FreeImage_Load(fifmt,"E:/VV-Ocean/texture/clouds_20070202-0240.png", 0);

BYTE *bits = newBYTE[FreeImage_GetWidth(dib)*FreeImage_GetHeight(dib)*4];

BYTE *pixels = (BYTE*)FreeImage_GetBits(dib);

BYTEt_r,t_g,t_b,t_a;

for(intpix=0; pix<FreeImage_GetWidth(dib)*FreeImage_GetHeight(dib); pix++)

{

t_r = bits[pix*4+0] =pixels[pix*4+2];

t_g = bits[pix*4+1] =pixels[pix*4+1];

t_b = bits[pix*4+2] =pixels[pix*4+0];

t_a = bits[pix*4+3] =pixels[pix*4+3];

}

glGenTextures(1,&texture); //generate texture object

glBindTexture(GL_TEXTURE_2D, texture); // enable ourtexture object

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);

// generate thetexture image

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,FreeImage_GetWidth(dib),

FreeImage_GetHeight(dib), 0, GL_RGBA,GL_UNSIGNED_BYTE, bits);

FreeImage_Unload(dib);

deletebits;

(1) 进行透明贴图的时候,要开混色(Blend);

(2) glTexImage2D 和 gluBuild2DMipmaps这两个函数,后者是经过GPU优化的,效率高,程序会根据视点离物体远的时候它会用比较粗糙的纹理,当视点离物体近的时候它会按照纹理过滤方法选用精细的图像,原理是Mipmaps,比如说你用一张256*256的图像当纹理,用第二个函数的话它会为这张图建立层次信息256*256(最清晰)、128*128、64*64、32*32、...通过纹理过滤会选择一个合适的像素尺寸。

使用glTexImage2D()时所采用的位图文件分辨率必须为:64×64128×128256×256三种格式,如果其他大小则会出现绘制不正常。而gluBuild2DMipmaps()支持任意分辨率位图文件

(3) 当一个物体已经有个纹理的时候,再去贴另外一个纹理的时候,要打开blend,或者用多重纹理。

posted @ 2012-01-11 13:43 skyline 阅读(921) | 评论 (0)编辑 收藏

Texturing

Introduction

Textures are basically a chuck of memory, often using R,G,B(,A) values with 8 bits per channel. Usually textures contain image data, but it is data, you can do with it whatever you want. In GLSL a texture is specified as a uniform variable. Textures have their own type, which is one of the following:

sampler1D 1D texture
sampler2D

2D texture

sampler3D 3D texture
samplerCube Cubemap texture
sampler1DShadow 1D texture for shadow map
sampler2DShadow 2D texture for shadow map
sampler2DRect for rectanguar textures (width, height non power of 2) (GL_ARB_texture_rectangle)
sampler2DRectShadow for shadow map, rectanguar textures (width, height non power of 2) (GL_ARB_texture_rectangle)

Table: Texture Data Types in GLSL

There are texture lookup functions to access the image data. Texture lookup functions can be called in the vertex and fragment shader. When looking up a texture in the vertex shader, level of detail is not yet computed, however there are some special lookup functions for that (function names end with "Lod").
The parameter "bias" is only available in the fragment shader It is an optional parameter you can use to add to the current level of detail.
Function names ending with "Proj" are the projective versions, the texture coordinate is divided by the last component of the texture coordinate vector.

vec4 texture1D(sampler1D s, float coord [, float bias])
vec4 texture1DProj(sampler1D s, vec2 coord [,float bias])
vec4 texture1DLod(sampler1D s, vec4 coord [,float bias])
vec4 texture1DProjLod(sampler1D s, float coord, float lod)
vec4 texture1DProjLod(sampler1D s, vec4 coord, float lod)
vec4 texture2D(sampler2D s, vec2 coord [, float bias])
vec4 texture2DProj(sampler2D s, vec3 coord [,float bias])
vec4 texture2DProj(sampler2D s, vec4 coord [,float bias])
vec4 texture2DProjLod(sampler2D s, vec3 coord, float lod)
vec4 texture2DProjLod(sampler2D s, vec4 coord, float lod)
vec4 texture3D(sampler3D s, vec3 coord [, float bias])
vec4 texture3DProj(sampler3D s, vec4 coord [, float bias])
vec4 texture3DLod(sampler3D s, vec3 coord [, float bias])
vec4 texture3DProjLod(sampler3D s, vec4 coord, float lod)
vec4 textureCube(samplerCube s, vec3 coord [, float bias])
vec4textureCubeLod(samplerCube s, vec3 coord , float lod)
vec4 shadow1D(sampler1DShadow s, vec3 coord [, float bias])
vec4 shadow1DProj(sampler1DShadow s, vec4 coord [, float bias])
vec4 shadow1DLod(sampler1DShadow s, vec3 coord [, float bias])
vec4 shadow1DProjLod(sampler1DShadow s, vec4 coord, float lod)
vec4 shadow2D(sampler2DShadow s, vec3 coord [, float bias])
vec4 shadow2DProj(sampler2DShadow s, vec4 coord [, float bias])
vec4 shadow2DLod(sampler2DShadow s, vec3 coord, float lod)
vec4 shadow2DProjLod(sampler2DShadow s, vec4 coord, float lod)

Table: Texture Lookup Functions in GLSL

Example: Loading a Texture

This part doesn't have anything to do with GLSL, but to have some code to load textures is important. There are many OpenSource libraries specialized in loading image formats. One of them is DevIL, another one is FreeImage. I am going to use FreeImage to load images for this tutorial.

I wrote a little wrapper around FreeImage to load and create textures with minimal code overhead. I also included a simple implementation of a smart pointer, which makes it much easier if you have several objects using the same texture, but you don't have to use it to load textures.

#include "texture.h"
#include "smartptr.h"

cwc::SmartPtr<cwc::TextureBase>   pTexture;

void loadtexture()
{
    pTexture = cwc::TextureFactory::CreateTextureFromFile("texture.jpg");
}


void draw()
{
  if (pTexture) pTexture->bind(0);  // bind texture to texture unit 0
}
C++ Source Code: Loading Texture

Example: Swapping Color Channels

An simple GLSL example is to swap the red and blue channel of the displayed texture..

varying vec2 vTexCoord;


void main(void)
{
   vTexCoord = gl_MultiTexCoord0;
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
        
Vertex Shader Source Code

the texture coordinate is passed down to the fragment shader as varying variable.

uniform sampler2D myTexture;

varying vec2 vTexCoord;



void main(void)

{
   gl_FragColor = texture2D(myTexture, vTexCoord).bgra;
}
Fragment Shader Source Code

You probably noticed the ".xy" and ".bgra". The order of components in GLSL can be changed. This can be done by appending the component names in the order you want. You can even repeat components. In this example ".bgra" is used. This technique can also be used to convert vectors, for example vec4 to vec2.

vec4 TestVec = vec4(1.0, 2.0, 3.0, 4.0);
vec4 a = TestVec.xyzw; // (1.0, 2.0, 3.0, 4.0) vec4 b = TestVec.wxyz; // (4.0, 1.0, 2.0, 3.0) vec4 c = TestVec.xxyy; // (1.0, 1.0, 2.0, 2.0) vec2 d = TextVec.zx; // (3.0, 1.0)
Vertex of Fragment Shader Source Code: Swizzle Examples

You may also wonder why "rgba" is used and not "xyzw". GLSL allows using the following names for vector component lookup:

x,y,z,w Useful for points, vectors, normals
r,g,b,a Useful for colors
s,t,p,q Useful for texture coordinates

Table: Vector Component Names

Multitexturing

Mutlitexturing is very easy: In the GLSL program you simply specify several samplers and in the C++ program you bind textures to the appropriate texture units. The uniform sampler variables must be set to the appropriate texture unit number.

Example Project

This source code only contains the simple example of swapping red and blue channel and is meant as base code for your texturing experiments. It contains everything required to compile it under Visual Studio 8 (GLEW, Freeglut, FreeImage).

Download: GLSL_Texture.zip (Visual Studio 8 Project)
(If you create a project/makefile for a different platform/compiler, please send it to: christen(at)clockworkcoders.com and I will put it here.)

posted @ 2012-01-11 13:37 skyline 阅读(610) | 评论 (0)编辑 收藏