平时我们看到电脑艺术笔写毛笔字,非常爽 也有朋友经常在群里炫耀自己毛笔字.如果自己能开发一款艺术笔软件那是多好啊,于是开始计划搜集资料 ,然后向众群求教,结果是数学要好,需要算法,并推荐了文章.结果文章打不开,我也没有拜读.只好开始自己动手啦.

 既然学OPENGL 编程 那一定能实现,

 基本思路,艺术笔的特点是 要有墨迹感 且墨水有收缩感 这个难度 其他写字很容易实现.于是想到纹理和混色 透明技术 ,首先加载纹理 ,用纹理来仿照毛笔字的粗糙度 用粒子来模拟散落的墨点.废话少说,动手写代码:

// wsqView.h : interface of the CWsqView class

//

/////////////////////////////////////////////////////////////////////////////


#if !defined(AFX_WSQVIEW_H__CF299264_8764_4342_9C5A_F0F9BA26FA75__INCLUDED_)

#define AFX_WSQVIEW_H__CF299264_8764_4342_9C5A_F0F9BA26FA75__INCLUDED_


#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000


#include "gl\gl.h"    //包含gl.h库

#include "gl\glu.h"   //包含glu.h库

#include "gl\glaux.h" //包含OpenGL实用库

#pragma comment( lib, "opengl32.lib")   //链接OpenGL库

#pragma comment( lib, "glu32.lib")

#pragma comment( lib, "glaux.lib")


struct ColorPoint         //定义结构体

{

float x,y;//坐标

float size;

float color[3]; //颜色

int life;

    

};


class CWsqView : public CView

{

protected: // create from serialization only

CWsqView();

DECLARE_DYNCREATE(CWsqView)


// Attributes

public:

CWsqDoc* GetDocument();


// Operations

public:

virtual void OnDraw(CDC* pDC);  // overridden to draw this view

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:

virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CWsqView)



//}}AFX_VIRTUAL

public:

void LoadTextures(); //读入纹理

void DrawScene(); //绘制场景

// void DrawOtherScene();

//初始化Opengl相关

BOOL CreateViewGLContext(HDC hDC); //创建绘制环境并使之成为当前绘制环境

BOOL SetWindowPixelFormat(HDC hDC);      //像素格式


HWND m_hWnd;      //窗口句柄

HDC m_hDC;            //设备描述表

    HGLRC m_hGLContext;  //图形操作描述表

int m_GLPixelIndex;

GLuint m_texture[10]; //纹理10个

int m_iWindowWidth,m_iWindowHeight; //窗口大小

bool m_bKey[256];

bool m_LeftButtonDown;

//    virtual BOOL OnNewDocument();


CPoint m_MousePos;      //鼠标...

// DWORD   m_iFrame;        //帧


int m_iSimStartPoint;    //模拟起始点

int m_iDrawStartPoint;   //开始画的点

int m_iPointNum;         //点的数量

float m_fPointSize;      //点的大小

float m_Color[3];        //点的颜色

   

//    bool m_bSpread;

bool m_bBrush;

ColorPoint m_ColorPoint[10000];


int m_ImageWidth;

int m_ImageHeight;

// Implementation

public:

virtual ~CWsqView();

    void Spread();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif


protected:


// Generated message map functions

protected:

    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

afx_msg void OnDestroy();

afx_msg void OnSize(UINT nType, int cx, int cy);

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

afx_msg void OnMouseMove(UINT nFlags, CPoint point);

afx_msg void OnTimer(UINT nIDEvent);

afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);

afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);

//{{AFX_MSG(CWsqView)


// NOTE - the ClassWizard will add and remove member functions here.

//    DO NOT EDIT what you see in these blocks of generated code !

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};


#ifndef _DEBUG  // debug version in wsqView.cpp

inline CWsqDoc* CWsqView::GetDocument()

   { return (CWsqDoc*)m_pDocument; }

#endif


/////////////////////////////////////////////////////////////////////////////


//`AFX_INSERT_LOCATION`

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.


#endif // !defined(AFX_WSQVIEW_H__CF299264_8764_4342_9C5A_F0F9BA26FA75__INCLUDED_)

=============================================================

// wsqView.cpp : implementation of the CWsqView class

//


#include "stdafx.h"

#include "wsq.h"


#include "wsqDoc.h"

#include "wsqView.h"

#include <MATH.H>


#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif


/////////////////////////////////////////////////////////////////////////////

// CWsqView

CView* g_pView;

bool resetView = false;

IMPLEMENT_DYNCREATE(CWsqView, CView)

//消息隐射

BEGIN_MESSAGE_MAP(CWsqView, CView)

//{{AFX_MSG_MAP(CWsqView)


//}}AFX_MSG_MAP

// Standard printing commands

ON_WM_CREATE()

ON_WM_DESTROY()

ON_WM_SIZE()

ON_WM_LBUTTONDOWN()

ON_WM_LBUTTONUP()

ON_WM_MOUSEMOVE()

ON_WM_TIMER()

ON_WM_KEYDOWN()

ON_WM_KEYUP()

ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)

//    ON_COMMAND(ID_FILE_NEW, CView::OnFileNew)

END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////

// CWsqView construction/destruction

BYTE tempdata[1024*1024*3]; //零时数据大小

CWsqView::CWsqView()

{

// TODO: add construction code here

m_LeftButtonDown = false;    //初始化

for(int i=0;i<256;i++)

{

m_bKey[i]=false;

}

m_iPointNum = 0;

m_iSimStartPoint = 0;

m_iDrawStartPoint = 0;

m_fPointSize = 0;

m_Color[0]=1.0;

m_Color[1]=1.0;

m_Color[2]=1.0;

    int life = 0;

m_bBrush = true;


}


CWsqView::~CWsqView()

{

}


BOOL CWsqView::PreCreateWindow(CREATESTRUCT& cs)

{

    cs.style|=WS_CLIPSIBLINGS|WS_CLIPCHILDREN;     //指定窗口风格


return CView::PreCreateWindow(cs);

}


/////////////////////////////////////////////////////////////////////////////

// CWsqView drawing


void CWsqView::OnDraw(CDC* pDC) //绘图函数

{

CWsqDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);


if(resetView)

{

m_iSimStartPoint=m_iDrawStartPoint=m_iPointNum=0;//初始化

resetView = false;

}

// TODO: add draw code for native data here


if(pDoc->m_bImageChanged)                    //使得可以新建一个画图区

{

glBindTexture(GL_TEXTURE_2D,m_texture[1]);  

m_ImageWidth=pDoc->m_ImageWidth;

m_ImageHeight=pDoc->m_ImageHeight;//纹理贴图

//        if(m_bKey[VK_TAB])

//            pDoc->m_bImageChanged = true;

glTexSubImage2D(GL_TEXTURE_2D,    //子纹理

           0,

512-m_ImageWidth/2,

512-m_ImageHeight/2,

m_ImageWidth,

m_ImageHeight,

GL_RGB,

GL_UNSIGNED_BYTE,

pDoc->m_pImage);//定义一个存在的二维纹理图像的一部分,但不能定义新的纹理

pDoc->m_bImageChanged = false;

//        if(m_bKey[VK_TAB])

//          pDoc->m_bImageChanged = true;

}

