热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

3D游戏从入门到精通1115

************************************作者:蔡军生*出处:http:blog.csdn.netcaimouse****

  /***********************************
 *作者:蔡军生
 *出处:http://blog.csdn.net/caimouse/
 ************************************/
 
 
 3D游戏从入门到精通-11
 
 
2.10.1索引缓冲区
上面已经学习了最简单的三角形显示,了解了整个3D物体的显示流程,下面来学习一个复杂一点的物体显示,使用12个三角形构造成的正方体显示。并且通过个例子学会使用索引缓冲区,提高图形绘制的速度和效率。
1、             使用三角形构造立方体
由前面可知,任何复杂的物体,都是由三角形组成的。现在就用12三角形构造一个正方体。先创建12点个顶点的缓冲区,然后再往里填写合适的数据,然后显示它出来。下面来仔细分析这段代码:
在函数HRESULT CCAICube::Init(IDirect3DDevice9* pd3dDevice)里,先创建12顶点数据。
const int nVTCount = 6*2*3;
 // 创建顶点缓冲区。
 if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( nVTCount * sizeof(VT_CAICUBE),
       0, VT_CAICUBE::dwFVF,
       D3DPOOL_MANAGED, &m_pVB, NULL ) ) )
 {
       //创建顶点缓冲区失败。
       return DXTRACE_ERR( "CreateVertexBuffer", hr );
 }
           这段代码,跟以前的代码一样创建顶点缓冲区。
接着下来就指明所有三角形的坐标:
// 用三角形填充顶点缓冲区。
 VT_CAICUBE* pVertices;
 
 if( FAILED( hr = m_pVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) )
 {
       //锁住顶点缓冲区。
       return DXTRACE_ERR( "Lock", hr );
 }
 
 // 三角形组成的立方体表面。
 //第一个面
 pVertices[0].vPosition = D3DXVECTOR3( -1.0f, -1.0f, -1.0f );
 pVertices[1].vPosition = D3DXVECTOR3( -1.0f, 1.0f, -1.0f );
 pVertices[2].vPosition = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
 
 //
 pVertices[3].vPosition = D3DXVECTOR3( -1.0f, -1.0f, -1.0f );
 pVertices[4].vPosition = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
 pVertices[5].vPosition = D3DXVECTOR3( 1.0f, -1.0f, -1.0f );
 
 
 //第二个面
 pVertices[6].vPosition = D3DXVECTOR3( -1.0f, 1.0f, -1.0f );
 pVertices[7].vPosition = D3DXVECTOR3( -1.0f, 1.0f, 1.0f );
 pVertices[8].vPosition = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
 
 //
 pVertices[9].vPosition = D3DXVECTOR3(   -1.0f, 1.0f, 1.0f );
 pVertices[10].vPosition = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
 pVertices[11].vPosition = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
 
 
 //第三个面
 pVertices[12].vPosition = D3DXVECTOR3( -1.0f, 1.0f, 1.0f );
 pVertices[13].vPosition = D3DXVECTOR3( -1.0f, -1.0f, 1.0f );
 pVertices[14].vPosition = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
 
 //
 pVertices[15].vPosition = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
 pVertices[16].vPosition = D3DXVECTOR3( -1.0f, -1.0f, 1.0f );
 pVertices[17].vPosition = D3DXVECTOR3( 1.0f, -1.0f, 1.0f );
 
 //第四个面
 pVertices[18].vPosition = D3DXVECTOR3( -1.0f, -1.0f, 1.0f );
 pVertices[19].vPosition = D3DXVECTOR3( 1.0f, -1.0f, -1.0f );
 pVertices[20].vPosition = D3DXVECTOR3( 1.0f, -1.0f, 1.0f );
 
 //
 pVertices[21].vPosition = D3DXVECTOR3( -1.0f, -1.0f, 1.0f );   
 pVertices[22].vPosition = D3DXVECTOR3( -1.0f, -1.0f, -1.0f );
 pVertices[23].vPosition = D3DXVECTOR3( 1.0f, -1.0f, -1.0f );
 
 
 //第五个面
 pVertices[24].vPosition = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );   
 pVertices[25].vPosition = D3DXVECTOR3( 1.0f, -1.0f, -1.0f );
 pVertices[26].vPosition = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
 
 //
 pVertices[27].vPosition = D3DXVECTOR3( 1.0f, -1.0f, -1.0f );   
 pVertices[28].vPosition = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
 pVertices[29].vPosition = D3DXVECTOR3( 1.0f, -1.0f, 1.0f );
 
 //第六个面
 pVertices[30].vPosition = D3DXVECTOR3( -1.0f, 1.0f, -1.0f );
 pVertices[31].vPosition = D3DXVECTOR3( -1.0f, -1.0f, -1.0f );    
 pVertices[32].vPosition = D3DXVECTOR3( -1.0f, 1.0f, 1.0f );
 
 //
 pVertices[33].vPosition = D3DXVECTOR3( -1.0f, 1.0f, 1.0f );    
 pVertices[34].vPosition = D3DXVECTOR3( -1.0f, -1.0f, -1.0f );
 pVertices[35].vPosition = D3DXVECTOR3( -1.0f, -1.0f, 1.0f );
 
 //解锁顶点缓冲区。
 m_pVB->Unlock();
