第一次发送超过字数了,被迫剪成两篇!

上一篇我们介绍了如何搭建开发环境,并创建了一个空白的窗口程序。
这里我们主要是实现在程序中装载一个简单的模型并显示出来。
首先看一下效果吧,(模型就是ogre例子中的robot.mesh),如下:

例子很简单,代码页不多,就4行。我们还是一步一步来分析吧。
首先我们上一个项目中的OgreDemo1类继承自ExampleApplication类,我们之所以什么都没

有做就能创建一个窗口,就是因为ExampleApplication为我们实现了。
首先我们打开ExampleApplication类,可以看到包含了如下几个成员变量(加入了少许注释)

  1. //ogre的程序"根"任何ogre程序都会有改对象
  2. Root *mRoot;
  3. //摄像机镜头
  4. Camera* mCamera;
  5. //场景管理器
  6. SceneManager* mSceneMgr;
  7. //对于每一帧进行处理的类
  8. ExampleFrameListener* mFrameListener;
  9. //渲染窗口
  10. RenderWindow* mWindow;
  11. //资源文件的路径字符串
  12. Ogre::String mResourcePath;

这里的ExampleFrameListener类,如果你暂时还不清楚是做什么的,不要紧,后面我们慢慢介绍。
知道了这些成员变量,我们在返回OgreDemo1.c文件中看看入口函数WinMain中是如何书写的呢?很简单就一句话:

  1. app.go();

