2010年12月31日 星期五

利用Qt轉出bitmap點陣字

一般轉點陣字都是用win api
不過我來寫一個Qt的方式
觀念是一樣的
先將字畫出來,在擷取下來,轉成點陣圖
所以我的作法是
將字畫在QLabel上(注意,要將反鋸齒關掉)
在擷取成QPixmap
最後在轉成bitmap
void Widget::rasters()
{
    if(ui->lineEdit->text().isEmpty()){
        ui->textEdit->setText(ui->lineEdit->text());
        return;
    }
    QLabel label(ui->lineEdit->text());
    QFont font(ui->fontComboBox->currentText());
    font.setStyleStrategy(QFont::NoAntialias);
    font.setPixelSize(ui->comboBox->currentText().toInt());
    label.setFont(font);
    label.adjustSize();
    QPixmap pixmap = QPixmap::grabWidget(&label);
    QImage image = pixmap.toImage();
    QString text;
    for(int i=0; i<pixmap.height(); i++){
        for(int j=0; j<pixmap.width(); j++){
            QRgb rgb = image.pixel(j,i);
            if(128 > qGray(rgb)){
                text.append(QString::fromUtf8("■"));
            }else{
                text.append(QString::fromUtf8("□"));
            }
        }
        text.append("\n");
    }
    ui->textEdit->setText(text);
}

利用freetype轉出bitmap點陣字

rasters是利用freetype將特定字型文字轉成bitmap字串
bool rasters(const wchar_t texts[], Bitmap *bitmap)
{
    if(texts[0] == '\0') {
        return true;
    }

    FT_Library library;
    if (FT_Init_FreeType(&library)) {
        return false;
    }

    FT_Face face;
    if(FT_New_Face(library, "C:/WINDOWS/Fonts/MINGLIU.TTC", 0, &face)) {
        FT_Done_FreeType(library);
        return false;
    }

    int pixalWidth = 36;
    int pixalHeight = 36;
    if(FT_Set_Pixel_Sizes(face, pixalWidth, pixalHeight)) {
        FT_Done_Face(face);
        FT_Done_FreeType(library);
        return false;
    }

    FT_Select_Charmap(face, FT_ENCODING_UNICODE);
    for(int i=0; i<wcslen(texts); i++) {
        unsigned int ucode = texts[i];
        FT_UInt glyph_index = FT_Get_Char_Index(face, ucode);
        if(!glyph_index) {
            continue;
        }

        if (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT)) {
            continue;
        }
        if (face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
            if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO)) {
                continue;
            }
        }

        Bitmap font = {    face->glyph->bitmap_left,
                        face->glyph->bitmap_top - face->glyph->bitmap.rows,
                        face->glyph->bitmap.width,
                        face->glyph->bitmap.rows,
                        face->glyph->bitmap.pitch,
                        face->glyph->bitmap.buffer
                      };
        combinetext(bitmap, &font);
    }

    FT_Done_Face(face);
    FT_Done_FreeType(library);

    return true;
}

將二個bitmap合成一個bitmap(印出bitmap字串)