上面从第一个面开始,就每个面两个三角形地填写,并且是按左中手坐标系的方向来填写三角形的顶点。
接着修改渲染的代码,改为渲染12个三角形,代码如下:
// 渲染顶点缓冲区的内容。
 m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(VT_CAICUBE) );
 m_pd3dDevice->SetFVF( VT_CAICUBE::dwFVF );
 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 12 );
这样显示出来的立方体是那个面都可以看得到的,如果不按左手坐标系填写,就会有一些面看不到的。
 
通过上面的代码,是否看到要显示一个简单的立方体,就需要复杂地填写顶点了,并且要小心翼翼地写代码,一不小心写错了,就看不见了。因此,再复杂的物体,一般是通过使用3D建模软件来构造的。通过上面的代码,也发现了一个问题,就是整个正方体,其实只有8个顶点,而上面的三角形列表里有很多顶点是重复的,对于只有12个三角形来说,也许不是很重要。但是对于数以万计的三角形来说,这样的重复顶点就会浪费很多内存,浪费系统的带宽,并且需要重复渲染顶点。有没有更好的方法来解决这个问题呢?答案是肯定的,下面接着就来学习索引缓冲区。
 3D游戏从入门到精通-12
 
1、             使用索引缓冲区
什么是索引缓冲区呢?其实索引缓冲区,就像指针一样的工具。顶点缓冲区里保存的是真实的顶点,而索引缓冲区只记录顶点缓冲区的顶点编号。比如顶点缓冲区里有4个顶点,而这4个顶点就可以构成两个三角形来显示。如果直接使用顶点缓冲区的话,就需要写6个顶点。这样就可以使用索引缓冲区,指明第一个三角形是由顶点编号1、2、3构成一个三角形,而第二个三角形就是1、3、4组成。

现在把上面的立方体改为使用索引缓冲区,先创建8个顶点,如下:
pVertices[0].vPosition = D3DXVECTOR3(    -1.0f, -1.0f, -1.0f );
pVertices[1].vPosition = D3DXVECTOR3(    -1.0f, 1.0f, -1.0f );   
pVertices[2].vPosition = D3DXVECTOR3(    1.0f, 1.0f, -1.0f );    
pVertices[3].vPosition = D3DXVECTOR3(    1.0f, -1.0f, -1.0f );   
 
pVertices[4].vPosition = D3DXVECTOR3(    -1.0f, 1.0f, 1.0f );    
pVertices[5].vPosition = D3DXVECTOR3(    1.0f, 1.0f, 1.0f );
pVertices[6].vPosition = D3DXVECTOR3(    1.0f, -1.0f, 1.0f );    
pVertices[7].vPosition = D3DXVECTOR3(    -1.0f, -1.0f, 1.0f );
这样,就可省下许多顶点占用的内存了,然后创建36个索引点的缓冲区,如下:
 
//创建索引缓冲区。
 hr = m_pd3dDevice->CreateIndexBuffer( 12*3 *sizeof(WORD),
       0, D3DFMT_INDEX16, D3DPOOL_DEFAULT,
       &m_pIB, NULL );
 
 if( FAILED( hr ) )
 {
       return E_FAIL;
 }   
 
上面创建了36个WORD大小的索引点,这样省了很多内存空间。由于顶点是由3个浮点数和其它值组成,肯定比两个字节索引值占用空间大。接着下来就是设置索引缓冲区,如下:
 