先将源代码贴出来,加了详细注意:
ExampleApplication.h

  1. #ifndef __ExampleApplication_H__
  2. #define __ExampleApplication_H__
  3. #include "Ogre.h"
  4. #include "OgreConfigFile.h"
  5. #include "ExampleFrameListener.h"
  6. #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
  7. #include <CoreFoundation/CoreFoundation.h>
  8. std::string macBundlePath()
  9. {
  10. char path[1024];
  11. CFBundleRef mainBundle = CFBundleGetMainBundle();
  12. assert(mainBundle);
  13. CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);
  14. assert(mainBundleURL);
  15. CFStringRef cfStringRef = CFURLCopyFileSystemPath( mainBundleURL, kCFURLPOSIXPathStyle);
  16. assert(cfStringRef);
  17. CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);
  18. CFRelease(mainBundleURL);
  19. CFRelease(cfStringRef);
  20. return std::string(path);
  21. }
  22. #endif
  23. using namespace Ogre;
  24. /** Base class which manages the standard startup of an Ogre application.
  25. Designed to be subclassed for specific examples if required.
  26. */
  27. class ExampleApplication
  28. {
  29. public:
  30. ExampleApplication()
  31. {
  32. mFrameListener = 0;
  33. mRoot = 0;
  34. #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
  35. mResourcePath = macBundlePath() + "/Contents/Resources/";
  36. #else
  37. mResourcePath = "";
  38. #endif
  39. }
  40. /// Standard destructor
  41. virtual ~ExampleApplication()
  42. {
  43. if (mFrameListener)
  44. delete mFrameListener;
  45. if (mRoot)
  46. OGRE_DELETE mRoot;
  47. }
  48. /// 程序的入口
  49. virtual void go(void)
  50. {
  51. //进行初始化工作
  52. if (!setup())
  53. return;
  54. //开始渲染
  55. mRoot->startRendering();
  56. // 清理屏幕
  57. destroyScene();
  58. }
  59. protected:
  60. //ogre的程序"根"任何ogre程序都会有改对象
  61. Root *mRoot;
  62. //摄像机镜头
  63. Camera* mCamera;
  64. //场景管理器
  65. SceneManager* mSceneMgr;
  66. //对于每一帧进行处理的类
  67. ExampleFrameListener* mFrameListener;
  68. //渲染窗口
  69. RenderWindow* mWindow;
  70. //资源文件的路径字符串
  71. Ogre::String mResourcePath;
  72. //初始化应用程序
  73. virtual bool setup(void)
  74. {
  75. String pluginsPath;
  76. #ifndef OGRE_STATIC_LIB
  77. pluginsPath = mResourcePath + "plugins.cfg";
  78. #endif
  79. //构建Root对象
  80. mRoot = OGRE_NEW Root(pluginsPath,
  81. mResourcePath + "ogre.cfg", mResourcePath + "Ogre.log");
  82. //配置资源文件相关
  83. setupResources();
  84. //配置,主要用于初始化渲染窗口
  85. bool carryOn = configure();
  86. if (!carryOn) return false;
  87. //创建场景管理器
  88. chooseSceneManager();
  89. //创建摄像机
  90. createCamera();
  91. //创建视口
  92. createViewports();
  93. TextureManager::getSingleton().setDefaultNumMipmaps(5);
  94. //创建资源监听
  95. createResourceListener();
  96. //床在资源
  97. loadResources();
  98. //创建屏幕,必须重写,也就是我们OgreDemo1类中(我们现实模型需要实现的)
  99. createScene();
  100. //创建帧监听
  101. createFrameListener();
  102. return true;
  103. }
  104. /** 是否配置完成,完成则初始化系统 */
  105. virtual bool configure(void)
  106. {
  107. //判断是否进入(即运行过了配置窗口,进入demo窗口)
  108. if(mRoot->showConfigDialog())
  109. {
  110. //初始化系统,得到一个渲染窗口对象
  111. mWindow = mRoot->initialise(true);
  112. return true;
  113. }
  114. else
  115. {
  116. return false;
  117. }
  118. }
  119. virtual void chooseSceneManager(void)
  120. {
  121. // 创建一个场景管理器(场景类型,窗口标题)
  122. mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "ExampleSMInstance");
  123. }
  124. virtual void createCamera(void)
  125. {
  126. // 创建一个摄像机
  127. mCamera = mSceneMgr->createCamera("PlayerCam");
  128. // 设置摄像机的位置
  129. mCamera->setPosition(Vector3(0,0,500));
  130. // 设置观察点
  131. mCamera->lookAt(Vector3(0,0,-300));
  132. // 设置最近裁剪距离,如果超出则不显示
  133. mCamera->setNearClipDistance(5);
  134. //同样还有设置最远裁剪距离
  135. //mCamera->setFarClipDistance(1000);
  136. }
  137. //创建帧监听
  138. virtual void createFrameListener(void)
  139. {
  140. //实例化帧监听,(渲染窗口,摄像机)
  141. mFrameListener= new ExampleFrameListener(mWindow, mCamera);
  142. //设置是否显示调试信息(比如:fps...)
  143. mFrameListener->showDebugOverlay(true);
  144. //添加帧监听到root中
  145. mRoot->addFrameListener(mFrameListener);
  146. }
  147. //创建屏幕
  148. virtual void createScene(void) = 0;
  149. //清屏
  150. virtual void destroyScene(void){}
  151. /* 创建视口并初始化 */
  152. virtual void createViewports(void)
  153. {
  154. // 创建一个“视口”
  155. Viewport* vp = mWindow->addViewport(mCamera);
  156. //设置背景颜色
  157. vp->setBackgroundColour(ColourValue(0,0,0));
  158. //设置屏幕的长宽比(视口的宽度和高度比,目前的宽屏电脑)
  159. mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
  160. }
  161. /// 初始化资源,比如:模型、贴图等资源
  162. virtual void setupResources(void)
  163. {
  164. ConfigFile cf;
  165. //读取配置文件
  166. cf.load(mResourcePath + "resources.cfg");
  167. ConfigFile::SectionIterator seci = cf.getSectionIterator();
  168. String secName, typeName, archName;
  169. while (seci.hasMoreElements())
  170. {
  171. secName = seci.peekNextKey();
  172. ConfigFile::SettingsMultiMap *settings = seci.getNext();
  173. ConfigFile::SettingsMultiMap::iterator i;
  174. for (i = settings->begin(); i != settings->end(); ++i)
  175. {
  176. //取得并添加资源文件
  177. typeName = i->first;
  178. archName = i->second;
  179. #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
  180. ResourceGroupManager::getSingleton().addResourceLocation(
  181. String(macBundlePath() + "/" + archName), typeName, secName);
  182. #else
  183. ResourceGroupManager::getSingleton().addResourceLocation(
  184. archName, typeName, secName);
  185. #endif
  186. }
  187. }
  188. }
  189. //创建资源监听,比如(正在装载资源,请稍等界面)
  190. virtual void createResourceListener(void)
  191. {
  192. }
  193. //装载资源
  194. virtual void loadResources(void)
  195. {
  196. ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
  197. }
  198. };
  199. #endif