之前有寫一個印出bitmap字的程式
現在將這個功能擴充成印出bitmap字串
void combinetext(Bitmap *bitmap, Bitmap *font)
{
    int x1 = bitmap->x;
    int y1 = bitmap->y;
    unsigned int width1 = bitmap->width;
    unsigned int height1 = bitmap->height;
    unsigned int pitch1 = bitmap->pitch;
    unsigned char* data1 = bitmap->data;

    int x2 = x1 + width1 + font->x;
    int y2 = font->y;
    unsigned int width2 = font->width;
    unsigned int height2 = font->height;
    unsigned int pitch2 = font->pitch;
    unsigned char* data2 = font->data;

    int x3 = x1;
    if(x1 > x2) {
        x3 = x2;
    }
    unsigned int width3 = width1 + font->x + width2;
    int y3 = y1;
    unsigned int height3 = height1;
    if(y1 > y2) {
        y3 = y2;
        height3 += (y1 - y2);
    }
    if(y1+height1 < y2+height2) {
        height3 += (y2+height2) - (y1+height1);
    }
    unsigned int pitch3 = width3/8;
    if(width3 % 8 != 0) {
        pitch3 += 1;
    }

    int size3 = pitch3 * height3;
    unsigned char *data3 = calloc(size3, sizeof(unsigned char));
    int shiftX1 = 0;
    int shiftY1 = (height3+y3) - (height1+y1);
    for(int j=0; j<height1; j++) {
        int nj = j+shiftY1;
        for(int i=0; i<pitch1; i++) {
            int n = shiftX1/8+i+nj*pitch3;
            unsigned char data = data1[i+j*pitch1];
            int shift = shiftX1%8;
            if(shift == 0) {
                data3[n] |= data;
            } else {
                data3[n] |= (0x7f & data>>shift);
                data3[n+1] |= data<<(8-shift);
            }
        }
    }
    int shiftX2 = x2-x3;
    int shiftY2 = (height3+y3) - (height2+y2);
    for(int j=0; j<height2; j++) {
        int nj = j+shiftY2;
        for(int i=0; i<pitch2; i++) {
            int n = shiftX2/8+i+nj*pitch3;
            unsigned char data = data2[i+j*pitch2];
            int shift = shiftX2%8;
            if(shift == 0) {
                data3[n] |= data;
            } else {
                data3[n] |= (0x7f & data>>shift);
                data3[n+1] |= data<<(8-shift);
            }
        }
    }
    free(bitmap->data);

    bitmap->x = x3;
    bitmap->y = y3;
    bitmap->width = width3;
    bitmap->height = height3;
    bitmap->pitch = pitch3;
    bitmap->data = data3;
}

2010年11月23日 星期二

Qt中讀寫jpg和gif

在我的開發電腦中,可以執行(秀出jpg和gif),但是其他電腦不行。
雖然我知道是dll的問題,但是還是找好久。

在執行檔處,建立一個資料夾叫imageformats
然後將qt\plugins\imageformats內要用的dll複製到剛剛建立的資料夾

2010年11月10日 星期三

在Qt中列出所有serial port

由於QSettings不能利用含有反斜線的key,來找到值。
所以只好和winapi交互利用。

要注意的是QSettings得到的鍵值是斜線,可是winapi是反斜線

const QStringList WinDongle::getComPort()
{
    QStringList comports;
    QString keyPath = "HARDWARE\\DEVICEMAP\\SERIALCOMM";
    HKEY comsKey;
    LPCWSTR winKeyPath = (LPCWSTR)keyPath.constData();
    if(RegOpenKey(HKEY_LOCAL_MACHINE, winKeyPath, &comsKey) != ERROR_SUCCESS)
    {
        error = UNKNOW;
        RegCloseKey(comsKey);
        return comports;
    }

    QSettings settings(QString("HKEY_LOCAL_MACHINE\\")+keyPath, QSettings::NativeFormat);
    QStringList keys = settings.allKeys();
    foreach( const QString & key, keys )
    {
        QString newKey(key);
        newKey.replace(QString("/"), QString("\\"));
        LPCWSTR winKey = (LPCWSTR)newKey.constData();
        char *szData= new char[101];
        DWORD dwType, dwLen=100;
        if (RegQueryValueEx(comsKey, winKey,
                            NULL, &dwType, (unsigned char *)szData, &dwLen) == ERROR_SUCCESS)
        {
            comports.append( QString::fromUtf16((ushort*)szData) );
        }
        delete[] szData;
    }
    RegCloseKey(comsKey);
    return comports;
}
參考資料:在 Win32 下 Serial Port 的通訊

Qt 字串轉換

//Convert a QString To LPCTSTR
LPCTSTR QString_To_LPCTSTR(QString mQTData)
{
    return (LPCTSTR)mQTData.utf16();
}

//Convert a QString To LPCSTR
LPCSTR QString_To_LPCSTR(QString mQTData)
{
    return (LPCSTR)mQTData.utf16();
}

//Convert a QString To LPTSTR
LPTSTR QString_To_LPTSTR(QString mQTData)
{
    return (LPTSTR)mQTData.utf16();
}

//Convert a LPCTSTR To QString
QString LPCTSTR_To_QString(LPCTSTR mWinData)
{
    return QString::fromUtf16((ushort*)mWinData);
}

//Convert a LPBYTE To QString
QString LPBYTE_To_QString(LPBYTE mWinData)
{
    return QString::fromUtf16((ushort*)mWinData);
}

//Convert a Char[] To QString
QString Char_To_QString(char mWinData[])
{
    return QString::fromUtf16((ushort*)mWinData);
}