void* pIndices;
 
 if( FAILED( m_pIB->Lock( 0, sizeof(WORD)*12*3, &pIndices,0 ) ) )          
 {
       m_pIB->Release();
       m_pIB = NULL;
       return E_FAIL;
 }
 
 //
 WORD* pIndex = reinterpret_cast(pIndices);
 int nPos = 0;
 
 //1
 pIndex[nPos++] = 0;
 pIndex[nPos++] = 1;
 pIndex[nPos++] = 2;
 
 pIndex[nPos++] = 0;
 pIndex[nPos++] = 2;
 pIndex[nPos++] = 3;
 
 
 //2
 pIndex[nPos++] = 1;
 pIndex[nPos++] = 4;
 pIndex[nPos++] = 2;
 
 pIndex[nPos++] = 2;
 pIndex[nPos++] = 4;
 pIndex[nPos++] = 5;
 
 //3
 pIndex[nPos++] = 2;
 pIndex[nPos++] = 5;
 pIndex[nPos++] = 3;
 
 pIndex[nPos++] = 3;
 pIndex[nPos++] = 5;
 pIndex[nPos++] = 6;
 
 //4
 pIndex[nPos++] = 0;
 pIndex[nPos++] = 7;
 pIndex[nPos++] = 1;
 
 pIndex[nPos++] = 1;
 pIndex[nPos++] = 7;
 pIndex[nPos++] = 4;
 
 //5
 pIndex[nPos++] = 0;
 pIndex[nPos++] = 3;
 pIndex[nPos++] = 7;
 
 pIndex[nPos++] = 3;
 pIndex[nPos++] = 6;
 pIndex[nPos++] = 7;
 
 
 //6
 pIndex[nPos++] = 4;
 pIndex[nPos++] = 7;
 pIndex[nPos++] = 5;
 
 pIndex[nPos++] = 5;
 pIndex[nPos++] = 7;
 pIndex[nPos++] = 6;
 //
 m_pIB->Unlock();
 
上面这段代码,先Lock函数取得索引缓冲区地址,然后依次设置索引值,这里使用三角形列表,所以顶点顺序一样是按顺时针方向来设置的,也就是按左手坐标系来设置的。
接着下来,就需要渲染这个立方体了,如下:
m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(VT_CAICUBE) );
 m_pd3dDevice->SetFVF( VT_CAICUBE::dwFVF );
 
m_pd3dDevice->SetIndices(m_pIB);
m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,8,0,12);
上面代码先设置了8个顶点缓冲区到管道里,然后再调用SetIndices设置索引缓冲区,最后调用DrawIndexedPrimitive函数来显示所有三角形列表。DrawIndexedPrimitive函数的第一个参数是索引列表里的类型,第二个参数是索引缓冲区在顶点缓冲区里的起始位置,比如顶点缓区是0,1,3的,当设置这个值为50时,那么相当于访问了50,51,53的顶点值。第三个参数是最小索引值。第四个参数是有多少个顶点会使用。第五个参数是从那个索引值开始。第六个参数是基本图形个数。
 
通过这样学习,就学会使用了索引缓冲区,如果有很多顶点,有很多三角形,就需要使用优化的算法,以便有最少的顶点,使用最多的索引,这样有利于减少内存占用,提高带宽利用,提高显示卡显示更多图形,提高游戏的性能。
 
 
 3D游戏从入门到精通-13
2.10.1基本图形显示
在D3D里只有几种基本图形可以显示的,它们分别是:
点列表、线列表、线带列表、三角形列表、三角形带列表、三角形扇形列表。
其它任何的图形,都可以由这向这几种基本图形组合出来。上面已经介绍了三角形显示了,所以这里就不再具体地说明它了。
1、             点列表
点列表主要显示为一个个像素点的集合,每个点都是单独显示,分离的。点列表作用是用来显示点元素,或者显示点线的。如下图所示:
上面这个图就是使用点列表来显示一条正弦曲线。其实它们都是由分理的点组成,每个点可显示为不同的颜色。
现在就看看怎么样用代码显示这条正弦曲线的。
 