ExampleFrameListener.h

  1. #ifndef __ExampleFrameListener_H__
  2. #define __ExampleFrameListener_H__
  3. #include "Ogre.h"
  4. #include "OgreStringConverter.h"
  5. #include "OgreException.h"
  6. #define OIS_DYNAMIC_LIB
  7. #include <OIS/OIS.h>
  8. using namespace Ogre;
  9. class ExampleFrameListener: public FrameListener, public WindowEventListener
  10. {
  11. protected:
  12. virtual void updateStats(void)
  13. {
  14. static String currFps = "Current FPS: ";
  15. static String avgFps = "Average FPS: ";
  16. static String bestFps = "Best FPS: ";
  17. static String worstFps = "Worst FPS: ";
  18. static String tris = "Triangle Count: ";
  19. static String batches = "Batch Count: ";
  20. // 需要更新debug信息时更新
  21. try {
  22. OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
  23. OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
  24. OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
  25. OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");
  26. const RenderTarget::FrameStats& stats = mWindow->getStatistics();
  27. guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
  28. guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS));
  29. guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)
  30. +" "+StringConverter::toString(stats.bestFrameTime)+" ms");
  31. guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)
  32. +" "+StringConverter::toString(stats.worstFrameTime)+" ms");
  33. OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
  34. guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));
  35. OverlayElement* guiBatches = OverlayManager::getSingleton().getOverlayElement("Core/NumBatches");
  36. guiBatches->setCaption(batches + StringConverter::toString(stats.batchCount));
  37. OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
  38. guiDbg->setCaption(mDebugText);
  39. }
  40. catch(...) { /* ignore */ }
  41. }
  42. public:
  43. // 构造函数,初始化成员变量
  44. ExampleFrameListener(RenderWindow* win, Camera* cam, bool bufferedKeys = false, bool bufferedMouse = false,
  45. bool bufferedJoy = false ) :
  46. mCamera(cam), mTranslateVector(Vector3::ZERO), mCurrentSpeed(0), mWindow(win), mStatsOn(true), mNumScreenShots(0),
  47. mMoveScale(0.0f), mRotScale(0.0f), mTimeUntilNextToggle(0), mFiltering(TFO_BILINEAR),
  48. mAniso(1), mSceneDetailIndex(0), mMoveSpeed(100), mRotateSpeed(36), mDebugOverlay(0),
  49. mInputManager(0), mMouse(0), mKeyboard(0), mJoy(0)
  50. {
  51. //得到debug视图
  52. mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
  53. //日志管理器
  54. LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
  55. OIS::ParamList pl;
  56. size_t windowHnd = 0;
  57. std::ostringstream windowHndStr;
  58. //取得自定义的属性
  59. win->getCustomAttribute("WINDOW", &windowHnd);
  60. windowHndStr << windowHnd;
  61. pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
  62. //创建输入管理器
  63. mInputManager = OIS::InputManager::createInputSystem( pl );
  64. //创建输入设备、鼠标、键盘、摇杆
  65. mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, bufferedKeys ));
  66. mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, bufferedMouse ));
  67. try {
  68. mJoy = static_cast<OIS::JoyStick*>(mInputManager->createInputObject( OIS::OISJoyStick, bufferedJoy ));
  69. }
  70. catch(...) {
  71. mJoy = 0;
  72. }
  73. //根据窗口的大小来设置鼠标的初始裁剪区域
  74. windowResized(mWindow);
  75. //显示debug信息
  76. showDebugOverlay(true);
  77. //注册一个windows窗口事件监听
  78. WindowEventUtilities::addWindowEventListener(mWindow, this);
  79. }
  80. //调整鼠标裁剪区域
  81. virtual void windowResized(RenderWindow* rw)
  82. {
  83. unsigned int width, height, depth;
  84. int left, top;
  85. //取得窗口矩阵
  86. rw->getMetrics(width, height, depth, left, top);
  87. //得到鼠标
  88. const OIS::MouseState &ms = mMouse->getMouseState();
  89. ms.width = width;
  90. ms.height = height;
  91. }
  92. //关闭窗口之前进行的处理
  93. virtual void windowClosed(RenderWindow* rw)
  94. {
  95. //检测是否关闭了我们的渲染窗口
  96. if( rw == mWindow )
  97. {
  98. if( mInputManager )
  99. {
  100. //清除输入设备
  101. mInputManager->destroyInputObject( mMouse );
  102. mInputManager->destroyInputObject( mKeyboard );
  103. mInputManager->destroyInputObject( mJoy );
  104. //销毁输入管理器
  105. OIS::InputManager::destroyInputSystem(mInputManager);
  106. mInputManager = 0;
  107. }
  108. }
  109. }
  110. virtual ~ExampleFrameListener()
  111. {
  112. //移除所有的窗口事件监听
  113. WindowEventUtilities::removeWindowEventListener(mWindow, this);
  114. //关闭窗口
  115. windowClosed(mWindow);
  116. }
  117. //按键事件处理
  118. virtual bool processUnbufferedKeyInput(const FrameEvent& evt)
  119. {
  120. if(mKeyboard->isKeyDown(OIS::KC_A))
  121. mTranslateVector.x = -mMoveScale;   // 向左移动摄像头矩阵
  122. if(mKeyboard->isKeyDown(OIS::KC_D))
  123. mTranslateVector.x = mMoveScale;    // Move camera RIGHT
  124. if(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W) )
  125. mTranslateVector.z = -mMoveScale;   // Move camera forward
  126. if(mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S) )
  127. mTranslateVector.z = mMoveScale;    // Move camera backward
  128. if(mKeyboard->isKeyDown(OIS::KC_PGUP))
  129. mTranslateVector.y = mMoveScale;    // Move camera up
  130. if(mKeyboard->isKeyDown(OIS::KC_PGDOWN))
  131. mTranslateVector.y = -mMoveScale;   // Move camera down
  132. if(mKeyboard->isKeyDown(OIS::KC_RIGHT))
  133. mCamera->yaw(-mRotScale);
  134. if(mKeyboard->isKeyDown(OIS::KC_LEFT))
  135. mCamera->yaw(mRotScale);
  136. if( mKeyboard->isKeyDown(OIS::KC_ESCAPE) || mKeyboard->isKeyDown(OIS::KC_Q) )
  137. return false;
  138. if( mKeyboard->isKeyDown(OIS::KC_F) && mTimeUntilNextToggle <= 0 )
  139. {
  140. mStatsOn = !mStatsOn;
  141. showDebugOverlay(mStatsOn);
  142. mTimeUntilNextToggle = 1;
  143. }
  144. if( mKeyboard->isKeyDown(OIS::KC_T) && mTimeUntilNextToggle <= 0 )
  145. {
  146. switch(mFiltering)
  147. {
  148. case TFO_BILINEAR:
  149. mFiltering = TFO_TRILINEAR;
  150. mAniso = 1;
  151. break;
  152. case TFO_TRILINEAR:
  153. mFiltering = TFO_ANISOTROPIC;
  154. mAniso = 8;
  155. break;
  156. case TFO_ANISOTROPIC:
  157. mFiltering = TFO_BILINEAR;
  158. mAniso = 1;
  159. break;
  160. default: break;
  161. }
  162. MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
  163. MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);
  164. showDebugOverlay(mStatsOn);
  165. mTimeUntilNextToggle = 1;
  166. }
  167. if(mKeyboard->isKeyDown(OIS::KC_SYSRQ) && mTimeUntilNextToggle <= 0)
  168. {
  169. std::ostringstream ss;
  170. ss << "screenshot_" << ++mNumScreenShots << ".png";
  171. mWindow->writeContentsToFile(ss.str());
  172. mTimeUntilNextToggle = 0.5;
  173. mDebugText = "Saved: " + ss.str();
  174. }
  175. if(mKeyboard->isKeyDown(OIS::KC_R) && mTimeUntilNextToggle <=0)
  176. {
  177. mSceneDetailIndex = (mSceneDetailIndex+1)%3 ;
  178. switch(mSceneDetailIndex) {
  179. case 0 : mCamera->setPolygonMode(PM_SOLID); break;//设置多边形的模式
  180. case 1 : mCamera->setPolygonMode(PM_WIREFRAME); break;
  181. case 2 : mCamera->setPolygonMode(PM_POINTS); break;
  182. }
  183. mTimeUntilNextToggle = 0.5;
  184. }
  185. static bool displayCameraDetails = false;
  186. if(mKeyboard->isKeyDown(OIS::KC_P) && mTimeUntilNextToggle <= 0)
  187. {
  188. displayCameraDetails = !displayCameraDetails;
  189. mTimeUntilNextToggle = 0.5;
  190. if (!displayCameraDetails)
  191. mDebugText = "";
  192. }
  193. if(displayCameraDetails)
  194. mDebugText = "P: " + StringConverter::toString(mCamera->getDerivedPosition()) +
  195. " " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation());
  196. return true;
  197. }
  198. //鼠标事件处理
  199. virtual bool processUnbufferedMouseInput(const FrameEvent& evt)
  200. {
  201. // Rotation factors, may not be used if the second mouse button is pressed
  202. // 2nd mouse button - slide, otherwise rotate
  203. const OIS::MouseState &ms = mMouse->getMouseState();
  204. if( ms.buttonDown( OIS::MB_Right ) )
  205. {
  206. mTranslateVector.x += ms.X.rel * 0.13;
  207. mTranslateVector.y -= ms.Y.rel * 0.13;
  208. }
  209. else
  210. {
  211. mRotX = Degree(-ms.X.rel * 0.13);
  212. mRotY = Degree(-ms.Y.rel * 0.13);
  213. }
  214. return true;
  215. }
  216. //移动摄像头
  217. virtual void moveCamera()
  218. {
  219. //偏移
  220. mCamera->yaw(mRotX);
  221. //倾斜
  222. mCamera->pitch(mRotY);
  223. //移动摄像机到指定位置
  224. mCamera->moveRelative(mTranslateVector);
  225. }
  226. //显示debug信息
  227. virtual void showDebugOverlay(bool show)
  228. {
  229. if (mDebugOverlay)
  230. {
  231. if (show)
  232. mDebugOverlay->show();
  233. else
  234. mDebugOverlay->hide();
  235. }
  236. }
  237. // 渲染队列
  238. bool frameRenderingQueued(const FrameEvent& evt)
  239. {
  240. if(mWindow->isClosed())  return false;
  241. mSpeedLimit = mMoveScale * evt.timeSinceLastFrame;
  242. //捕获、更新设备
  243. mKeyboard->capture();
  244. mMouse->capture();
  245. if( mJoy ) mJoy->capture();
  246. bool buffJ = (mJoy) ? mJoy->buffered() : true;
  247. Ogre::Vector3 lastMotion = mTranslateVector;
  248. if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ )
  249. {
  250. // one of the input modes is immediate, so setup what is needed for immediate movement
  251. if (mTimeUntilNextToggle >= 0)
  252. mTimeUntilNextToggle -= evt.timeSinceLastFrame;
  253. // Move about 100 units per second
  254. mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
  255. // Take about 10 seconds for full rotation
  256. mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
  257. mRotX = 0;
  258. mRotY = 0;
  259. mTranslateVector = Ogre::Vector3::ZERO;
  260. }
  261. //Check to see which device is not buffered, and handle it
  262. if( !mKeyboard->buffered() )
  263. if( processUnbufferedKeyInput(evt) == false )
  264. return false;
  265. if( !mMouse->buffered() )
  266. if( processUnbufferedMouseInput(evt) == false )
  267. return false;
  268. // ramp up / ramp down speed
  269. if (mTranslateVector == Ogre::Vector3::ZERO)
  270. {
  271. // decay (one third speed)
  272. mCurrentSpeed -= evt.timeSinceLastFrame * 0.3;
  273. mTranslateVector = lastMotion;
  274. }
  275. else
  276. {
  277. // ramp up
  278. mCurrentSpeed += evt.timeSinceLastFrame;
  279. }
  280. // Limit motion speed
  281. if (mCurrentSpeed > 1.0)
  282. mCurrentSpeed = 1.0;
  283. if (mCurrentSpeed < 0.0)
  284. mCurrentSpeed = 0.0;
  285. mTranslateVector *= mCurrentSpeed;
  286. if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ )
  287. moveCamera();
  288. return true;
  289. }
  290. //帧结束,更新状态
  291. bool frameEnded(const FrameEvent& evt)
  292. {
  293. updateStats();
  294. return true;
  295. }
  296. protected:
  297. //指向摄像机的指针
  298. Camera* mCamera;
  299. //一个3维向量,用于摄像机的位置变换
  300. Vector3 mTranslateVector;
  301. Real mCurrentSpeed;
  302. //指向渲染窗口的指针
  303. RenderWindow* mWindow;
  304. //是否显示调试信息
  305. bool mStatsOn;
  306. //debug信息
  307. std::string mDebugText;
  308. //主要用于截图
  309. unsigned int mNumScreenShots;
  310. //该demo中,摄像机会旋转
  311. float mMoveScale;
  312. //速度限制
  313. float mSpeedLimit;
  314. //同样用于摄像机变换
  315. Degree mRotScale;
  316. //延时
  317. Real mTimeUntilNextToggle ;
  318. //鼠标旋转的角度,用于摄像机的更新
  319. Radian mRotX, mRotY;
  320. //纹理差值的类型,枚举类型
  321. TextureFilterOptions mFiltering;
  322. int mAniso;
  323. int mSceneDetailIndex ;
  324. //移动速度
  325. Real mMoveSpeed;
  326. //旋转速度
  327. Degree mRotateSpeed;
  328. //debug视图
  329. Overlay* mDebugOverlay;
  330. //一些输入设备(输入设备管理器)
  331. OIS::InputManager* mInputManager;
  332. //鼠标
  333. OIS::Mouse*    mMouse;
  334. //键盘
  335. OIS::Keyboard* mKeyboard;
  336. //摇杆
  337. OIS::JoyStick* mJoy;
  338. };
  339. #endif

