如何开发一个艺术笔

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

既然学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);

}

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

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

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

时间: 2024-11-10 15:03:37

如何开发一个艺术笔的相关文章

【转】两天快速开发一个自己的微信小程序 悬笔e绝 www.xuanbiyijue.com

文章出处:https://www.cnblogs.com/xuanbiyijue/p/7980010.html 作者: 悬笔e绝 www.xuanbiyijue.com 两天快速开发一个自己的微信小程序 一.写在前面 1.为什么要学小程序开发? 对于前端开发而言,微信小程序因为其简单快速.开发成本低.用户流量巨大等特点,也就成了前端开发工程师必会的一个技能. 2.先放上我做的小程序 可以在微信小程序搜索“悬笔e绝”,或者用微信扫描下面的二维码哦 (1)欢迎页:这个logo是当年念大学给社团做的l

Java开发工程师上机笔试题

网上看到3道比较好的Java开发工程师上机笔试题,没有答案这里把答案写出来,给大家参考. 1.编一个程序,输入10个整数,并放在数组中,先降序输出所有的数,再统计并输出其中正数.负数和零的个数 package cn.Pigzhu.test; import java.util.Scanner; /**  * 控制台输入10个数字,并输入正负和零的个数  * @author xiaoyezhu  *  */ public class test { public static void main(St

Python开发一个简单的BBS论坛

项目:开发一个简单的BBS论坛 需求: 整体参考“抽屉新热榜” + “虎嗅网” 实现不同论坛版块 帖子列表展示 帖子评论数.点赞数展示 在线用户展示 允许登录用户发贴.评论.点赞 允许上传文件 帖子可被置顶 可进行多级评论 就先这些吧... 知识必备: Django HTML\CSS\JS BootStrap Jquery 设计表结构 1 # -*- coding:utf-8 -*- 2 from django.db import models 3 from django.contrib.aut

如何在cocos2d-x中使用ECS(实体-组件-系统)架构方法开发一个游戏?

引言 在我的博客中,我曾经翻译了几篇关于ECS的文章.这些文章都是来自于Game Development网站.如果你对这个架构方式还不是很了解的话,欢迎阅读理解 组件-实体-系统和实现 组件-实体-系统. 我发现这个架构方式,是在浏览GameDev上的文章的时候了解到的.很久以前,就知道了有这么个架构方法,只是一直没有机会自己实践下.这一次,我就抽空,根据网上对ECS系统的讨论,采用了一种实现方法,来实现一个. 我很喜欢做游戏,所以同样的,还是用游戏实例来实践这个架构方法.我将会采用cocos2

贝塞尔曲线开发的艺术

贝塞尔曲线开发的艺术 一句话概括贝塞尔曲线:将任意一条曲线转化为精确的数学公式. 很多绘图工具中的钢笔工具,就是典型的贝塞尔曲线的应用,这里的一个网站可以在线模拟钢笔工具的使用: http://bezier.method.ac/ 贝塞尔曲线中有一些比较关键的名词,解释如下: 数据点:通常指一条路径的起始点和终止点 控制点:控制点决定了一条路径的弯曲轨迹,根据控制点的个数,贝塞尔曲线被分为一阶贝塞尔曲线(0个控制点).二阶贝塞尔曲线(1个控制点).三阶贝塞尔曲线(2个控制点)等等. 要想对贝塞尔曲

【刘文彬】【精解】开发一个智能合约

原文链接:醒者呆的博客园,https://www.cnblogs.com/Evsward/p/contract.html 智能合约 这两天被老大搞去搬砖,学习计划有变但无大碍,这篇文章将仔细分析智能合约相关内容. 关键字:智能合约,remix,Solidity,truffle,geth,leveldb,datadir,ganache,web3j 合约 合约也称合同.协议,是甲乙双方参与的,制定一系列条目规范双方权利与义务的文件.智能合约是电子化的,自动执行的,去中心化的,具有不可抵赖性,本质上它

用python+django+twistd 开发一个属于自己的运维系统

开源的运维系统不少,比如nagios.zabbix.cati等等,但是遇到自己个性化的运维需求的时候,总是显的力不从心!最近在学习python,所以就考虑用python+django+twisted来定做一个完全个性化的运维系统. 运维系统有几个主要的功能:监控.分析.报警.更甚者直接根据分析的结果进行反应操作.而以上几点通过上述的框架可以比较容易的实现. 下面上图说明: 使用freemind整理了下思路: 下面是一些代码段,完整的代码下载见文档底部: Server: #!/usr/bin/en

【如何快速的开发一个完整的iOS直播app】(原理篇)

一.个人见解(直播难与易) 直播难:个人认为要想把直播从零开始做出来,绝对是牛逼中的牛逼,大牛中的大牛,因为直播中运用到的技术难点非常之多,视频/音频处理,图形处理,视频/音频压缩,CDN分发,即时通讯等技术,每一个技术都够你学几年的. 直播易:已经有各个领域的大牛,封装好了许多牛逼的框架,我们只需要用别人写好的框架,就能快速的搭建一个直播app,也就是传说中的站在大牛肩膀上编程. 二.了解直播 热门直播产品 映客,斗鱼,熊猫,虎牙,花椒等等 直播效果图 直播效果.jpeg 1.一个完整直播ap

【如何快速的开发一个完整的iOS直播app】(播放篇)

前言 在看这篇之前,如果您还不了解直播原理,请查看上篇文章如何快速的开发一个完整的iOS直播app(原理篇) 开发一款直播app,集成ijkplayer成功后,就算完成直播功能一半的工程了,只要有拉流url,就能播放直播啦 本篇主要讲解的是直播app中,需要用到的一个很重要的开源框架ijkplayer,然后集成这个框架可能对大多数初学者还是比较有难度的,所以本篇主要教你解决集成[ijkplayer]遇见的各种坑. 很多文章,可能讲解的是如何做,我比较注重讲解为什么这样做,大家有什么不明白,还可以