DrawScene();

//       if(m_bKey[VK_TAB])

//          pDoc->m_bImageChanged = true;

//    Spread();

    SetTimer(0,30,NULL); //定时30毫秒


SwapBuffers(m_hDC); //切换缓冲区  启用用双缓冲

}


/////////////////////////////////////////////////////////////////////////////

// CWsqView printing

//打印

BOOL CWsqView::OnPreparePrinting(CPrintInfo* pInfo)

{

// default preparation

return DoPreparePrinting(pInfo);

}

//重新打印

void CWsqView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add extra initialization before printing

}


void CWsqView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add cleanup after printing

}


/////////////////////////////////////////////////////////////////////////////

// CWsqView diagnostics


#ifdef _DEBUG

void CWsqView::AssertValid() const

{

CView::AssertValid();

}


void CWsqView::Dump(CDumpContext& dc) const

{

CView::Dump(dc);

}


CWsqDoc* CWsqView::GetDocument() // non-debug version is inline

{

ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CWsqDoc)));

return (CWsqDoc*)m_pDocument;

}

#endif //_DEBUG


/////////////////////////////////////////////////////////////////////////////

// CWsqView message handlers

BOOL CWsqView::SetWindowPixelFormat(HDC hDC)

{

PIXELFORMATDESCRIPTOR pixelDesc; //像素图结构体

pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR); //说明该数据结构的长度

pixelDesc.nVersion = 1;  //说明该数据结构的版本

pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |

PFD_DOUBLEBUFFER | PFD_STEREO_DONTCARE;  //指定像素缓存的属性:支持window,支持OpenGL,像素存为双缓存、立方体结构。

pixelDesc.iPixelType = PFD_TYPE_RGBA; // 指定RGBA模式

pixelDesc.cColorBits = 32;      //说明颜色缓存中颜色位平面的个数

pixelDesc.cRedBits = 0;         

pixelDesc.cRedShift = 0;

pixelDesc.cGreenBits = 0;

pixelDesc.cGreenShift = 0;

pixelDesc.cBlueBits = 0;

pixelDesc.cBlueShift = 0;

pixelDesc.cAlphaBits = 0;

pixelDesc.cAlphaShift = 0;

pixelDesc.cAccumBits = 64;       //说明累积缓存位平面的个数

pixelDesc.cAccumRedBits = 0;

pixelDesc.cAccumGreenBits = 0;

pixelDesc.cAccumBlueBits = 0;

pixelDesc.cAccumAlphaBits = 0;

pixelDesc.cDepthBits = 32;      //说明模板缓存的位数

pixelDesc.cStencilBits = 8;    //说明模板缓存的位数

pixelDesc.cAuxBuffers = 0;     //说明辅助缓存的个数

pixelDesc.iLayerType = PFD_MAIN_PLANE;

pixelDesc.bReserved = 0;

pixelDesc.dwLayerMask = 0;

pixelDesc.dwVisibleMask = 0;

pixelDesc.dwDamageMask = 0;

m_GLPixelIndex = ChoosePixelFormat(hDC,&pixelDesc);

if(m_GLPixelIndex == 0) // Choose default

{

m_GLPixelIndex = 1;

if(DescribePixelFormat(hDC,m_GLPixelIndex,

sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0)

return FALSE;

}

if(!SetPixelFormat(hDC,m_GLPixelIndex,&pixelDesc))

return FALSE;

return TRUE;

}



BOOL CWsqView::CreateViewGLContext(HDC hDC)

{

m_hGLContext = wglCreateContext(hDC); //创建RC

if(m_hGLContext==NULL)   //创建失败


return FALSE;

if(wglMakeCurrent(hDC,m_hGLContext)==FALSE)  //选为当前RC失败


return FALSE;

return TRUE;

}


void CWsqView::LoadTextures()   //载入纹理

{

AUX_RGBImageRec *TextureImage; //颜色对象

TextureImage = auxDIBImageLoad(_T("Data/tree.bmp")); //载入bmp图,并转换为纹理

glGenTextures(1,&m_texture[0]);   // 创建一个新纹理

glBindTexture(GL_TEXTURE_2D,m_texture[0]); //关联一个纹理

//设定纹理参数

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); // 创建使用线性Mipmap过滤器过滤得纹理,即使用线性插值计算两个图像中的每个图像的纹素值,然后在两个图像间进行线性插值

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); //放大、缩小纹理滤波

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);  //使用重复贴图

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);

gluBuild2DMipmaps(GL_TEXTURE_2D,3,TextureImage->sizeX,TextureImage->sizeY,GL_RGB,GL_UNSIGNED_BYTE,TextureImage->data);//创建二维多重映射

//glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);

    

free(TextureImage->data); //释放数据

free(TextureImage); //释放纹理对象


TextureImage = auxDIBImageLoad(_T("Data/Terrain.bmp")); //载入bmp图,并转换为纹理

glGenTextures(1,&m_texture[1]);// 创建纹理

glBindTexture(GL_TEXTURE_2D,m_texture[1]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // 创建使用临近过滤器过滤得纹理,选择最接近像素中心的纹素进行放大或缩小

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);//不使用重复贴图

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);

gluBuild2DMipmaps(GL_TEXTURE_2D,3,1024,1024,GL_RGB,GL_UNSIGNED_BYTE,tempdata); //定义分辨率逐渐减小到2*2的多重图像,并将原图缩放到最接近2的幂次方的尺寸上

// glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);

free(TextureImage->data);

free(TextureImage);


TextureImage = auxDIBImageLoad(_T("Data/grass1.bmp")); //载入bmp图,并转换为纹理

glGenTextures(1,&m_texture[2]);   // 创建纹理

glBindTexture(GL_TEXTURE_2D,m_texture[2]);


free(TextureImage->data);

free(TextureImage);


TextureImage = auxDIBImageLoad(_T("Data/Butterfly3.bmp")); //载入bmp图,并转换为纹理

glGenTextures(1,&m_texture[3]);// 创建纹理

glBindTexture(GL_TEXTURE_2D,m_texture[3]);

gluBuild2DMipmaps(GL_TEXTURE_2D,3,1024,1024,GL_RGB,GL_UNSIGNED_BYTE,tempdata); //定义分辨率逐渐减小到2*2的多重图像,并将原图缩放到最接近2的幂次方的尺寸上

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);

free(TextureImage->data);