//Convert a WCHAR* to a QString
QString WCHAR_to_QString(WCHAR* mBuffer)
{
    return QString::fromWCharArray(mBuffer);
}

//Convert a TCHAR To QString
QString TChar_To_QString(TCHAR mWinData[])
{
    return QString::fromUtf16((ushort*)mWinData);
}

資料來源 VQTConver

2010年11月7日 星期日

opengl 視窗置中

其實視窗置中和openGL一點關係都沒有
問題在你的視窗是誰建立的
是用glfw? glut? or ??
至於置中,就還簡單了
視窗的左上角位置 = 0.5 X( 桌面大小 - 視窗大小 )


    // Open a window and create its OpenGL context
    if( !glfwOpenWindow( width, height, 0,0,0,0, 0,0, GLFW_WINDOW ) ) {
        fprintf( stderr, "Failed to open GLFW window\n" );

        glfwTerminate();
        exit( EXIT_FAILURE );
    }
    
    GLFWvidmode desktop;
    glfwGetDesktopMode( &desktop );
    int posX = 0.5 * ( desktop.Width - width );
    int posY = 0.5 * ( desktop.Height - height );
    glfwSetWindowPos( posX, posY );

CodeLite

每次在用Code::Block都覺得用的很不習慣
尤其最近用久了Qt Creator後
整個寫code的習慣,都被養刁了
但是我又不想用vc

終於讓我找到CodeLite了
不管是畫面,熱鍵配置都比Code::Block好太多了

2010年11月4日 星期四

Squirrel

今天灌Code::Block時發現Squirrel的選項。
wiki了一下
It is used extensively by Code::Blocks for scripting and was also used in Final Fantasy Crystal Chronicles: My Life as a King[2] It is also used in Left 4 Dead 2 for scripted events[3].
沒想到才幾年而已,就流行起來了

2010年10月25日 星期一

Qt多國語言機制

Qt原本就內建了一套多國語言的機制,可是需要用到Qt Linguist。另外如果要作到動態的話,使用Qt Designer建立的GUI才有提供,要不然只能手動設定(參考)。

所以我自己改寫了一個class Translator。
為了使用方便,我利用了Singleton Pattern
只要傳入物件的指標,還有屬性,以及字串標籤。其他的部份,Translator都幫你處理了。
使用範例如下:
    QMenu *menu = new QMenu;
    menuBar()->addMenu(menu);
    Translator::add(menu, "title", "FILE");
    QAction *action = new QAction(0);
    menu->addAction(action);
    Translator::add(action, "text", "EXIT");
當然還有語言清單
menuBar()->addMenu(Translator::menu);

在這裡說明一下,我是利用Qt的setProperty來達到這個效果的。
bool QObject::setProperty ( const char * name, const QVariant & value )
只要是繼承至QOject的元件,都可以用setProperty來設定屬性值。
widget->setProperty("windowTitle", QVariant("標題"));

另外語言表方面,我比較喜歡用table而不是跟Qt一樣用list。table格式我選用csv,因為可以直接用openoffice編輯。
以下是csv檔的內容
"LANGUAGE_COUNTRY","en","zh_TW","zh_CN","ja","es"
"LANGUAGE_COUNTRY","English","繁體中文","简体中文","日本語","español"
"LANGUAGE","Language","語系","语言","言語","Lenguaje"
"FILE","File","檔案","文件","ファイル","Archivo"
"NEW","New","開新檔案","新建","新規","Nuevo"
利用第二列產生QMenu,
至於第一列則因為當要判斷作業系統環境時,需要用到language_country code

為什麼不跟Qt一樣,用英文當key,要用第一行的tag呢?
其實原因很簡單。當你有一天,發現老闆總是同一段英文一直換寫法,你就知道為什麼了。。。

2010年10月18日 星期一

license header template (Qt creator)

大部分的程式開頭,都有一段宣告。像是LGPL、GPL或doxygen的註譯等。
Qt creator提供一個license template的功能,當每次增加新的檔案時,都會在文件最前面加上設定好的字串。
Tools > Options... > C++ > License Template > Browse
選擇文件檔(像是gpl.txt)

以下Qt提供的特殊placeholders

  1. %YEAR%: Year
  2. %DATE%: Date
  3. %USER%: User name
  4. %FILENAME%: File name
  5. %CLASS%: Class name (if applicable)
