2009年2月15日星期日

OpenGL Evaluators

OpenGL的求值器很好用,对于显示和编辑曲面非常有用,不过遗憾的是它仅仅能够帮助显示曲面,而无法回传给用户真正的多边形数据,这也难怪,最初ogl在SGI的图形工作站上,Evaluators是以硬件加速实现的。
把手头的opengl driver代码打开,看来看去,还是mesa的好些,整理一下贴出来,顺便测试一下如何贴代码, 颜色显示的还不正常,需要上传一个css文件,不知道blogspot如何才能上传文件。

namespace sglib{
namespace gfx{

class bezier{
public:
/*
* Horner scheme for Bezier curves
*
* Bezier curves can be computed via a Horner scheme.
* Horner is numerically less stable than the de Casteljau
* algorithm, but it is faster. For curves of degree n
* the complexity of Horner is O(n) and de Casteljau is O(n^2).
* Since stability is not important for displaying curve
* points I decided to use the Horner scheme.
*
* A cubic Bezier curve with control points b0, b1, b2, b3 can be
* written as
*
* (([3] [3] ) [3] ) [3]
* c(t) = (([0]*s*b0 + [1]*t*b1)*s + [2]*t^2*b2)*s + [3]*t^2*b3
*
* [n]
* where s=1-t and the binomial coefficients [i]. These can
* be computed iteratively using the identity:
*
* [n] [n ] [n]
* [i] = (n-i+1)/i * [i-1] and [0] = 1
*/
static void curve(
const float * cp
, float * out
, float t
, int dim
, int order ) {

#define MAX_EVAL_ORDER 30
static float inv_tab[MAX_EVAL_ORDER];
static bool inited = false;
if(!inited){
// KW: precompute 1/x for useful x.
for (int i = 1; i < MAX_EVAL_ORDER; i++)
inv_tab[i] = 1.0F / i;
inited = true;
}
float s, powert, bincoeff;
unsigned int i, k;

if(t == 0){
for (k = 0; k < dim; k++)
out[k] = cp[k];
}
else if( t == 1.0){
for (k = 0; k<dim; k++)
out[k] = cp[dim*(order-1)+k];
}
else {
if (order >= 2) {
bincoeff = (float) (order - 1);
s = 1.0F - t;

for (k = 0; k < dim; k++)
out[k] = s * cp[k] + bincoeff * t * cp[dim + k];

for (i = 2, cp += 2 * dim, powert = t * t; i < order; i++, powert *= t, cp += dim) {
bincoeff *= (float) (order - i);
bincoeff *= inv_tab[i];
for (k = 0; k < dim; k++)
out[k] = s * out[k] + bincoeff * powert * cp[k];
}
}
else { /* order=1 -> constant curve */
for (k = 0; k < dim; k++)
out[k] = cp[k];
}
}
}
private:
void cleanup(){
if(_ver)
delete []_ver;
_ver = 0;
}
bool gen_vertex(int usize, int vsize){
cleanup();

int total = _dim * usize * vsize;

float * vcp = new float [_dim*_vorder];
_ver = new float[total];
if(!_cp || !_ver || !vcp)
return false;

float ustep = 1.0f/(usize-1);
float vstep = 1.0f/(vsize-1);
float fu, fv;
int u, v;
for(u=0, fu=0 ; u<usize; u++, fu += ustep){
//1. calc control point first
for(v=0; v<_vorder; v++){
curve (&_cp[_dim*v*_uorder], &vcp[v*_dim], fu, _dim, _uorder);
}
float * ver = _ver + _dim*u;
//2. calc vertex along v dir
for(v=0, fv=0; v<vsize; v++, fv += vstep){
curve (vcp, ver, fv, _dim, _vorder);
ver += usize*_dim;
}
}
delete []vcp;
return true;
}
public:
bezier(): _cp(0) , _ver(0) {
}
~bezier(){
cleanup();
}
void init(const float * cp, int dim, int uorder, int vorder){
_cp = cp, _dim = dim, _uorder = uorder, _vorder = vorder;
}

bool gen(int usize, int vsize){
bool b = true;
b &= gen_vertex(usize, vsize);
return b;
}

float * get_vertex() {
return _ver;
}
protected:
const float * _cp; // control points
int _uorder;
int _vorder;
int _dim;
float * _ver;
};


}} //gfx, sglib