free(TextureImage);



 /*       int Status=FALSE; // Status Indicator

        AUX_RGBImageRec *TextureImage[4]; // Create Storage Space For The Textures

        memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL


        if (TextureImage[0]=LoadBMP("Data/Particle.bmp")) // Load Particle Texture

        {

Status=TRUE; // Set The Status To TRUE

glGenTextures(1, &texture[0]); // Create One Texture


glBindTexture(GL_TEXTURE_2D, texture[0]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

        }

        if (TextureImage[1]=LoadBMP("Data/grass1.bmp")) // Load Particle Texture

        {

Status=TRUE; // Set The Status To TRUE

glGenTextures(1, &texture[1]); // Create One Texture


glBindTexture(GL_TEXTURE_2D, texture[1]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, 1024, 1024, 0, GL_RGB, GL_UNSIGNED_BYTE, tempdata);

        }

        if (TextureImage[2]=LoadBMP("Data/Terrain.bmp")) // Load Particle Texture

        {

Status=TRUE; // Set The Status To TRUE

glGenTextures(1, &texture[2]); // Create One Texture


glBindTexture(GL_TEXTURE_2D, texture[2]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[2]->sizeX, TextureImage[2]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[2]->data);

        }

        if (TextureImage[3]=LoadBMP("Data/tree.bmp")) // Load Particle Texture

        {

Status=TRUE; // Set The Status To TRUE

glGenTextures(1, &texture[3]); // Create One Texture


glBindTexture(GL_TEXTURE_2D, texture[3]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[3]->sizeX, TextureImage[3]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[3]->data);

        }


        if (TextureImage[0]) // If Texture Exists

{

if (TextureImage[0]->data) // If Texture Image Exists

{

free(TextureImage[0]->data); // Free The Texture Image Memory

}

free(TextureImage[0]); // Free The Image Structure

}

        if (TextureImage[1]) // If Texture Exists

{

if (TextureImage[1]->data) // If Texture Image Exists

{

free(TextureImage[1]->data); // Free The Texture Image Memory

}

free(TextureImage[1]); // Free The Image Structure

}

        if (TextureImage[2]) // If Texture Exists

{

if (TextureImage[2]->data) // If Texture Image Exists

{

free(TextureImage[2]->data); // Free The Texture Image Memory

}

free(TextureImage[2]); // Free The Image Structure

}

        if (TextureImage[3]) // If Texture Exists

{

if (TextureImage[3]->data) // If Texture Image Exists

{

free(TextureImage[3]->data); // Free The Texture Image Memory

}

free(TextureImage[3]); // Free The Image Structure

}

        return Status; */ // Return The Status

}


void CWsqView::DrawScene()//绘制场景

{

int pNum;

glClearColor(0,0,0,0);    //设置背景颜色

// if(m_bKey[VK_TAB])

// glClear(GL_COLOR_BUFFER_BIT);

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存

glLoadIdentity();         //重置当前的模型观察矩阵

glEnable(GL_TEXTURE_2D);  //启用二维纹理映射


glBindTexture(GL_TEXTURE_2D,m_texture[1]); //创建纹理


glColor3f(1,1,1);    //设置颜色为白色

glBegin(GL_QUADS);   //绘制四边形

glTexCoord2f(0,0);   //设定当前纹理坐标

glVertex2f(-512,-512); //指定顶点,即纹理坐标(0,0)被映射到物体顶点(-512,-512)上

// glColor3f(1.0,0.0,0.0);

glTexCoord2f(0,1);   //设定当前纹理坐标

glVertex2f(-512,512);   //指定顶点

// glColor3f(0.0,1.0,0.0);

glTexCoord2f(1,1);

glVertex2f(512,512);

// glColor3f(0.0,0.0,1.0);

glTexCoord2f(1,0);

glVertex2f(512,-512);

// glColor3f(1.0,0.0,0.0);

glEnd();             //关闭纹理映射


glEnable(GL_BLEND);  //启用混色效果

if(m_bBrush)

// glBlendFunc(GL_ONE,GL_ONE);// 当画刷为真时具体混色方案,第一个参数是源融合因子,后一个是目标融合因子

        glBlendFunc(GL_SRC_ALPHA,GL_ONE);

else

glBlendFunc(GL_SRC_COLOR,GL_ONE_MINUS_SRC_COLOR); //当画刷不为真时,采用另一种混色方案


glBindTexture(GL_TEXTURE_2D,m_texture[0]);

    glBegin(GL_TRIANGLES);

// glBegin(GL_QUADS);

for(int i=m_iDrawStartPoint;i<m_iSimStartPoint;i++)

{

pNum = i%10000;

glColor3fv(m_ColorPoint[pNum].color);

glTexCoord2f(0,0);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

glTexCoord2f(0,0.5);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

glTexCoord2f(0.5,0.5);

glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

// glTexCoord2f(1,0);

// glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

}

glEnd();


glBindTexture(GL_TEXTURE_2D,m_texture[1]);

glCopyTexSubImage2D(GL_TEXTURE_2D,0,512-m_iWindowWidth/2,512-m_iWindowHeight/2,0,0,m_iWindowWidth,m_iWindowHeight);

m_iDrawStartPoint=m_iSimStartPoint;


glBindTexture(GL_TEXTURE_2D,m_texture[0]);

// glBegin(GL_QUADS);

    glBegin(GL_TRIANGLES);

for(int i=m_iSimStartPoint;i<m_iPointNum;i++)

{

pNum = i%10000;

glColor3fv(m_ColorPoint[pNum].color);

//glTexCoord2f(0,0);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

//glTexCoord2f(0,0.5);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

//glTexCoord2f(0.5,0.5);

glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

// glTexCoord2f(1,0);

// glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

}

glEnd();



glDisable(GL_TEXTURE_2D);

glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ZERO);

if(m_bKey[VK_TAB])

   glColor3f(0.9,0.9,0.8);

else

  glColor3f(1.0,1.0,1.0);

//    Spread();


glBegin(GL_QUADS);

glVertex2f(-m_iWindowWidth/2,-m_iWindowHeight/2);

glVertex2f(m_iWindowWidth/2,-m_iWindowHeight/2);

glVertex2f(m_iWindowWidth/2,m_iWindowHeight/2);

glVertex2f(-m_iWindowWidth/2,m_iWindowHeight/2);

glEnd();

glDisable(GL_BLEND);

}


