好的,我有一个类允许用户在 100x64 LCD 上设置像素。
// (U8 = unsigned char)
inline void pixelOn(const U8 X, const U8 Y) {
*(disp + ((Y / LCD_DEPTH) * LCD_WIDTH + X)) |= (1 << (Y % LCD_DEPTH));
}
inline void pixelOff(const U8 X, const U8 Y) {
*(disp + ((Y / LCD_DEPTH) * LCD_WIDTH + X)) &= !(1 << (Y % LCD_DEPTH));
}
现在我有一个在液晶显示器上画线的课程。有 3 个函数使用不同的像素“设置函数”:显示、擦除、反转
void NLine::show(bool update) const {
if(lcd == 0) return;
if (!NLcd::pixelInLcd(x, y) && !NLcd::pixelInLcd(endX, endY))
return;
if ((x == endX) || (y == endY)) {
straight(&NLcd::pixelOn);
} else {
bresenham(&NLcd::pixelOn);
}
visible = true;
if (update) {
display_update();
}
}
目前调用一个私有函数来使用函数指针设置像素。
void NLine::bresenham(void (NLcd::*fpPixelState)(const U8, const U8)) const {
// predetermine function to avoid ifs during calculation!
// low level pixel functions use U8!
S8 ix = x;
S8 iy = y;
S8 sx = ix < endX ? 1 : -1;
S8 sy = iy < endY ? 1 : -1;
S16 err = width + (-height), e2;
for (;;) {
// how to get the compiler to inline this (template?)!
(lcd->*fpPixelState)(static_cast<U8>(ix), static_cast<U8>(iy));
if (ix == endX && iy == endY)
break;
e2 = 2 * err;
if (e2 > (-height)) {
err += (-height);
ix += sx;
}
if (e2 < width) {
err += width;
iy += sy;
}
}
}
我认为我希望编译器在 for 循环中内联这个函数是可以理解的。我试图用模板解决这个问题,但同样的问题是我不知道编译器是否使用内联。我应该使用完全不同的设计还是如何解决这个问题?下一个问题是如果我调用 show erase 和 invert 因为不同的内联,编译器会生成很多代码,所以我认为我应该使用不同的代码设计?
编辑:
首先,感谢 Dietmar Kühl 的设计建议!所以这是结论:
这是测试代码:
NLine line(lcd, 0, 0, 99, 0);
t0 = timer.now();
for(S8 i=0; i<NLcd::LCD_HEIGHT; ++i) {
// x0, y0, xend, yend
line.setPosition(NLine::keep, i, NLine::keep, i);
// call only straight not the bigger bresenham function
line.show();
line.erase();
line.invert();
}
t1 = timer.now();
方法一:使用函数指针(第一)
内存:26384
RT:51 ms
方法 2:使用函数对象 (Dietmar Kühl)
内存:26592
RT:27 ms
方法三:在for循环中使用switch判断像素操作函数
内存:26416
RT:36 ms
方法 2:最佳 RT 但事实证明,如果围绕绘图方法的实现变得非常大,程序就会变得非常大,尤其是对于 bresenham。发生这种情况是因为模板实现为所有 3 个像素函数生成了完整代码。
方法3:似乎最简单的方法是一个很好的权衡。
欢迎进一步的建议。