Directx11学习笔记【二十二】 用高度图实现地形
本文由zhangbaochong原创,转载请注明出处http://www.cnblogs.com/zhangbaochong/p/5827714.html
在前面我们曾经实现过简单的地形(Directx11学习笔记【十三】 实现一个简单地形),只不过原来使用一个固定的函数获得地形高度,这样跟真实的地形差距比较大。接下来让我们学习使用高度图来进行三维地形模拟。
1.高度图
高度图其实就是一组连续的数组,这个数组中的元素与地形网格中的顶点一一对应,且每一个元素都指定了地形网格的某个顶点的高度值。高度图最常用的使用灰度图实现,灰度图中亮度越大对应的地形高度越高。下面就是一幅灰度图:
灰度图格式通常为.raw,google一下高度图保存图片改为raw格式就可以了。高度图每个元素通常只分配一个字节,即数值在0~255之间。但在实际使用的时候经常要对高度进行比例变换,因此需要将byte转为float,然后通过一个缩放系数进行缩放,这样就不必拘泥于0~255这么一个范围了。
2.读取高度图
读取高度图很简单,用二进制读取文件就好了。
//读取高度图信息
bool TerrainDemo::ReadRawFile(std::string filePath)
{
std::ifstream inFile;
//二进制方式打开文件
inFile.open(filePath.c_str(), std::ios::binary);
//文件指针移动到末尾
inFile.seekg(, std::ios::end);
//大小为当前缓冲区大小
std::vector<BYTE> inData(inFile.tellg());
//文件指针移动到开头
inFile.seekg(std::ios::beg);
//读取高度信息
inFile.read((char*)&inData[], inData.size());
inFile.close(); m_heightInfos.resize(inData.size());
for (int i = ; i < inData.size(); ++i)
{
m_heightInfos[i] = inData[i];
} return true;
}
3.顶点和索引的计算
顶点和索引的计算同Directx11学习笔记【十三】 实现一个简单地形类似,这里就不再详细说明了。不一样的由于采用了纹理光照渲染,所以需要得到法线,在计算索引的同时需要把顶点法线计算出来:
//计算法线
void TerrainDemo::ComputeNomal(Vertex& v1, Vertex& v2, Vertex& v3, XMFLOAT3& normal)
{
XMFLOAT3 f1(v2.pos.x - v1.pos.x, v2.pos.y - v1.pos.y, v2.pos.z - v1.pos.z);
XMFLOAT3 f2(v3.pos.x - v1.pos.x, v3.pos.y - v1.pos.y, v3.pos.z - v1.pos.z);
XMVECTOR vec1 = XMLoadFloat3(&f1);
XMVECTOR vec2 = XMLoadFloat3(&f2);
XMVECTOR temp = XMVector3Normalize(XMVector3Cross(vec1, vec2));
XMStoreFloat3(&normal, temp);
}
计算顶点和索引:
bool TerrainDemo::InitTerrain(float width, float height, UINT m, UINT n,float scale)
{
m_cellsPerRow = m;
m_cellsPerCol = n;
m_verticesPerRow = m + ;
m_verticesPerCol = n + ;
m_numsVertices = m_verticesPerRow*m_verticesPerCol;
m_width = width;
m_height = height;
m_heightScale = scale; //得到缩放后的高度
for (auto& item : m_heightInfos)
{
item *= m_heightScale;
} //起始x z坐标
float oX = -width * 0.5f;
float oZ = height * 0.5f;
//每一格坐标变化
float dx = width / m;
float dz = height / n; m_vertices.resize(m_numsVertices);
//计算顶点
for (UINT i = ; i < m_verticesPerCol; ++i)
{
float tempZ = oZ - dz * i;
for (UINT j = ; j < m_verticesPerRow; ++j)
{
UINT index = m_verticesPerRow * i + j;
m_vertices[index].pos.x = oX + dx * j;
m_vertices[index].pos.y = m_heightInfos[index];
m_vertices[index].pos.z = tempZ; m_vertices[index].tex = XMFLOAT2(dx*i, dx*j);
}
} //计算索引和法线
//总格子数量:m * n
//因此总索引数量: 6 * m * n
UINT nIndices = m * n * ;
m_indices.resize(nIndices);
UINT tmp = ;
for (UINT i = ; i < n; ++i)
{
for (UINT j = ; j < m; ++j)
{
m_indices[tmp] = i * m_verticesPerRow + j;
m_indices[tmp + ] = i * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j; //计算法线
XMFLOAT3 temp;
ComputeNomal(m_vertices[m_indices[tmp]], m_vertices[m_indices[tmp + ]],
m_vertices[m_indices[tmp + ]], temp);
m_vertices[m_indices[tmp]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp; m_indices[tmp + ] = i * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j; ComputeNomal(m_vertices[m_indices[tmp + ]], m_vertices[m_indices[tmp + ]],
m_vertices[m_indices[tmp + ]], temp);
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp; tmp += ;
}
} return true;
}
4.效果截图
5.详细源码
TerrainDemo.h
#pragma once
#include <string>
#include <vector>
#include "Dx11Base.h"
#include "Camera.h"
#include "Input.h"
#include "Utility.h"
#include "LightHelper.h" class TerrainDemo : public Dx11Base
{
public:
TerrainDemo(HINSTANCE hInst, std::wstring title = L"TerrainDemo", int width = , int height = );
~TerrainDemo(); //顶点结构 位置、法线、uv坐标
struct Vertex
{
Vertex() {}
Vertex(const XMFLOAT3 _pos, XMFLOAT3 _normal, XMFLOAT2 _tex) :
pos(_pos), normal(_normal), tex(_tex) {} XMFLOAT3 pos;
XMFLOAT3 normal;
XMFLOAT2 tex;
}; bool Init() override;
void Update(float dt);
void Render(); bool OnResize() override;
private:
bool BuildBuffers();
bool BuildSRVs();
bool BuildInputLayouts();
void UpdateCamera(float dt);
private:
bool ReadRawFile(std::string filePath); //从高度图读取高度信息
bool InitTerrain(float width, float height, UINT m, UINT n, float scale); //初始化地形
void ComputeNomal(Vertex& v1, Vertex& v2, Vertex& v3, XMFLOAT3& normal); //计算法线
private:
std::vector<float> m_heightInfos; //高度图高度信息
int m_cellsPerRow; //每行单元格数
int m_cellsPerCol; //每列单元格数
int m_verticesPerRow; //每行顶点数
int m_verticesPerCol; //每列顶点数
int m_numsVertices; //顶点总数
float m_width; //地形宽度
float m_height; //地形高度
float m_heightScale; //高度缩放系数 std::vector<Vertex> m_vertices; //顶点集合
std::vector<UINT> m_indices; //索引集合 private:
ID3D11Buffer* m_pVertexBuffer;
ID3D11Buffer* m_pIndexBuffer;
ID3D11InputLayout* m_pInputLayout;
ID3D11ShaderResourceView* m_pSRVTerrain; Lights::DirectionalLight m_dirLights[]; //3个平行光源
Lights::Material m_materialTerrain; //材质 Camera m_camera; XMFLOAT4X4 m_world; //世界变换矩阵
XMFLOAT4X4 m_worldViewProj; //世界视角投影矩阵
XMFLOAT4X4 m_worldInvTranspose; //世界逆矩阵的转置,用于法线变换
XMFLOAT4X4 m_texTrans; //纹理坐标变换矩阵 POINT m_lastMousePos;
};
TerrainDemo.cpp
#include <fstream>
#include <memory>
#include "TerrainDemo.h"
#include "Utility.h"
#include "WICTextureLoader.h"
#include "d3dx11effect.h"
#include "Effects.h" TerrainDemo::TerrainDemo(HINSTANCE hInst, std::wstring title, int width, int height)
:Dx11Base(hInst, title, width, height)
{
//"三点式"照明
//主光源
m_dirLights[].ambient = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
m_dirLights[].diffuse = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
m_dirLights[].specular = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
m_dirLights[].direction = XMFLOAT3(0.57735f, -0.57735f, 0.57735f);
//侧光源
m_dirLights[].ambient = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
m_dirLights[].diffuse = XMFLOAT4(0.20f, 0.20f, 0.20f, 1.0f);
m_dirLights[].specular = XMFLOAT4(0.25f, 0.25f, 0.25f, 1.0f);
m_dirLights[].direction = XMFLOAT3(-0.57735f, -0.57735f, 0.57735f);
//背光源
m_dirLights[].ambient = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
m_dirLights[].diffuse = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
m_dirLights[].specular = XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
m_dirLights[].direction = XMFLOAT3(0.0f, -0.707f, -0.707f); //材质
m_materialTerrain.ambient = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
m_materialTerrain.diffuse = XMFLOAT4(.f, .f, .f, 1.0f);
m_materialTerrain.specular = XMFLOAT4(0.3f, 0.3f, 0.3f, 16.0f); //设置相机
m_lastMousePos = { , };
XMVECTOR Eye = XMVectorSet(0.0f, 50.0f, 0.1f, 0.0f);
XMVECTOR At = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
m_camera.LookAtXM(Eye, At, Up);
//设置投影矩阵
m_camera.SetLens(XM_PIDIV4, AspectRatio(), 0.1f, .f); //初始化世界矩阵 逆转置矩阵 及纹理坐标矩阵
//这些每一帧不改变
XMMATRIX I = XMMatrixIdentity();
XMStoreFloat4x4(&m_world, I);
XMVECTOR det = XMMatrixDeterminant(I);
XMMATRIX worldInvTranspose = XMMatrixTranspose(XMMatrixInverse(&det,I));
XMStoreFloat4x4(&m_worldInvTranspose, worldInvTranspose);
XMStoreFloat4x4(&m_texTrans, I);
} TerrainDemo::~TerrainDemo()
{
SafeRelease(m_pVertexBuffer);
SafeRelease(m_pIndexBuffer);
SafeRelease(m_pInputLayout);
SafeRelease(m_pSRVTerrain);
Effects::ReleaseAll();
} bool TerrainDemo::Init()
{
if (!Dx11Base::Init())
return false;
if (!Effects::InitAll(m_pd3dDevice))
return false;
if (!ReadRawFile("Texture\\heightmap.raw"))
return false;
if (!InitTerrain(, , , , 0.2f))
return false;
if (!BuildBuffers())
return false;
if (!BuildSRVs())
return false;
if (!BuildInputLayouts())
return false;
} void TerrainDemo::Update(float dt)
{
UpdateCamera(dt);
XMMATRIX world = XMLoadFloat4x4(&m_world);
XMMATRIX worldViewProj = world * m_camera.GetViewProj();
XMStoreFloat4x4(&m_worldViewProj, worldViewProj); //设置灯光
Effects::ms_pBasicEffect->m_pFxDirLights->SetRawValue(&m_dirLights, ,
* sizeof(Lights::DirectionalLight));
Effects::ms_pBasicEffect->m_pFxEyePos->SetRawValue(&m_camera.GetPosition(), ,
sizeof(m_camera.GetPosition()));
} void TerrainDemo::Render()
{
m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, Colors::Silver);
m_pImmediateContext->ClearDepthStencilView(m_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, );
m_pImmediateContext->IASetInputLayout(m_pInputLayout); UINT stride = sizeof(Vertex);
UINT offset = ;
m_pImmediateContext->IASetVertexBuffers(, , &m_pVertexBuffer, &stride, &offset);
m_pImmediateContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, offset);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); D3DX11_TECHNIQUE_DESC desc;
ID3DX11EffectTechnique* tech = Effects::ms_pBasicEffect->m_pFxLight3TexTech;
tech->GetDesc(&desc); for (UINT i = ; i < desc.Passes; ++i)
{
//设置着色器变量
Effects::ms_pBasicEffect->m_pFxWorld->SetMatrix(reinterpret_cast<const float*>(&m_world));
Effects::ms_pBasicEffect->m_pFxWorldViewProj->SetMatrix(reinterpret_cast<const float*>(
&m_worldViewProj));
Effects::ms_pBasicEffect->m_pFxWorldInvTranspose->SetMatrix(reinterpret_cast<const float*>(
&m_worldInvTranspose));
Effects::ms_pBasicEffect->m_pFxTexTrans->SetMatrix(reinterpret_cast<const float*>(
&m_texTrans));
Effects::ms_pBasicEffect->m_pFxMaterial->SetRawValue(&m_materialTerrain, , sizeof(m_materialTerrain));
Effects::ms_pBasicEffect->m_pFxSR->SetResource(m_pSRVTerrain);
tech->GetPassByIndex(i)->Apply(, m_pImmediateContext);
m_pImmediateContext->DrawIndexed(m_indices.size(), , );
} m_pSwapChain->Present(, );
} bool TerrainDemo::OnResize()
{
if (!Dx11Base::OnResize())
return false;
//更新camera参数
m_camera.SetLens(XM_PIDIV4, AspectRatio(), .f, .f); return true;
} bool TerrainDemo::BuildBuffers()
{
//创建顶点缓冲区
D3D11_BUFFER_DESC vertexDesc;
ZeroMemory(&vertexDesc, sizeof(vertexDesc));
vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexDesc.ByteWidth = sizeof(Vertex) * m_numsVertices;
vertexDesc.Usage = D3D11_USAGE_IMMUTABLE; D3D11_SUBRESOURCE_DATA vertexData;
vertexData.pSysMem = &m_vertices[];
vertexData.SysMemPitch = ;
vertexData.SysMemSlicePitch = ;
if (FAILED(m_pd3dDevice->CreateBuffer(&vertexDesc, &vertexData, &m_pVertexBuffer)))
{
MessageBox(nullptr, L"Create Vertex Buffer failed!", L"Error", MB_OK);
return false;
} //创建索引缓冲区
D3D11_BUFFER_DESC indexDesc;
ZeroMemory(&indexDesc, sizeof(indexDesc));
indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexDesc.ByteWidth = sizeof(UINT) * m_indices.size();
indexDesc.Usage = D3D11_USAGE_IMMUTABLE; D3D11_SUBRESOURCE_DATA indexData;
indexData.pSysMem = &m_indices[];
indexData.SysMemPitch = ;
indexData.SysMemSlicePitch = ;
if (FAILED(m_pd3dDevice->CreateBuffer(&indexDesc, &indexData, &m_pIndexBuffer)))
{
MessageBox(nullptr, L"Create Index Buffer failed!", L"Error", MB_OK);
return false;
} return true;
} bool TerrainDemo::BuildSRVs()
{
if (FAILED(CreateWICTextureFromFile(m_pd3dDevice, L"Texture\\desert.bmp", nullptr, &m_pSRVTerrain)))
{
MessageBox(nullptr, L"create texture failed!", L"error", MB_OK);
return false;
}
return true;
} bool TerrainDemo::BuildInputLayouts()
{
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", , DXGI_FORMAT_R32G32B32_FLOAT, , , D3D11_INPUT_PER_VERTEX_DATA, },
{ "NORMAL", , DXGI_FORMAT_R32G32B32_FLOAT, , ,D3D11_INPUT_PER_VERTEX_DATA, },
{ "TEXCOORD", , DXGI_FORMAT_R32G32_FLOAT, , ,D3D11_INPUT_PER_VERTEX_DATA, }
}; UINT numLayoutElements = ARRAYSIZE(layout);
D3DX11_PASS_DESC passDesc;
Effects::ms_pBasicEffect->m_pFxLight3TexTech->GetPassByIndex()->GetDesc(&passDesc);
if (FAILED(m_pd3dDevice->CreateInputLayout(layout, numLayoutElements, passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize, &m_pInputLayout)))
{
MessageBox(nullptr, L"create inputLayout failed!", L"error", MB_OK);
return false;
}
return true;
} void TerrainDemo::UpdateCamera(float dt)
{
//前后左右行走
if (Input::GetInstance()->IsKeyDown('A'))
{
m_camera.Strafe(-.f*dt);
}
else if (Input::GetInstance()->IsKeyDown('D'))
{
m_camera.Strafe(.f*dt);
}
if (Input::GetInstance()->IsKeyDown('W'))
{
m_camera.Walk(.f*dt);
}
else if (Input::GetInstance()->IsKeyDown('S'))
{
m_camera.Walk(-.f*dt);
} if (Input::GetInstance()->IsMouseMove())
{
float mouseX = Input::GetInstance()->GetMouseX();
float mouseY = Input::GetInstance()->GetMouseY();
if (Input::GetInstance()->IsLMouseDown())
{
float dx = XMConvertToRadians(0.25f*(mouseX - m_lastMousePos.x));
float dy = XMConvertToRadians(0.25f*(mouseY - m_lastMousePos.y)); OutputDebugString(L"left btn click");
m_camera.Pitch(dy);
m_camera.RotateY(dx);
}
m_lastMousePos.x = mouseX;
m_lastMousePos.y = mouseY;
} m_camera.UpdateViewMatrix();
} //读取高度图信息
bool TerrainDemo::ReadRawFile(std::string filePath)
{
std::ifstream inFile;
//二进制方式打开文件
inFile.open(filePath.c_str(), std::ios::binary);
//文件指针移动到末尾
inFile.seekg(, std::ios::end);
//大小为当前缓冲区大小
std::vector<BYTE> inData(inFile.tellg());
//文件指针移动到开头
inFile.seekg(std::ios::beg);
//读取高度信息
inFile.read((char*)&inData[], inData.size());
inFile.close(); m_heightInfos.resize(inData.size());
for (int i = ; i < inData.size(); ++i)
{
m_heightInfos[i] = inData[i];
} return true;
} bool TerrainDemo::InitTerrain(float width, float height, UINT m, UINT n,float scale)
{
m_cellsPerRow = m;
m_cellsPerCol = n;
m_verticesPerRow = m + ;
m_verticesPerCol = n + ;
m_numsVertices = m_verticesPerRow*m_verticesPerCol;
m_width = width;
m_height = height;
m_heightScale = scale; //得到缩放后的高度
for (auto& item : m_heightInfos)
{
item *= m_heightScale;
} //起始x z坐标
float oX = -width * 0.5f;
float oZ = height * 0.5f;
//每一格坐标变化
float dx = width / m;
float dz = height / n; m_vertices.resize(m_numsVertices);
//计算顶点
for (UINT i = ; i < m_verticesPerCol; ++i)
{
float tempZ = oZ - dz * i;
for (UINT j = ; j < m_verticesPerRow; ++j)
{
UINT index = m_verticesPerRow * i + j;
m_vertices[index].pos.x = oX + dx * j;
m_vertices[index].pos.y = m_heightInfos[index];
m_vertices[index].pos.z = tempZ; m_vertices[index].tex = XMFLOAT2(dx*i, dx*j);
}
} //计算索引和法线
//总格子数量:m * n
//因此总索引数量: 6 * m * n
UINT nIndices = m * n * ;
m_indices.resize(nIndices);
UINT tmp = ;
for (UINT i = ; i < n; ++i)
{
for (UINT j = ; j < m; ++j)
{
m_indices[tmp] = i * m_verticesPerRow + j;
m_indices[tmp + ] = i * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j; //计算法线
XMFLOAT3 temp;
ComputeNomal(m_vertices[m_indices[tmp]], m_vertices[m_indices[tmp + ]],
m_vertices[m_indices[tmp + ]], temp);
m_vertices[m_indices[tmp]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp; m_indices[tmp + ] = i * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j + ;
m_indices[tmp + ] = (i + ) * m_verticesPerRow + j; ComputeNomal(m_vertices[m_indices[tmp + ]], m_vertices[m_indices[tmp + ]],
m_vertices[m_indices[tmp + ]], temp);
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp;
m_vertices[m_indices[tmp + ]].normal = temp; tmp += ;
}
} return true;
} //计算法线
void TerrainDemo::ComputeNomal(Vertex& v1, Vertex& v2, Vertex& v3, XMFLOAT3& normal)
{
XMFLOAT3 f1(v2.pos.x - v1.pos.x, v2.pos.y - v1.pos.y, v2.pos.z - v1.pos.z);
XMFLOAT3 f2(v3.pos.x - v1.pos.x, v3.pos.y - v1.pos.y, v3.pos.z - v1.pos.z);
XMVECTOR vec1 = XMLoadFloat3(&f1);
XMVECTOR vec2 = XMLoadFloat3(&f2);
XMVECTOR temp = XMVector3Normalize(XMVector3Cross(vec1, vec2));
XMStoreFloat3(&normal, temp);
} int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow)
{
std::shared_ptr<Dx11Base> bd(new TerrainDemo(hInstance));
if (!bd->Init())
return -;
return bd->Run();
}
Directx11学习笔记【二十二】 用高度图实现地形的更多相关文章
- Directx11学习笔记【十二】 画一个旋转的彩色立方体
上一次我们学习了如何画一个2D三角形,现在让我们进一步学习如何画一个旋转的彩色立方体吧. 具体流程同画三角形类似,因此不再给出完整代码了,不同的部分会再说明. 由于我们要画彩色的立方体,所以顶点结构体 ...
- VSTO 学习笔记(十二)自定义公式与Ribbon
原文:VSTO 学习笔记(十二)自定义公式与Ribbon 这几天工作中在开发一个Excel插件,包含自定义公式,根据条件从数据库中查询结果.这次我们来做一个简单的测试,达到类似的目的. 即在Excel ...
- 汇编入门学习笔记 (十二)—— int指令、port
疯狂的暑假学习之 汇编入门学习笔记 (十二)-- int指令.port 參考: <汇编语言> 王爽 第13.14章 一.int指令 1. int指令引发的中断 int n指令,相当于引 ...
- Binder学习笔记(十二)—— binder_transaction(...)都干了什么?
binder_open(...)都干了什么? 在回答binder_transaction(...)之前,还有一些基础设施要去探究,比如binder_open(...),binder_mmap(...) ...
- java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...
- Android学习笔记(十二)——实战:制作一个聊天界面
//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 运用简单的布局知识,我们可以来尝试制作一个聊天界面. 一.制作 Nine-Patch 图片 : Nine-Pa ...
- MySQL数据库学习笔记(十二)----开源工具DbUtils的使用(数据库的增删改查)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- 如鹏网学习笔记(十二)HTML5
一.HTML5简介 HTML5是HTML语言第五次修改产生的新的HTML语言版本 改进主要包括: 增加新的HTML标签或者属性.新的CSS样式属性.新的JavaScript API等.同时删除了一些过 ...
- o'Reill的SVG精髓(第二版)学习笔记——第十二章
第十二章 SVG动画 12.1动画基础 SVG的动画特性基于万维网联盟的“同步多媒体集成语言”(SMIL)规范(http://www.w3.org/TR/SMIL3). 在这个动画系统中,我们可以指定 ...
- Dynamic CRM 2013学习笔记(十二)实现子表合计(汇总,求和)功能的通用插件
上一篇 Dynamic CRM 2013学习笔记(十一)利用Javascript实现子表合计(汇总,求和)功能 , 介绍了如何用js来实现子表合计功能,这种方法要求在各个表单上添加js方法,如果有很多 ...
随机推荐
- android一个上传图片的样例,包含怎样终止上传过程,假设在上传的时候更新进度条(一)
先上效果图: Layout为: <? xml version="1.0" encoding="utf-8"?> <LinearLayout x ...
- 慕尼黑大学公开课 Competitive Strategy(竞争策略)总结
第一章博弈 同时的博弈:双方同时定制策略 如果有显著的次优策略总是不如另一个,则剔除它. 如果一个策略组合中没有一方可以单独改变其策略以提高回报,则称为Nash均衡.一个游戏可能没有也可能有多个Nas ...
- ORACLE—005:创建JOB(二)
假设须要创建带參数的job,怎样创建呢. 我们直接将參数声明.并赋值.然后传给job调用的存储过程就可以. 比如.存储过程名为Pro_Test_JOB,參数共同拥有一个.是VARCHAR2类型. 创建 ...
- 不知道的JavaScript
你不知道的JavaScript上卷笔记 前言 You don't know JavaScript是github上一个系列文章 初看到这一标题的时候,感觉怎么老外也搞标题党,用这种冲突性比较强的题目吸 ...
- php 双向队列类
(deque,全名double-ended queue)是一种具有队列和栈的性质的数据结构.双向队列中的元素能够从两端弹出,其限定插入和删除操作在表的两端进行. 在实际使用中,还能够有输出受限的双向队 ...
- [置顶] ANDROID 返回,菜单和HOME键的监听
------网上找了很多资料,项目中使用,最后将经验总结如下: 1,返回和菜单键是可以直接重写onKeyDown(int keyCode, KeyEvent event) 方法监听: @Overrid ...
- cocos2dx使用tolua关于字符串处理的一个问题
正在使用cocos2dx的tolua binding在此过程中发现的一个问题.假设一回或输入是std::string当我们不同意包括二进制数据,和std::string我同意,这样一来就导致了不正确的 ...
- 开源语法分析器--ANTLR
序言 有的时候,我还真是怀疑过上本科时候学的那些原理课究竟是不是在浪费时间.比方学完操作系统原理之后我们并不能自己动手实现一个操作系统:学完数据库原理我们也不能弄出个像样的DBMS出来:相同,学完 ...
- C#反射机制详解(转)
两个现实中的例子:1.B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内脏的生理情况.这是如何做到的呢?B超是B型超声波,它可以透过肚皮通过向你体内发射B型超声波,当超声波遇到内脏壁的时 ...
- poj3126解题报告
题意:简单的说就是:有一个人门牌号是一个四位数的整数,并且还是一个素数,现在他想要换成另外一个四位数且是素数的门牌号,而且,每次都只能更换这个四位数的一个位置的数 ,也就是每换一次都只改变一个数字,而 ...