/*void CWsqView::DrawOtherScene()  其他场景绘制

{

int pNum;

glClearColor(0,0,0,0);    //设置背景颜色

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存

glLoadIdentity();         //重置当前的模型观察矩阵

glEnable(GL_TEXTURE_2D);  //启用二维纹理映射


glBindTexture(GL_TEXTURE_2D,m_texture[1]); //创建纹理


glColor3f(1,1,1);    //设置颜色为白色

glBegin(GL_QUADS);   //绘制四边形

glTexCoord2f(0,0);   //设定当前纹理坐标

glVertex2f(-512,-512); //指定顶点,即纹理坐标(0,0)被映射到物体顶点(-512,-512)上

// glColor3f(1.0,0.0,0.0);

glTexCoord2f(0,1);   //设定当前纹理坐标

glVertex2f(-512,512);   //指定顶点

// glColor3f(0.0,1.0,0.0);

glTexCoord2f(1,1);

glVertex2f(512,512);

// glColor3f(0.0,0.0,1.0);

glTexCoord2f(1,0);

glVertex2f(512,-512);

// glColor3f(1.0,0.0,0.0);

glEnd();             //关闭纹理映射


glEnable(GL_BLEND);  //启用混色效果

if(m_bBrush)

// glBlendFunc(GL_ONE,GL_ONE);// 当画刷为真时具体混色方案,第一个参数是源融合因子,后一个是目标融合因子

        glBlendFunc(GL_SRC_ALPHA,GL_ONE);

else

glBlendFunc(GL_SRC_COLOR,GL_ONE_MINUS_SRC_COLOR); //当画刷不为真时,采用另一种混色方案


glBindTexture(GL_TEXTURE_2D,m_texture[0]);

    glBegin(GL_TRIANGLES);

// glBegin(GL_QUADS);

for(int i=m_iDrawStartPoint;i<m_iSimStartPoint;i++)

{

pNum = i%10000;

glColor3fv(m_ColorPoint[pNum].color);

glTexCoord2f(0,0);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

glTexCoord2f(0,0.5);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

glTexCoord2f(0.5,0.5);

glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

// glTexCoord2f(1,0);

// glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

}

glEnd();


glBindTexture(GL_TEXTURE_2D,m_texture[1]);

glCopyTexSubImage2D(GL_TEXTURE_2D,0,512-m_iWindowWidth/2,512-m_iWindowHeight/2,0,0,m_iWindowWidth,m_iWindowHeight);

m_iDrawStartPoint=m_iSimStartPoint;


glBindTexture(GL_TEXTURE_2D,m_texture[0]);

// glBegin(GL_QUADS);

    glBegin(GL_TRIANGLES);

for(i=m_iSimStartPoint;i<m_iPointNum;i++)

{

pNum = i%10000;

glColor3fv(m_ColorPoint[pNum].color);

glTexCoord2f(0,0);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

glTexCoord2f(0,0.5);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

glTexCoord2f(0.5,0.5);

glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

// glTexCoord2f(1,0);

// glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

}

glEnd();



glDisable(GL_TEXTURE_2D);

glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ZERO);

// glColor3f(0.9,0.9,0.8);

glColor3f(1.0,1.0,1.0);

glBegin(GL_QUADS);

glVertex2f(-m_iWindowWidth/2,-m_iWindowHeight/2);

glVertex2f(m_iWindowWidth/2,-m_iWindowHeight/2);

glVertex2f(m_iWindowWidth/2,m_iWindowHeight/2);

glVertex2f(-m_iWindowWidth/2,m_iWindowHeight/2);

glEnd();

glDisable(GL_BLEND);

}*/


int CWsqView::OnCreate(LPCREATESTRUCT lpCreateStruct) 

{

if (CView::OnCreate(lpCreateStruct) == -1)

return -1;

g_pView = (CView*)this;

// TODO: Add your specialized creation code here

m_hWnd = GetSafeHwnd();  

m_hDC = ::GetDC(m_hWnd); //取得设备描述表

if(SetWindowPixelFormat(m_hDC)==FALSE)

return 0;

if(CreateViewGLContext(m_hDC)==FALSE)

return 0;

LoadTextures(); //调用载入纹理函数

    if(m_bKey[VK_TAB])

glClear(GL_COLOR_BUFFER_BIT);

// SetTimer(0,30,NULL);

//    Spread();

return 0;

}


void CWsqView::OnDestroy() 

{

CView::OnDestroy();

// TODO: Add your message handler code here

if(wglGetCurrentContext() != NULL)

wglMakeCurrent(NULL,NULL);

if(m_hGLContext != NULL)

{

wglDeleteContext(m_hGLContext);

m_hGLContext = NULL;

}

}


void CWsqView::OnSize(UINT nType, int cx, int cy) 

{

CView::OnSize(nType, cx, cy);

// TODO: Add your message handler code here

m_hWnd = GetSafeHwnd();  

m_hDC = ::GetDC(m_hWnd); //取得设备描述表

m_iWindowWidth = cx;

m_iWindowHeight = cy;

if(m_iWindowWidth < 10)

m_iWindowWidth = 10;

if(m_iWindowHeight < 10)

m_iWindowHeight = 10;

glViewport(0, 0, m_iWindowWidth, m_iWindowHeight);  //设定视口

glMatrixMode(GL_PROJECTION);//指定哪一个矩阵是当前矩阵,对投影矩阵堆栈用随后的的矩阵操作

glLoadIdentity();

glOrtho(-m_iWindowWidth/2,m_iWindowWidth/2,-m_iWindowHeight/2,m_iWindowHeight/2,-100,100);   

glMatrixMode(GL_MODELVIEW);//对模型视景矩阵堆栈应用随后的矩阵操作

}


void CWsqView::OnLButtonDown(UINT nFlags, CPoint point) //毛笔的捕捉

{

// TODO: Add your message handler code here and/or call default

m_LeftButtonDown = true;

m_fPointSize=1;

CView::OnLButtonDown(nFlags, point);

}


void CWsqView::OnLButtonUp(UINT nFlags, CPoint point) 

{

// TODO: Add your message handler code here and/or call default

m_LeftButtonDown = false;




/*if(m_iPointNum>50)

{

for(int i=m_iPointNum-50;i<m_iPointNum;i++)

{

int pNum = m_iPointNum%10000;

if(m_ColorPoint[i].size>(m_iPointNum-i)/5)

m_ColorPoint[i].size=(m_iPointNum-i)/5;

}

}*/

CView::OnLButtonUp(nFlags, point);

}





void CWsqView::OnMouseMove(UINT nFlags, CPoint point) //毛笔的移动

{

// TODO: Add your message handler code here and/or call default

if(m_fPointSize>0)

{

float dx=(CPoint(m_MousePos-point)).x;

float dy=(CPoint(m_MousePos-point)).y;

float l=sqrt(dx*dx+dy*dy);

for(int i=0;i<int(l)+1;i++)

{

int pNum = m_iPointNum%10000;

m_ColorPoint[pNum].x=m_MousePos.x-m_iWindowWidth/2+dx/l*i;

m_ColorPoint[pNum].y=m_iWindowHeight/2-m_MousePos.y-dy/l*i;

m_ColorPoint[pNum].size=m_fPointSize;


for(int j=0;j<3;j++)

{

m_ColorPoint[pNum].color[j]=m_Color[j];

}


m_ColorPoint[pNum].life=30;

m_iPointNum++;


}

if(m_LeftButtonDown)

{

m_fPointSize-=(l-5)/10;

if(m_fPointSize>8)

m_fPointSize=8;

if(m_fPointSize<2)

m_fPointSize=2;

}

//      Invalidate(0);


}

m_MousePos = point;

CView::OnMouseMove(nFlags, point);

}


void CWsqView::Spread()   //毛笔写到纸上产生的蔓延开的效果

{

if(m_bKey[VK_TAB])

  for(int i=m_iSimStartPoint;i<m_iPointNum;i++)

 {

int pNum = i%10000;

m_ColorPoint[pNum].size*=1.01;

m_ColorPoint[pNum].color[0]-=0.001;

m_ColorPoint[pNum].color[1]-=0.001;

m_ColorPoint[pNum].color[2]-=0.001;

m_ColorPoint[pNum].life--;

if(m_ColorPoint[pNum].life<=0)

m_iSimStartPoint = i+1;

 }

}


void CWsqView::OnTimer(UINT nIDEvent) 

{

// TODO: Add your message handler code here and/or call default


if(!m_LeftButtonDown)

{

m_fPointSize-=(1+0.3*m_fPointSize);

if(m_fPointSize<0)

m_fPointSize=0;

}


Spread();

Invalidate(0);

 //   if(m_bKey[VK_TAB])

//    SetTimer(3000,6000,NULL);

/* if(!m_LeftButtonDown)

{

m_fPointSize-=(1+0.3*m_fPointSize);

if(m_fPointSize<0)

m_fPointSize=0;

}

        Invalidate(0);*/

CView::OnTimer(nIDEvent);

}