舉個例子:
/**
* @file %FILENAME%
* @brief define %CLASS% class
*
* Define %CLASS% class.
*
* @author %USER%
*
* @date %DATE%
*/
經過Qt轉換後,就會變成
/**
* @file dictionary.h
* @brief define Dictionary class
*
* Define Dictionary class.
*
* @author http://yycking.blogspot.com/
*
* @date 2010/10/18
*/

2010年10月3日 星期日

DPInst & nsis

DPInst是驅動程式安裝架構DIFx(Driver Install Frameworks) 所提供的工具之ㄧ。使用方式很簡單。
以下說明是以FTDI的driver為例:
  1. 將ftdi的driver解壓縮到driver資料夾
  2. 到微軟下載wdk
  3. 安裝完wdk後,可在WinDDK\redist\DIFx\dpinst中看到二個資料夾MultiLin(提供多國語言),EngMui(提供特定語言,預設為英文,除非提供.mui檔)
  4. 在MultiLin提供三個資料夾x86,amd64,ia64
  5. 將x86內的dpinst.exe重新命名為x86.exe,將amd64內的dpinst.exe重新命名為x64.exe。將x86.exe和x64.exe複製到driver資料夾(現在執行x86或x64就會幫你安裝FTDI的driver了)
  6. 因為我想要安裝程式時,偷偷的替user安裝驅動(也就是不用秀出DPInst的視窗)。
  7. 所以在driver的資料夾建立一個dpinst.xml檔。
    <?xml version="1.0"?>
    <dpInst>
    <!--- 不秀出視窗 -->
    <suppressWizard/>
    <quietInstallStrict/>
    <!--- 強迫安裝 -->
    <forceIfDriverIsNotBetter/>
    </dpInst>
    
  8. 在nsis中加入下面程式,即可自動判斷安裝32還是64位元的驅動
    ; Check OS is 32bit or 64bit
    !include "x64.nsh"
    !define FTDI_32_URL "$INSTDIR\driver\x86.exe"
    !define FTDI_64_URL "$INSTDIR\driver\x64.exe"
    
    Function installFTDI
    ${If} ${RunningX64}
    StrCpy $2 ${FTDI_64_URL}
    ${Else}
    StrCpy $2 ${FTDI_32_URL}
    ${EndIf}
    ExecWait $2
    FunctionEnd
    

2010年9月7日 星期二

在Qt中整合freetype

建立字型對照表
    QSettings settings("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
QSettings::NativeFormat);
QStringList list = settings.allKeys();

for(int i=0;i<list.size();i++)
{
QString key = list.at(i);
QString text = settings.value(key).toString();
QStringList keys = key.split(" & ");
QString last = keys.last();
keys[keys.size()-1] = last.left(last.indexOf(" ("));
for(int j=0;j<keys.size();j++)
{
index.insert(keys[j], j);
name.insert(keys[j], text);
}
}

轉換成FT_Face
    QString family = ui->fontComboBox->currentText();
QString path("C:/WINDOWS/Fonts/");
path.append(name[family]);
int in = index[family];
FT_New_Face(library, path.toUtf8(), in, &face))

2010年8月30日 星期一

用mingw編譯freetype

下載ft242.zip,解壓縮

1.devcpp+mingw
set PATH=C:\Dev-Cpp\bin
set PATH=%PATH%;C:\Dev-Cpp\mingw\bin
set PATH=%PATH%;%SystemRoot%\System32
set make=mingw32-make
set make=%make%
make
make
copy objs\freetype.a C:\Dev-Cpp\lib\libfreetype.a /Y
xcopy include\* C:\Dev-Cpp\include /Y /S
pause

將上面的文字檔存成t.bat檔,放在解壓縮後的freetype資料夾,點擊t.bat

2.qt+mingw
set QTDIR=C:\Qt\2010.04\qt
set PATH=C:\Qt\2010.04\qt\bin
set PATH=%PATH%;C:\Qt\2010.04\bin;C:\Qt\2010.04\mingw\bin
set PATH=%PATH%;%SystemRoot%\System32
set QMAKESPEC=win32-g++
set make=mingw32-make
set make=%make%
make
make
copy objs\freetype.a C:\Qt\2010.04\mingw\lib\libfreetype.a /Y
xcopy include\* C:\Qt\2010.04\mingw\include /Y /S
pause