HRESULT hr;
 
 // 创建顶点缓冲区。
 if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer(
       m_nPointListCount * sizeof(VT_CAIPRIMITIVE),
       0, VT_CAIPRIMITIVE::dwFVF,
       D3DPOOL_MANAGED, &m_pvbPointList, NULL ) ) )
 {
       //创建顶点缓冲区失败。
       return DXTRACE_ERR( "CreateVertexBuffer", hr );
 }
 
 //
 VT_CAIPRIMITIVE* pVertices;
 if( FAILED( hr = m_pvbPointList->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) )
 {
       //锁住顶点缓冲区。
       return DXTRACE_ERR( "Lock", hr );
 }
 
 for (int i = 0; i  {
       float fX = -10.0f + (float)i * 0.1f;
       float fY = sinf(fX);
       pVertices[i].vPosition = D3DXVECTOR3( fX, fY, 0.0f );    
       pVertices[i].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 }
 
 
 //解锁顶点缓冲区。
 m_pvbPointList->Unlock();
 
上面这段代码,先创建点列表的顶点缓冲区,然后使用正弦函数计算点坐标的值,并把它们设置到顶点缓冲区里。接着就需要调用渲染函数:
m_pd3dDevice->SetStreamSource( 0, m_pvbPointList, 0, sizeof(VT_CAIPRIMITIVE) );
m_pd3dDevice->SetFVF( VT_CAIPRIMITIVE::dwFVF );
m_pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, 0, m_nPointListCount );  
先设置顶点缓冲区,然后调用DrawPrimitive函数来显示,这里第一个参数不一样,使用了D3DPT_POINTLIST类型,这个类型就是显示为点列表方式。
如果使用直线或者三角形不能显示的图形,就可以使用它来显示了。
 
 
 3D游戏从入门到精通-14
 
2、             线列表
D3D还提供直线的显示,由于很多自然现现象需要它来显示。比如大雨,就需要使用直线来模拟出来。如下图所示:
这里显示三条红、绿、蓝的直线。它的代码如下:
pVertices[0].vPosition = D3DXVECTOR3( -2.0f, 0.0f, 0.0f );    
 pVertices[0].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 pVertices[1].vPosition = D3DXVECTOR3( 2.0f, 0.0f, 0.0f );    
 pVertices[1].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 //
 pVertices[2].vPosition = D3DXVECTOR3( 0.0f, -2.0f, 0.0f );   
 pVertices[2].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 pVertices[3].vPosition = D3DXVECTOR3( 0.0f, 2.0f, 0.0f );    
 pVertices[3].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 //
 pVertices[4].vPosition = D3DXVECTOR3( -2.0f, -2.0f, 0.0f );
 pVertices[4].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
 pVertices[5].vPosition = D3DXVECTOR3( 2.0f, 2.0f, 0.0f );    
 pVertices[5].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
上面的代码分别设置了三条直线的向量和颜色值。然后调用下面函数显示:
 
m_pd3dDevice->DrawPrimitive( D3DPT_LINELIST, 0, m_nLineListCount );
第一个参数设置为D3DPT_LINELIST类型,就是直线列表的方式。
 
 3D游戏从入门到精通-15
 
3、             线带列表
在D3D里还提供线带列表显示,这种显示方式是把所有直线顺着顶点连接显示出来。如下图所示:
采用线带列表显示的方式,可以减少顶点占用内存空间,提高显示效率。下面这段代码就是显示6个顶点的直线。
 
m_nLineStripCount = 3;
 
HRESULT hr;
 
 // 创建顶点缓冲区。
 if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer(
       m_nLineStripCount*2 * sizeof(VT_CAIPRIMITIVE),
       0, VT_CAIPRIMITIVE::dwFVF,
       D3DPOOL_MANAGED, &pVB, NULL ) ) )
 {
       //创建顶点缓冲区失败。
       return DXTRACE_ERR( "CreateVertexBuffer", hr );
 }
 
 //
 VT_CAIPRIMITIVE* pVertices;
 if( FAILED( hr = pVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) )
 {
       //锁住顶点缓冲区。
       return DXTRACE_ERR( "Lock", hr );
 }
 
 pVertices[0].vPosition = D3DXVECTOR3( -6.0f, -2.0f, 2.0f );
 pVertices[0].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 pVertices[1].vPosition = D3DXVECTOR3( -4.0f, 2.0f, 2.0f );   
 pVertices[1].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 //
 pVertices[2].vPosition = D3DXVECTOR3( -2.0f, -2.0f, 2.0f );
 pVertices[2].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 pVertices[3].vPosition = D3DXVECTOR3( 0.0f, 2.0f, 0.0f );    
 pVertices[3].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 //
 pVertices[4].vPosition = D3DXVECTOR3( 2.0f, -2.0f, 2.0f );   
 pVertices[4].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
 pVertices[5].vPosition = D3DXVECTOR3( 4.0f, 2.0f, 2.0f );    
 pVertices[5].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
 //解锁顶点缓冲区。
 pVB->Unlock();
 