void CWsqView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 

{

// TODO: Add your message handler code here and/or call default

m_bKey[nChar]=true;

switch(nChar) 

{

case '0':

        m_bKey[VK_TAB]=true;

        m_iSimStartPoint=m_iDrawStartPoint=m_iPointNum=0;

m_Color[0]=1;

m_Color[1]=1;

m_Color[2]=1;

break;

case '1':

        

m_Color[0]=0;

m_Color[1]=1;

m_Color[2]=1;

break;

case '2':

m_Color[0]=1;

m_Color[1]=0;

m_Color[2]=1;

break;

case '3':

m_Color[0]=1;

m_Color[1]=1;

m_Color[2]=0;

break;

case '4':

m_Color[0]=0;

m_Color[1]=0;

m_Color[2]=1;

break;

case '5':

m_Color[0]=1;

m_Color[1]=0;

m_Color[2]=0;

break;

case '6':

m_Color[0]=0;

m_Color[1]=1;

m_Color[2]=0;

break;

case '7':

m_Color[0]=0.2;

m_Color[1]=0.2;

m_Color[2]=0.2;

break;

case '8':

m_bKey[VK_TAB]=false;

m_Color[0]=1;

m_Color[1]=1;

m_Color[2]=1;

break;

case '9':

//        glBindTexture(GL_TEXTURE_2D,m_texture[3]);

//    DrawOtherScene();


m_Color[0]=0;

m_Color[1]=1;

m_Color[2]=1;

break;

case 'B':

m_bBrush = !m_bBrush;

default:

;

}

CView::OnKeyDown(nChar, nRepCnt, nFlags);

}


void CWsqView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 

{

// TODO: Add your message handler code here and/or call default

m_bKey[nChar]=false;

CView::OnKeyUp(nChar, nRepCnt, nFlags);

}

// wsqView.cpp : implementation of the CWsqView class

//


#include "stdafx.h"

#include "wsq.h"


#include "wsqDoc.h"

#include "wsqView.h"

#include <MATH.H>


#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif


/////////////////////////////////////////////////////////////////////////////

// CWsqView

CView* g_pView;

bool resetView = false;

IMPLEMENT_DYNCREATE(CWsqView, CView)

//消息隐射

BEGIN_MESSAGE_MAP(CWsqView, CView)

//{{AFX_MSG_MAP(CWsqView)


//}}AFX_MSG_MAP

// Standard printing commands

ON_WM_CREATE()

ON_WM_DESTROY()

ON_WM_SIZE()

ON_WM_LBUTTONDOWN()

ON_WM_LBUTTONUP()

ON_WM_MOUSEMOVE()

ON_WM_TIMER()

ON_WM_KEYDOWN()

ON_WM_KEYUP()

ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)

//    ON_COMMAND(ID_FILE_NEW, CView::OnFileNew)

END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////

// CWsqView construction/destruction

BYTE tempdata[1024*1024*3]; //零时数据大小

CWsqView::CWsqView()

{

// TODO: add construction code here

m_LeftButtonDown = false;    //初始化

for(int i=0;i<256;i++)

{

m_bKey[i]=false;

}

m_iPointNum = 0;

m_iSimStartPoint = 0;

m_iDrawStartPoint = 0;

m_fPointSize = 0;

m_Color[0]=1.0;

m_Color[1]=1.0;

m_Color[2]=1.0;

    int life = 0;

m_bBrush = true;


}


CWsqView::~CWsqView()

{

}


BOOL CWsqView::PreCreateWindow(CREATESTRUCT& cs)

{

    cs.style|=WS_CLIPSIBLINGS|WS_CLIPCHILDREN;     //指定窗口风格


return CView::PreCreateWindow(cs);

}


/////////////////////////////////////////////////////////////////////////////

// CWsqView drawing


void CWsqView::OnDraw(CDC* pDC) //绘图函数

{

CWsqDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);


if(resetView)

{

m_iSimStartPoint=m_iDrawStartPoint=m_iPointNum=0;//初始化

resetView = false;

}

// TODO: add draw code for native data here


if(pDoc->m_bImageChanged)                    //使得可以新建一个画图区

{

glBindTexture(GL_TEXTURE_2D,m_texture[1]);  

m_ImageWidth=pDoc->m_ImageWidth;

m_ImageHeight=pDoc->m_ImageHeight;//纹理贴图

//        if(m_bKey[VK_TAB])

//            pDoc->m_bImageChanged = true;

glTexSubImage2D(GL_TEXTURE_2D,    //子纹理

           0,

512-m_ImageWidth/2,

512-m_ImageHeight/2,

m_ImageWidth,

m_ImageHeight,

GL_RGB,

GL_UNSIGNED_BYTE,

pDoc->m_pImage);//定义一个存在的二维纹理图像的一部分,但不能定义新的纹理

pDoc->m_bImageChanged = false;

//        if(m_bKey[VK_TAB])

//          pDoc->m_bImageChanged = true;

}

DrawScene();

//       if(m_bKey[VK_TAB])

//          pDoc->m_bImageChanged = true;

//    Spread();

    SetTimer(0,30,NULL); //定时30毫秒


SwapBuffers(m_hDC); //切换缓冲区  启用用双缓冲

}


/////////////////////////////////////////////////////////////////////////////

// CWsqView printing

//打印

BOOL CWsqView::OnPreparePrinting(CPrintInfo* pInfo)

{

// default preparation

return DoPreparePrinting(pInfo);

}

//重新打印

void CWsqView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add extra initialization before printing

}


void CWsqView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add cleanup after printing

}


/////////////////////////////////////////////////////////////////////////////

// CWsqView diagnostics


#ifdef _DEBUG

void CWsqView::AssertValid() const

{

CView::AssertValid();

}


void CWsqView::Dump(CDumpContext& dc) const

{

CView::Dump(dc);

}


CWsqDoc* CWsqView::GetDocument() // non-debug version is inline

{

ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CWsqDoc)));

return (CWsqDoc*)m_pDocument;

}

#endif //_DEBUG


/////////////////////////////////////////////////////////////////////////////

// CWsqView message handlers

BOOL CWsqView::SetWindowPixelFormat(HDC hDC)

{

PIXELFORMATDESCRIPTOR pixelDesc; //像素图结构体

pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR); //说明该数据结构的长度

pixelDesc.nVersion = 1;  //说明该数据结构的版本

pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |

PFD_DOUBLEBUFFER | PFD_STEREO_DONTCARE;  //指定像素缓存的属性:支持window,支持OpenGL,像素存为双缓存、立方体结构。

pixelDesc.iPixelType = PFD_TYPE_RGBA; // 指定RGBA模式

pixelDesc.cColorBits = 32;      //说明颜色缓存中颜色位平面的个数

pixelDesc.cRedBits = 0;         

pixelDesc.cRedShift = 0;

pixelDesc.cGreenBits = 0;

pixelDesc.cGreenShift = 0;

pixelDesc.cBlueBits = 0;

pixelDesc.cBlueShift = 0;

pixelDesc.cAlphaBits = 0;

pixelDesc.cAlphaShift = 0;

pixelDesc.cAccumBits = 64;       //说明累积缓存位平面的个数

pixelDesc.cAccumRedBits = 0;