接续(二)

转载于:https://blog.51cto.com/yarin/382498

ogre研究之第一个程序(一)相关推荐

  1. ogre研究之第一个程序(二)

    接续(一) 首先,我们要分析的就是Root类,使用Ogre的程序所需要作的第一件事情就是实例化一个Root对象.如果没有这个对象,你就无法调用(除了日志管理以外)的任何一个功能.Root类的构造函数接 ...

  2. 她,诗人拜伦之女,英国数学家,历史上第一位程序员

    作者丨吴军 来源丨大数据文摘 摘自丨<信息论> 人类使用机械处理信息的尝试是由两个看似不该有交集的英国人开启的. 在英格兰中部莱斯特郡的柯比-马洛里庄园,住着一对母女. 1816年初那个多 ...

  3. 世界上第一位程序员是位美女——AdaLovelace【有图为证】

    AdaLovelace画像   仙女一般吧.... 简介: 阿达·奥古斯塔,19世纪诗人拜伦的女儿,数学家.穿孔机程序创始人,建立了循环和子程序概念.为计算程序拟定"算法",写作的 ...

  4. 【C++教程】03.第一个程序解析

    第三章 第一个程序解析 前言 第一个程序也即是如何显示字符串"HelloWorld!",这是大多数程序员都走过的路.别提第一次成功编译时,我有多高兴,所以如果你还没编译成功,不要气 ...

  5. 世界上第一个程序员竟然是女性,难以置信......

    一说到程序员,人们的第一反应可能是–男的! 接着浮现在眼前的程序员标配是:眼镜,双肩包,格子衬衫,牛仔裤,运动鞋- 不难发现,在现代的IT公司里,从事编程工作的女性比例远远低于男性. 细数" ...

  6. 世界上第一位程序员,竟然是诗人拜伦的女儿?

    导读:女神节来了,数据叔终于忍不住要聊一聊这个憋了很久的八卦,世界上第一位程序员,当然也是世界上第一位女程序员--Ada. 作者:数据叔 来源:大数据DT(ID:hzdashuju) 这位女神级的神人 ...

  7. 一行代码没写,凭啥被尊为“第一位程序员”?

    作者 | Aholiab 出品 | 程序人生 (ID:coder _life) 阿达·拉芙莱斯,一个 IT 圈里人人都听过的名字.被称为「程序员的开山鼻祖」,但也存在着旷日持久的争议. 探索关于 Ad ...

  8. 中国第一代程序员潘爱民的 30 年程序人生

    作者 | 潘爱民 出品 | 程序员大本营 [编者按]搞技术是一件极其幸运的事情,不仅是我们迎来了最好的时代,亦在于我们的祖师爷大多还都健在甚至健谈,比如 Linux 之父 Linus Torvalds ...

  9. 百万畅销书带你学 Python:第一个程序

    第一个程序 你应该在习题0上花了不少的时间,学会了如何安装和运行文本编辑器,以及如何运行终端.如果你还没有完成这些练习,请不要继续往下进行,否则后面的学习过程会很痛苦.下面这个警告你不要跳过前面内容的 ...