2010年8月16日 星期一

避免打開雙視窗

#include <windows.h>

#define Executable "test.exe"
char TITLE[] = "The SoftW";//full title name "The SoftWare"
int size;

BOOL CALLBACK EnumWindowsProc(HWND hwnd, DWORD lParam)
{
//get hwnd title
char buffer[255];
SendMessage(hwnd,WM_GETTEXT,255,(long)buffer);

//check title is we want
if(strncmp(buffer,TITLE,size)==0)
{
//if window is iconic, show it as normal
if(IsIconic(hwnd))
ShowWindow(hwnd, SW_RESTORE);

//show it at top of desktop
SetForegroundWindow(hwnd);

//we got it
return FALSE;
}

//to check next hwnd
return TRUE;
}

int main(int argc, char** argv)
{
//check title size,remove '\0'
size = sizeof(TITLE)/sizeof(char);
size--;

//check window is show or not
if(EnumWindows((WNDENUMPROC)EnumWindowsProc,0)==TRUE)
{
//if window not show, to execute it
WinExec(Executable,SW_SHOW);
}

return 0;
}

2010年8月10日 星期二

使用glut時,不顯示控制台視窗

prevent opening a console window in addition to your GLUT window when it is run

in vc
menu option ( Project → Properties )
From the Configuration: list box, select All Configurations.
select the Linker subtree and then Command Line option in the left pane. Then add the following code to the Additional Options: text box
Copy & Paste: /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup

in mingw
click on Project and go to Project Options.
Click on the Parameters tab.
On the 3rd box, Linker, you will need to add in the following code to your project
-Wl,--subsystem,windows

2010年7月20日 星期二

專案自動化建置(先叫這個名字)

這是我轉寫的批次檔
主要功能是將Qt的專案編譯成執行檔
再轉成安裝程式(unicode nsis)
最後上傳到伺服器

資料夾說明
code放qt的專案和程式碼
bin編譯完成後的執行檔和obj file
resource執行時需要的圖檔或文字檔
install-win安裝程式原始碼和檔案
CD-win光碟檔

下面是批次檔
rem 移除一些不需要的檔案(win和mac以及qt的暫存檔)
del .* /a/s/f/q
del Thumbs.db /a/s/f/q
del *.o /a/s/f/q
del *.db /a/s/f/q
del *.DS_Store /a/s/f/q
del *.pro.user /a/s/f/q
del Makefile /a/s/f/q
del *.Debug /a/s/f/q
del *.bak /a/s/f/q
del *.Release /a/s/f/q
del moc_*.cpp /a/s/f/q
rem 移除執行檔(因為要重新編譯)
rd bin /s /Q

rem 建立版本(利用日期),分別放到version.h和version.nsi,這樣執行檔和安裝程式就有相同的版本
For /f "tokens=1-3 delims=/ " %%a in ('date /t') do (set date=%%a-%%b-%%c)
echo #define VERSION "%date%">Code/version.h
echo !define SOURCE_FILE_VERSION "%date%">install-win\version.nsi

rem 編譯qt專案成執行檔
call C:\Qt\2010.04\bin\qtenv.bat
cd Code
qmake
mingw32-make release
cd ..

rem 建立安裝檔,先將光碟檔移除(因為將重新編譯)
rd CD-win /s /Q
rem 將執行檔需要的檔案複製到file
xcopy install-win\File-template\*.* install-win\File\ /Y /S
XCOPY Resource\*.* install-win\File\ /Y
COPY "bin\release\MySoftWare\MySoftWare.exe" "install-win\File\MySoftWare.exe"
rem 將光碟需要的檔案複製到CD-win
XCOPY install-win\CD-template\*.* CD-win\ /Y /S
rem 編譯安裝檔(請自行尋找nsis),產生setup.exe
call "C:\Program Files\NSIS\Unicode\makensis.exe" "install-win\setup.nsi"
rem 移除File(因為安裝檔已經產生)
rd install-win\File /s /Q
COPY "install-win\setup.exe" "CD-win\setup.exe"