pixelDesc.cAccumGreenBits = 0;

pixelDesc.cAccumBlueBits = 0;

pixelDesc.cAccumAlphaBits = 0;

pixelDesc.cDepthBits = 32;      //说明模板缓存的位数

pixelDesc.cStencilBits = 8;    //说明模板缓存的位数

pixelDesc.cAuxBuffers = 0;     //说明辅助缓存的个数

pixelDesc.iLayerType = PFD_MAIN_PLANE;

pixelDesc.bReserved = 0;

pixelDesc.dwLayerMask = 0;

pixelDesc.dwVisibleMask = 0;

pixelDesc.dwDamageMask = 0;

m_GLPixelIndex = ChoosePixelFormat(hDC,&pixelDesc);

if(m_GLPixelIndex == 0) // Choose default

{

m_GLPixelIndex = 1;

if(DescribePixelFormat(hDC,m_GLPixelIndex,

sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)==0)

return FALSE;

}

if(!SetPixelFormat(hDC,m_GLPixelIndex,&pixelDesc))

return FALSE;

return TRUE;

}



BOOL CWsqView::CreateViewGLContext(HDC hDC)

{

m_hGLContext = wglCreateContext(hDC); //创建RC

if(m_hGLContext==NULL)   //创建失败


return FALSE;

if(wglMakeCurrent(hDC,m_hGLContext)==FALSE)  //选为当前RC失败


return FALSE;

return TRUE;

}


void CWsqView::LoadTextures()   //载入纹理

{

AUX_RGBImageRec *TextureImage; //颜色对象

TextureImage = auxDIBImageLoad(_T("Data/tree.bmp")); //载入bmp图,并转换为纹理

glGenTextures(1,&m_texture[0]);   // 创建一个新纹理

glBindTexture(GL_TEXTURE_2D,m_texture[0]); //关联一个纹理

//设定纹理参数

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); // 创建使用线性Mipmap过滤器过滤得纹理,即使用线性插值计算两个图像中的每个图像的纹素值,然后在两个图像间进行线性插值

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); //放大、缩小纹理滤波

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);  //使用重复贴图

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);

gluBuild2DMipmaps(GL_TEXTURE_2D,3,TextureImage->sizeX,TextureImage->sizeY,GL_RGB,GL_UNSIGNED_BYTE,TextureImage->data);//创建二维多重映射

//glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);

    

free(TextureImage->data); //释放数据

free(TextureImage); //释放纹理对象


TextureImage = auxDIBImageLoad(_T("Data/Terrain.bmp")); //载入bmp图,并转换为纹理

glGenTextures(1,&m_texture[1]);// 创建纹理

glBindTexture(GL_TEXTURE_2D,m_texture[1]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // 创建使用临近过滤器过滤得纹理,选择最接近像素中心的纹素进行放大或缩小

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);//不使用重复贴图

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);

gluBuild2DMipmaps(GL_TEXTURE_2D,3,1024,1024,GL_RGB,GL_UNSIGNED_BYTE,tempdata); //定义分辨率逐渐减小到2*2的多重图像,并将原图缩放到最接近2的幂次方的尺寸上

// glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);

free(TextureImage->data);

free(TextureImage);


TextureImage = auxDIBImageLoad(_T("Data/grass1.bmp")); //载入bmp图,并转换为纹理

glGenTextures(1,&m_texture[2]);   // 创建纹理

glBindTexture(GL_TEXTURE_2D,m_texture[2]);


free(TextureImage->data);

free(TextureImage);


TextureImage = auxDIBImageLoad(_T("Data/Butterfly3.bmp")); //载入bmp图,并转换为纹理

glGenTextures(1,&m_texture[3]);// 创建纹理

glBindTexture(GL_TEXTURE_2D,m_texture[3]);

gluBuild2DMipmaps(GL_TEXTURE_2D,3,1024,1024,GL_RGB,GL_UNSIGNED_BYTE,tempdata); //定义分辨率逐渐减小到2*2的多重图像,并将原图缩放到最接近2的幂次方的尺寸上

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);

free(TextureImage->data);

free(TextureImage);



 /*       int Status=FALSE; // Status Indicator

        AUX_RGBImageRec *TextureImage[4]; // Create Storage Space For The Textures

        memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL


        if (TextureImage[0]=LoadBMP("Data/Particle.bmp")) // Load Particle Texture

        {

Status=TRUE; // Set The Status To TRUE

glGenTextures(1, &texture[0]); // Create One Texture


glBindTexture(GL_TEXTURE_2D, texture[0]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

        }

        if (TextureImage[1]=LoadBMP("Data/grass1.bmp")) // Load Particle Texture

        {

Status=TRUE; // Set The Status To TRUE

glGenTextures(1, &texture[1]); // Create One Texture


glBindTexture(GL_TEXTURE_2D, texture[1]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, 1024, 1024, 0, GL_RGB, GL_UNSIGNED_BYTE, tempdata);

        }

        if (TextureImage[2]=LoadBMP("Data/Terrain.bmp")) // Load Particle Texture

        {

Status=TRUE; // Set The Status To TRUE

glGenTextures(1, &texture[2]); // Create One Texture


glBindTexture(GL_TEXTURE_2D, texture[2]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[2]->sizeX, TextureImage[2]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[2]->data);

        }

        if (TextureImage[3]=LoadBMP("Data/tree.bmp")) // Load Particle Texture

        {

Status=TRUE; // Set The Status To TRUE

glGenTextures(1, &texture[3]); // Create One Texture


glBindTexture(GL_TEXTURE_2D, texture[3]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[3]->sizeX, TextureImage[3]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[3]->data);

        }


        if (TextureImage[0]) // If Texture Exists

{

if (TextureImage[0]->data) // If Texture Image Exists

{

free(TextureImage[0]->data); // Free The Texture Image Memory

}

free(TextureImage[0]); // Free The Image Structure

}

        if (TextureImage[1]) // If Texture Exists

{

if (TextureImage[1]->data) // If Texture Image Exists

{

free(TextureImage[1]->data); // Free The Texture Image Memory

}

free(TextureImage[1]); // Free The Image Structure

}

        if (TextureImage[2]) // If Texture Exists

{

if (TextureImage[2]->data) // If Texture Image Exists

{

free(TextureImage[2]->data); // Free The Texture Image Memory

}

free(TextureImage[2]); // Free The Image Structure

}

        if (TextureImage[3]) // If Texture Exists

{

if (TextureImage[3]->data) // If Texture Image Exists

{

free(TextureImage[3]->data); // Free The Texture Image Memory

}

free(TextureImage[3]); // Free The Image Structure

}

        return Status; */ // Return The Status

}


void CWsqView::DrawScene()//绘制场景