最新文章

  1. Linux 网页挂马实验,网页挂马详细教程
  2. java script简介
  3. AndroidStudio_android开发在线文档_在线API_蓝牙开发在线文档---Android原生开发工作笔记243
  4. VC----SDK下对窗口非客户区的操作
  5. jQuery第一个孩子“这个”
  6. java 容器(联系数据结构)
  7. java的package需要大写吗,java 数字转大写的小程序
  8. 斗地主(二)———创建扑克牌基类枚举, 牌库,出牌规则
  9. 深度学习之CNN反向传播
  10. 基于Java的卡诺图化简
  11. Win10笔记本不显示WiFi列表
  12. 计算机安全模式怎么消除计,win10如何解除安全模式,教您如何解除电脑安全模式...
  13. Qt 绘制南丁格尔玫瑰图
  14. 在2016年,Linux是否还需要Windows的支持呢
  15. 面试官:说一说 Docker 原理
  16. 将字符串转换为singel类型
  17. 手工安装oracle的JVM包
  18. 揭秘成都Java培训班学费
  19. ai人工智能可以干什么_什么是情感AI,为什么要关心
  20. VulnHub Tomato

热门文章

  1. c语言参数不能用 吗,如何在C语言中禁止“未使用的参数”警告?
  2. golang 数组组合成最小的整数_golang数组-----寻找数组中缺失的整数方法
  3. 各层电子数排布规则_原子核外电子排布原理
  4. PythonPyqt5项目开发完成后如何使用pyinstaller打包——以Pycharm编辑器为例(目前为止最正确的版本,成功打包日期为2020.11.26)
  5. linux终端常用快捷键
  6. Systemd入门教程:命令篇
  7. java第四次上机作业_第十java上机作业
  8. linux .desktop权限,如何在Ubuntu Xenial Xerus 16.04 Linux Desktop上以root用户身份登录
  9. oracle 结果集已耗尽_java.sql.SQLException: 结果集已耗尽
  10. python四级中考有用的_一位中考生家长的后悔药:考前30多天,千万别做这7件傻事...