上面的代码是先创建合适的顶点缓冲区,然后设置6个顶点的值。由这6个顶点就可以连接成为5条直线。显示的代码如下:
 
m_pd3dDevice->SetStreamSource( 0, m_pvbLineStrip, 0, sizeof(VT_CAIPRIMITIVE) );
 m_pd3dDevice->SetFVF( VT_CAIPRIMITIVE::dwFVF );
 m_pd3dDevice->DrawPrimitive( D3DPT_LINESTRIP, 0, m_nLineStripCount*2 -1 );
上面的DrawPrimitive函数设置为D3DPT_LINESTRIP显示,就是线带方式显示。最后一个参数指明了它要显示多少条直线。
 
 


推荐阅读
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 在Delphi7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下:1234 ... [详细]
  • 在HTML布局中,即使将 `top: 0%` 和 `left: 0%` 设置为元素的定位属性,浏览器中仍然会出现空白填充。这个问题通常与默认的浏览器样式、盒模型或父元素的定位方式有关。为了消除这些空白,可以考虑重置浏览器的默认样式,确保父元素的定位方式正确,并检查是否有其他CSS规则影响了元素的位置。 ... [详细]
  • 在分析和解决 Keepalived VIP 漂移故障的过程中,我们发现主备节点配置如下:主节点 IP 为 172.16.30.31,备份节点 IP 为 172.16.30.32,虚拟 IP 为 172.16.30.10。故障表现为监控系统显示 Keepalived 主节点状态异常,导致 VIP 漂移到备份节点。通过详细检查配置文件和日志,我们发现主节点上的 Keepalived 进程未能正常运行,最终通过优化配置和重启服务解决了该问题。此外,我们还增加了健康检查机制,以提高系统的稳定性和可靠性。 ... [详细]
  • 经过两天的努力,终于成功解决了半平面交模板题POJ3335的问题。原来是在`OnLeft`函数中漏掉了关键的等于号。通过这次训练,不仅加深了对半平面交算法的理解,还提升了调试和代码实现的能力。未来将继续深入研究计算几何的其他核心问题,进一步巩固和拓展相关知识。 ... [详细]
  • C++ 开发实战:实用技巧与经验分享
    C++ 开发实战:实用技巧与经验分享 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • Spring Boot 中配置全局文件上传路径并实现文件上传功能
    本文介绍如何在 Spring Boot 项目中配置全局文件上传路径,并通过读取配置项实现文件上传功能。通过这种方式,可以更好地管理和维护文件路径。 ... [详细]
  • 本文回顾了作者初次接触Unicode编码时的经历,并详细探讨了ASCII、ANSI、GB2312、UNICODE以及UTF-8和UTF-16编码的区别和应用场景。通过实例分析,帮助读者更好地理解和使用这些编码。 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • 使用Maven JAR插件将单个或多个文件及其依赖项合并为一个可引用的JAR包
    本文介绍了如何利用Maven中的maven-assembly-plugin插件将单个或多个Java文件及其依赖项打包成一个可引用的JAR文件。首先,需要创建一个新的Maven项目,并将待打包的Java文件复制到该项目中。通过配置maven-assembly-plugin,可以实现将所有文件及其依赖项合并为一个独立的JAR包,方便在其他项目中引用和使用。此外,该方法还支持自定义装配描述符,以满足不同场景下的需求。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • Java能否直接通过HTTP将字节流绕过HEAP写入SD卡? ... [详细]
  • AIX编程挑战赛:AIX正方形问题的算法解析与Java代码实现
    在昨晚的阅读中,我注意到了CSDN博主西部阿呆-小草屋发表的一篇文章《AIX程序设计大赛——AIX正方形问题》。该文详细阐述了AIX正方形问题的背景,并提供了一种基于Java语言的解决方案。本文将深入解析这一算法的核心思想,并展示具体的Java代码实现,旨在为参赛者和编程爱好者提供有价值的参考。 ... [详细]
author-avatar
mobiledu2502881767
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有