{

int pNum;

glClearColor(0,0,0,0);    //设置背景颜色

// if(m_bKey[VK_TAB])

// glClear(GL_COLOR_BUFFER_BIT);

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存

glLoadIdentity();         //重置当前的模型观察矩阵

glEnable(GL_TEXTURE_2D);  //启用二维纹理映射


glBindTexture(GL_TEXTURE_2D,m_texture[1]); //创建纹理


glColor3f(1,1,1);    //设置颜色为白色

glBegin(GL_QUADS);   //绘制四边形

glTexCoord2f(0,0);   //设定当前纹理坐标

glVertex2f(-512,-512); //指定顶点,即纹理坐标(0,0)被映射到物体顶点(-512,-512)上

// glColor3f(1.0,0.0,0.0);

glTexCoord2f(0,1);   //设定当前纹理坐标

glVertex2f(-512,512);   //指定顶点

// glColor3f(0.0,1.0,0.0);

glTexCoord2f(1,1);

glVertex2f(512,512);

// glColor3f(0.0,0.0,1.0);

glTexCoord2f(1,0);

glVertex2f(512,-512);

// glColor3f(1.0,0.0,0.0);

glEnd();             //关闭纹理映射


glEnable(GL_BLEND);  //启用混色效果

if(m_bBrush)

// glBlendFunc(GL_ONE,GL_ONE);// 当画刷为真时具体混色方案,第一个参数是源融合因子,后一个是目标融合因子

        glBlendFunc(GL_SRC_ALPHA,GL_ONE);

else

glBlendFunc(GL_SRC_COLOR,GL_ONE_MINUS_SRC_COLOR); //当画刷不为真时,采用另一种混色方案


glBindTexture(GL_TEXTURE_2D,m_texture[0]);

    glBegin(GL_TRIANGLES);

// glBegin(GL_QUADS);

for(int i=m_iDrawStartPoint;i<m_iSimStartPoint;i++)

{

pNum = i%10000;

glColor3fv(m_ColorPoint[pNum].color);

glTexCoord2f(0,0);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

glTexCoord2f(0,0.5);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

glTexCoord2f(0.5,0.5);

glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

// glTexCoord2f(1,0);

// glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

}

glEnd();


glBindTexture(GL_TEXTURE_2D,m_texture[1]);

glCopyTexSubImage2D(GL_TEXTURE_2D,0,512-m_iWindowWidth/2,512-m_iWindowHeight/2,0,0,m_iWindowWidth,m_iWindowHeight);

m_iDrawStartPoint=m_iSimStartPoint;


glBindTexture(GL_TEXTURE_2D,m_texture[0]);

// glBegin(GL_QUADS);

    glBegin(GL_TRIANGLES);

for(int i=m_iSimStartPoint;i<m_iPointNum;i++)

{

pNum = i%10000;

glColor3fv(m_ColorPoint[pNum].color);

//glTexCoord2f(0,0);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

//glTexCoord2f(0,0.5);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

//glTexCoord2f(0.5,0.5);

glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

// glTexCoord2f(1,0);

// glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

}

glEnd();



glDisable(GL_TEXTURE_2D);

glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ZERO);

if(m_bKey[VK_TAB])

   glColor3f(0.9,0.9,0.8);

else

  glColor3f(1.0,1.0,1.0);

//    Spread();


glBegin(GL_QUADS);

glVertex2f(-m_iWindowWidth/2,-m_iWindowHeight/2);

glVertex2f(m_iWindowWidth/2,-m_iWindowHeight/2);

glVertex2f(m_iWindowWidth/2,m_iWindowHeight/2);

glVertex2f(-m_iWindowWidth/2,m_iWindowHeight/2);

glEnd();

glDisable(GL_BLEND);

}


/*void CWsqView::DrawOtherScene()  其他场景绘制

{

int pNum;

glClearColor(0,0,0,0);    //设置背景颜色

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存

glLoadIdentity();         //重置当前的模型观察矩阵

glEnable(GL_TEXTURE_2D);  //启用二维纹理映射


glBindTexture(GL_TEXTURE_2D,m_texture[1]); //创建纹理


glColor3f(1,1,1);    //设置颜色为白色

glBegin(GL_QUADS);   //绘制四边形

glTexCoord2f(0,0);   //设定当前纹理坐标

glVertex2f(-512,-512); //指定顶点,即纹理坐标(0,0)被映射到物体顶点(-512,-512)上

// glColor3f(1.0,0.0,0.0);

glTexCoord2f(0,1);   //设定当前纹理坐标

glVertex2f(-512,512);   //指定顶点

// glColor3f(0.0,1.0,0.0);

glTexCoord2f(1,1);

glVertex2f(512,512);

// glColor3f(0.0,0.0,1.0);

glTexCoord2f(1,0);

glVertex2f(512,-512);

// glColor3f(1.0,0.0,0.0);

glEnd();             //关闭纹理映射


glEnable(GL_BLEND);  //启用混色效果

if(m_bBrush)

// glBlendFunc(GL_ONE,GL_ONE);// 当画刷为真时具体混色方案,第一个参数是源融合因子,后一个是目标融合因子

        glBlendFunc(GL_SRC_ALPHA,GL_ONE);

else

glBlendFunc(GL_SRC_COLOR,GL_ONE_MINUS_SRC_COLOR); //当画刷不为真时,采用另一种混色方案


glBindTexture(GL_TEXTURE_2D,m_texture[0]);

    glBegin(GL_TRIANGLES);

// glBegin(GL_QUADS);

for(int i=m_iDrawStartPoint;i<m_iSimStartPoint;i++)

{

pNum = i%10000;

glColor3fv(m_ColorPoint[pNum].color);

glTexCoord2f(0,0);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

glTexCoord2f(0,0.5);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

glTexCoord2f(0.5,0.5);

glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

// glTexCoord2f(1,0);

// glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

}

glEnd();


glBindTexture(GL_TEXTURE_2D,m_texture[1]);

glCopyTexSubImage2D(GL_TEXTURE_2D,0,512-m_iWindowWidth/2,512-m_iWindowHeight/2,0,0,m_iWindowWidth,m_iWindowHeight);

m_iDrawStartPoint=m_iSimStartPoint;


glBindTexture(GL_TEXTURE_2D,m_texture[0]);

// glBegin(GL_QUADS);

    glBegin(GL_TRIANGLES);

for(i=m_iSimStartPoint;i<m_iPointNum;i++)

{

pNum = i%10000;

glColor3fv(m_ColorPoint[pNum].color);

glTexCoord2f(0,0);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

glTexCoord2f(0,0.5);

glVertex2f(m_ColorPoint[pNum].x-m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

glTexCoord2f(0.5,0.5);

glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y+m_ColorPoint[pNum].size);

// glTexCoord2f(1,0);

// glVertex2f(m_ColorPoint[pNum].x+m_ColorPoint[pNum].size,m_ColorPoint[pNum].y-m_ColorPoint[pNum].size);

}

glEnd();



glDisable(GL_TEXTURE_2D);

glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ZERO);

// glColor3f(0.9,0.9,0.8);

glColor3f(1.0,1.0,1.0);

glBegin(GL_QUADS);

glVertex2f(-m_iWindowWidth/2,-m_iWindowHeight/2);

glVertex2f(m_iWindowWidth/2,-m_iWindowHeight/2);

glVertex2f(m_iWindowWidth/2,m_iWindowHeight/2);

glVertex2f(-m_iWindowWidth/2,m_iWindowHeight/2);

glEnd();

glDisable(GL_BLEND);

}*/


int CWsqView::OnCreate(LPCREATESTRUCT lpCreateStruct) 