2009年2月14日星期六

template & local class

void qnode::on_poschanged() {
struct pos_changed {
inline void operator ()(qio_input * i) {
i->node_poschanged();
}
};
std::for_each(_inputs.begin(), _inputs.end(), pos_changed());
_output->node_poschanged();
}

以目前的c++标准而言,这段代码是通不过的,不过vc2008还是没问题,ms的人务实,
g++编译错误。
当然这是简单的例子,可以用mem_func糊弄过去,然而复杂点的就麻烦了...
所以为了目前的可移植性,尽量还是把class移出去,这是个让人灰心的解决之道。或者,用boost::lambda来替代.
这对于c++号称oo封装的语言来说,为一个封装的便利付出的代价,够讽刺的。

2009年2月13日星期五

跨平台的C++ IDE

http://www.codeblocks.org

支持windows,linux,Mac Os,windows下结合mingw,基本可以脱离vs.
debug也挺方便,只是用的时间还短,不知道稳定性如何。

2009年2月4日星期三

std::string format(const char * format, ...)

很多时候需要这样一个便捷的函数
std::string s = format("string %d ", i);
std::string s = format("string %d %f", i, f);
std::string s = format("string %d %f %s", i, f, s);

ostream用起来很笨拙,而且效率低下,boost::format很强大,不过这么简单的东西就没必要动用boost这个庞然大物了...


std::string format( const char * format, ...)
{
char buf[1024];
va_list arglist;
va_start(arglist, format);
_vsnprintf(buf, 1024, format, arglist);
va_end(arglist);
return std::string(buf);
}

2009年2月3日星期二

auto delete ptr

有时候经常需要这样的一个东西
...
{
T * p = new T ;
....
delete p;
}
...

boost的smart ptr有shared_ptr可以用,不过boost实在太大了,这是唯一让我感到有些不爽的地方。

于是写了一个auto_deleteT的template class

template
class auto_deleteT {
public:
auto_deleteT(T * p) : _ptr(p){
}
~auto_deleteT() {
if(_ptr)
delete _ptr;
}
inline T * operator->() const {// never throws
assert(_ptr != 0);
return _ptr;
}
protected:
T * _ptr;
};

这样可以很方便使用 :
{
auto_deleteT aptr(new T(...));
aptr->xxxx(....)
....
}

接着,再添加一个支持,可以把auto_deleteT放到STL的容器内:
...
auto_deleteT(const auto_deleteT & a){
_ptr = a._ptr;
// giveup pointer.
auto_deleteT & at = (auto_deleteT &)a;
at.reset();
}
auto_deleteT & operator = (const auto_deleteT & a){
_ptr = a._ptr;
auto_deleteT & at = (auto_deleteT &)a;
at.reset();
return *this;
}
void reset() {
_ptr = 0;
}
....
STL容器内部使用的copy复制内容,这样如果auto_delete ptr被复制后,就主动放弃
pointer内容:

{
std::vector objs;
for(int i=0; i < n; i++) {
a(new obj...);
objs.push_back(a);
}
}

不过由于它没有引用计数,所以使用上要小心,不过也不是什么大问题:
objs[n]->xxx()之类的,就可以避免内存泄露。


iocp net lib

去年某个时候,花了几天写了一个基于模板的network lib,基于windows的iocp,源于当时对asio使用繁琐的失望。
由于最近有使用的需要,把代码重新看过一遍,才发现问题多多,于是重新写了一遍,然后看了看asio的文档,才发现这张熟悉的图。

顺便链接下asio作者的blog,http://think-async.blogspot.com/

2009年2月1日星期日

My son





In 01/07/2009, my son, the first baby of mine, came into the world.