rem 上傳到伺服器
cd install-win
rem 壓縮安裝檔成zip(zip.exe是利用info-zip)
zip setup.zip setup.exe
cd..
set FTPActions=00000000000000.FTP
echo open your.web.ip>>%FTPActions%
echo namen>>%FTPActions%
echo password>>%FTPActions%
echo cd /web.com/download/MySoftWare>>%FTPActions%
echo mkdir %date%>>%FTPActions%
echo cd %date%>>%FTPActions%
echo bin>>%FTPActions%
echo send install-win\setup.zip setup.zip>>%FTPActions%
echo bye>>%FTPActions%
ftp -s:%FTPActions%
del %FTPActions%

rem 利用php解壓縮
start http://www.web.com/download/MySoftWare/unzip.php?path=%date%

pause


下面這一段式是unzip.php
<?php
$zip = zip_open($path."/setup.zip");
if ($zip) {
while ($zip_entry = zip_read($zip)) {
$fp = fopen($path."/".zip_entry_name($zip_entry), "w");
if (zip_entry_open($zip, $zip_entry, "r")) {
$buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
fwrite($fp,"$buf");
zip_entry_close($zip_entry);
fclose($fp);
}
}
zip_close($zip);
echo ‘ok’;
} else {
echo ‘failed’;
}
?>

2010年6月22日 星期二

print bitmap font array

先定義一下bitmap格式方便之後處裡
typedef struct Bitmap_ {
    int             x;
    int             y;
    unsigned int    width;
    unsigned int    height;
    unsigned int    pitch;
    unsigned char*  data;

} Bitmap;
下面是完整的程式,執行後將列印出一個大寫的F

#include <stdlib.h>
#include <stdio.h>
#include <locale.h>

typedef struct Bitmap_ {
    int             x;
    int             y;
    unsigned int    width;
    unsigned int    height;
    unsigned int    pitch;
    unsigned char*  data;

} Bitmap;

void printtext(Bitmap *bitmap)
{
    for(int j=0; j<bitmap->height; j++) {
        for(int i=0; i<bitmap->pitch; i++) {
            for(int k=7; k>=0; k--) {
                if(7-k+i*8 == bitmap->width)
                    break;
                wprintf(L"%c", (bitmap->data[i+j*bitmap->pitch] & 0x1<<k)?L'■':L'□');
            }
        }
        printf("\n");
    }
}

int main(int argc, char *argv[])
{
    if (!setlocale(LC_CTYPE, "")) {
        return EXIT_FAILURE;
    }

    unsigned char rasters[24] = { 0xff,0xc0,
                                  0xff,0xc0,
                                  0xc0,0x00,
                                  0xc0,0x00,
                                  0xc0,0x00,
                                  0xff,0x00,
                                  0xff,0x00,
                                  0xc0,0x00,
                                  0xc0,0x00,
                                  0xc0,0x00,
                                  0xc0,0x00,
                                  0xc0,0x00
                                };

    Bitmap bitmap = {0, 0, 10, 12, 2, rasters};
    printtext(&bitmap);
    return EXIT_SUCCESS;
}

2010年3月30日 星期二

專案交接

1.建置環境
必須建立實作一套可以在命令列下完成 init, build, package, install, test 動作的建置程序,並且包涵需要之套件軟體。視專案內容,這套建置程序可能是一份 build.xml(ant), 也可能是一份 Makefile ,或是更基礎的 shell script。重點是,這套建置程序要能交由建置系統自動執行並完成上述所有動作,整個過程不可以有人工輸入的部份。

2.環境說明文件
必須說明專案以及所需套件軟體和函式庫的用途。

3.專案uml圖

4.程式碼文件
開頭必須作文件簡介,及各函式簡介和修改紀錄
函式前必須詳細說明函式功能,包涵輸入及輸出說明


參考資料

2010年1月24日 星期日

如何在建立windows執行檔的版本資訊

打開rc檔
加入
VALUE "CompanyName", "公司\0"
VALUE "FileVersion", "檔案版本\0"
VALUE "FileDescription", "描述\0"
VALUE "InternalName", "內部名稱\0"
VALUE "LegalCopyright", "著作權\0"
VALUE "LegalTrademarks", "合法商標\0"
VALUE "OriginalFilename", "原始檔名\0"
VALUE "ProductName", "產品名稱\0"
VALUE "ProductVersion", "產品版本\0"
VALUE "Comments", "註解\0"
斷行要用\r\n

2010年1月6日 星期三

Wheel Light 模擬器

這是最近替公司產品寫的模擬器。主要是用Qt+OpenGL寫出來的。
有美工人員就是不一樣^.^