{

if (CView::OnCreate(lpCreateStruct) == -1)

return -1;

g_pView = (CView*)this;

// TODO: Add your specialized creation code here

m_hWnd = GetSafeHwnd();  

m_hDC = ::GetDC(m_hWnd); //取得设备描述表

if(SetWindowPixelFormat(m_hDC)==FALSE)

return 0;

if(CreateViewGLContext(m_hDC)==FALSE)

return 0;

LoadTextures(); //调用载入纹理函数

    if(m_bKey[VK_TAB])

glClear(GL_COLOR_BUFFER_BIT);

// SetTimer(0,30,NULL);

//    Spread();

return 0;

}


void CWsqView::OnDestroy() 

{

CView::OnDestroy();

// TODO: Add your message handler code here

if(wglGetCurrentContext() != NULL)

wglMakeCurrent(NULL,NULL);

if(m_hGLContext != NULL)

{

wglDeleteContext(m_hGLContext);

m_hGLContext = NULL;

}

}


void CWsqView::OnSize(UINT nType, int cx, int cy) 

{

CView::OnSize(nType, cx, cy);

// TODO: Add your message handler code here

m_hWnd = GetSafeHwnd();  

m_hDC = ::GetDC(m_hWnd); //取得设备描述表

m_iWindowWidth = cx;

m_iWindowHeight = cy;

if(m_iWindowWidth < 10)

m_iWindowWidth = 10;

if(m_iWindowHeight < 10)

m_iWindowHeight = 10;

glViewport(0, 0, m_iWindowWidth, m_iWindowHeight);  //设定视口

glMatrixMode(GL_PROJECTION);//指定哪一个矩阵是当前矩阵,对投影矩阵堆栈用随后的的矩阵操作

glLoadIdentity();

glOrtho(-m_iWindowWidth/2,m_iWindowWidth/2,-m_iWindowHeight/2,m_iWindowHeight/2,-100,100);   

glMatrixMode(GL_MODELVIEW);//对模型视景矩阵堆栈应用随后的矩阵操作

}


void CWsqView::OnLButtonDown(UINT nFlags, CPoint point) //毛笔的捕捉

{

// TODO: Add your message handler code here and/or call default

m_LeftButtonDown = true;

m_fPointSize=1;

CView::OnLButtonDown(nFlags, point);

}


void CWsqView::OnLButtonUp(UINT nFlags, CPoint point) 

{

// TODO: Add your message handler code here and/or call default

m_LeftButtonDown = false;




/*if(m_iPointNum>50)

{

for(int i=m_iPointNum-50;i<m_iPointNum;i++)

{

int pNum = m_iPointNum%10000;

if(m_ColorPoint[i].size>(m_iPointNum-i)/5)

m_ColorPoint[i].size=(m_iPointNum-i)/5;

}

}*/

CView::OnLButtonUp(nFlags, point);

}





void CWsqView::OnMouseMove(UINT nFlags, CPoint point) //毛笔的移动

{

// TODO: Add your message handler code here and/or call default

if(m_fPointSize>0)

{

float dx=(CPoint(m_MousePos-point)).x;

float dy=(CPoint(m_MousePos-point)).y;

float l=sqrt(dx*dx+dy*dy);

for(int i=0;i<int(l)+1;i++)

{

int pNum = m_iPointNum%10000;

m_ColorPoint[pNum].x=m_MousePos.x-m_iWindowWidth/2+dx/l*i;

m_ColorPoint[pNum].y=m_iWindowHeight/2-m_MousePos.y-dy/l*i;

m_ColorPoint[pNum].size=m_fPointSize;


for(int j=0;j<3;j++)

{

m_ColorPoint[pNum].color[j]=m_Color[j];

}


m_ColorPoint[pNum].life=30;

m_iPointNum++;


}

if(m_LeftButtonDown)

{

m_fPointSize-=(l-5)/10;

if(m_fPointSize>8)

m_fPointSize=8;

if(m_fPointSize<2)

m_fPointSize=2;

}

//      Invalidate(0);


}

m_MousePos = point;

CView::OnMouseMove(nFlags, point);

}


void CWsqView::Spread()   //毛笔写到纸上产生的蔓延开的效果

{

if(m_bKey[VK_TAB])

  for(int i=m_iSimStartPoint;i<m_iPointNum;i++)

 {

int pNum = i%10000;

m_ColorPoint[pNum].size*=1.01;

m_ColorPoint[pNum].color[0]-=0.001;

m_ColorPoint[pNum].color[1]-=0.001;

m_ColorPoint[pNum].color[2]-=0.001;

m_ColorPoint[pNum].life--;

if(m_ColorPoint[pNum].life<=0)

m_iSimStartPoint = i+1;

 }

}


void CWsqView::OnTimer(UINT nIDEvent) 

{

// TODO: Add your message handler code here and/or call default


if(!m_LeftButtonDown)

{

m_fPointSize-=(1+0.3*m_fPointSize);

if(m_fPointSize<0)

m_fPointSize=0;

}


Spread();

Invalidate(0);

 //   if(m_bKey[VK_TAB])

//    SetTimer(3000,6000,NULL);

/* if(!m_LeftButtonDown)

{

m_fPointSize-=(1+0.3*m_fPointSize);

if(m_fPointSize<0)

m_fPointSize=0;

}

        Invalidate(0);*/

CView::OnTimer(nIDEvent);

}


void CWsqView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 

{

// TODO: Add your message handler code here and/or call default

m_bKey[nChar]=true;

switch(nChar) 

{

case '0':

        m_bKey[VK_TAB]=true;

        m_iSimStartPoint=m_iDrawStartPoint=m_iPointNum=0;

m_Color[0]=1;

m_Color[1]=1;

m_Color[2]=1;

break;

case '1':

        

m_Color[0]=0;

m_Color[1]=1;

m_Color[2]=1;

break;

case '2':

m_Color[0]=1;

m_Color[1]=0;

m_Color[2]=1;

break;

case '3':

m_Color[0]=1;

m_Color[1]=1;

m_Color[2]=0;

break;

case '4':

m_Color[0]=0;

m_Color[1]=0;

m_Color[2]=1;

break;

case '5':

m_Color[0]=1;

m_Color[1]=0;

m_Color[2]=0;

break;

case '6':

m_Color[0]=0;

m_Color[1]=1;

m_Color[2]=0;

break;

case '7':

m_Color[0]=0.2;

m_Color[1]=0.2;

m_Color[2]=0.2;

break;

case '8':

m_bKey[VK_TAB]=false;

m_Color[0]=1;

m_Color[1]=1;

m_Color[2]=1;

break;

case '9':

//        glBindTexture(GL_TEXTURE_2D,m_texture[3]);

//    DrawOtherScene();


m_Color[0]=0;

m_Color[1]=1;

m_Color[2]=1;

break;

case 'B':

m_bBrush = !m_bBrush;

default:

;

}

CView::OnKeyDown(nChar, nRepCnt, nFlags);

}


void CWsqView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 

{

// TODO: Add your message handler code here and/or call default

m_bKey[nChar]=false;

CView::OnKeyUp(nChar, nRepCnt, nFlags);

}

------------------------------

调试一路下来了,赶紧看看结果,非常激动人心的时刻到来了

如何开发一个艺术笔_其他

由于自己写的不好,但是那些功能全部实现了,有毛笔字写的好一定发给我啊