Main.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. #include "GLFW/glfw3.h"
  2. #include "common/Box.h"
  3. #include "common/Packets.h"
  4. #include "data/Array.h"
  5. #include "data/HashMap.h"
  6. #include "data/RingBuffer.h"
  7. #include "math/Frustum.h"
  8. #include "network/Client.h"
  9. #include "rendering/Shader.h"
  10. #include "rendering/Texture.h"
  11. #include "rendering/VertexBuffer.h"
  12. #include "rendering/Window.h"
  13. #include "utils/Buffer.h"
  14. static constexpr int WORLD_SIZE = 16;
  15. static Array<bool, WORLD_SIZE * WORLD_SIZE * WORLD_SIZE> world(true);
  16. static Shader shader;
  17. static Shader fontShader;
  18. static VertexBuffer vertexBuffer;
  19. static VertexBuffer markVertexBuffer;
  20. static VertexBuffer fontBuffer;
  21. static Texture fontTexture;
  22. static bool dirtyVertexBuffer = true;
  23. static int vertices = 0;
  24. static Frustum frustum(80.0f, 0.1f, 1000.0f);
  25. static Vector3 lastPosition(8.0f, 30.0f, 8.0f);
  26. static Vector3 position(lastPosition);
  27. static float lastWidthAngle = 0.0f;
  28. static float widthAngle = lastWidthAngle;
  29. static float lastLengthAngle = 0.0f;
  30. static float lengthAngle = lastLengthAngle;
  31. static Vector3 velocity;
  32. static Vector3 acceleration;
  33. static bool onGround = false;
  34. static Window::Controls::ButtonId leftKey;
  35. static Window::Controls::ButtonId rightKey;
  36. static Window::Controls::ButtonId upKey;
  37. static Window::Controls::ButtonId downKey;
  38. static Window::Controls::ButtonId jumpKey;
  39. static Window::Controls::ButtonId sneakKey;
  40. static Window::Controls::ButtonId escapeKey;
  41. static Window::Controls::ButtonId chatKey;
  42. static Window::Controls::ButtonId sendChatKey;
  43. static Window::Controls::ButtonId primaryClick;
  44. static bool trappedMoused = false;
  45. static Vector3 up;
  46. static Vector3 down;
  47. static Vector3 left;
  48. static Vector3 right;
  49. static Vector3 front;
  50. static Vector3 back;
  51. static Vector3 focus;
  52. static bool hasFocus = false;
  53. struct Player {
  54. Vector3 lastPosition;
  55. Vector3 position;
  56. };
  57. static HashMap<int, Player> players;
  58. typedef StringBuffer<50> ChatMessage;
  59. static Array<ChatMessage, 20> chat;
  60. static int chatIndex = 0;
  61. static bool renderInput = false;
  62. static void addToChat(const ChatMessage& msg) {
  63. chat[chatIndex] = msg;
  64. chatIndex = (chatIndex + 1) % chat.getLength();
  65. }
  66. static bool isRunning() {
  67. return !Window::shouldClose();
  68. // return !Window::shouldClose() &&
  69. // (Client::isConnecting() || Client::isConnected());
  70. }
  71. static void set(int x, int y, int z, bool b) {
  72. if(x < 0 || x >= WORLD_SIZE || y < 0 || y >= WORLD_SIZE || z < 0 ||
  73. z >= WORLD_SIZE) {
  74. return;
  75. }
  76. world[x * WORLD_SIZE * WORLD_SIZE + y * WORLD_SIZE + z] = b;
  77. dirtyVertexBuffer = true;
  78. }
  79. static void onPacket(InPacket& in) {
  80. uint8 type = 0;
  81. if(in.readU8(type)) {
  82. puts("no data");
  83. return;
  84. }
  85. switch(static_cast<Packet::Type>(type)) {
  86. case Packet::Type::WORLD: {
  87. for(bool& b : world) {
  88. uint8 data = 0;
  89. if(in.readU8(data)) {
  90. puts("too less data in world packet");
  91. return;
  92. }
  93. b = data;
  94. }
  95. dirtyVertexBuffer = true;
  96. break;
  97. }
  98. case Packet::Type::SET_BLOCK: {
  99. Vector3 pos;
  100. in.readFloat(pos[0]);
  101. in.readFloat(pos[1]);
  102. in.readFloat(pos[2]);
  103. uint8 type;
  104. in.readU8(type);
  105. set(pos[0], pos[1], pos[2], type);
  106. break;
  107. }
  108. case Packet::Type::PLAYER: {
  109. Vector3 pos;
  110. in.readFloat(pos[0]);
  111. in.readFloat(pos[1]);
  112. in.readFloat(pos[2]);
  113. int client = -1;
  114. in.readS32(client);
  115. Player* p = players.search(client);
  116. if(p != nullptr) {
  117. p->position = pos;
  118. } else {
  119. players.add(client, {pos, pos});
  120. }
  121. break;
  122. }
  123. case Packet::Type::CHAT: {
  124. ChatMessage msg;
  125. uint32 u;
  126. int i = 0;
  127. while(!in.readU32(u)) {
  128. i++;
  129. msg.appendUnicode(u);
  130. }
  131. printf("%d\n", i);
  132. addToChat(msg);
  133. break;
  134. }
  135. default: printf("invalid package type %d\n", static_cast<int>(type));
  136. }
  137. }
  138. static void onDisconnect() {
  139. puts("Disconnect");
  140. }
  141. static void addTriangle(Buffer& buffer, const Vector3& a, const Vector3& b,
  142. const Vector3& c) {
  143. Vector3 normal = (b - a).cross(c - a);
  144. buffer.add(a).add(normal).add(b).add(normal).add(c).add(normal);
  145. }
  146. static bool init() {
  147. Error e =
  148. shader.compile("resources/shader/test.vs", "resources/shader/test.fs");
  149. if(e.has()) {
  150. e.message.printLine();
  151. return true;
  152. }
  153. e = fontShader.compile("resources/shader/fontTest.vs",
  154. "resources/shader/fontTest.fs");
  155. if(e.has()) {
  156. e.message.printLine();
  157. return true;
  158. }
  159. e = fontTexture.load("resources/font8x8.png", 0);
  160. if(e.has()) {
  161. e.message.printLine();
  162. return true;
  163. }
  164. vertexBuffer.init(VertexBuffer::Attributes().addFloat(3).addFloat(3));
  165. markVertexBuffer.init(VertexBuffer::Attributes().addFloat(3).addFloat(3));
  166. fontBuffer.init(VertexBuffer::Attributes().addFloat(3).addFloat(2));
  167. Vector3 v000(0, 0, 0);
  168. Vector3 v001(0, 0, 1);
  169. Vector3 v010(0, 1, 0);
  170. Vector3 v011(0, 1, 1);
  171. Vector3 v100(1, 0, 0);
  172. Vector3 v101(1, 0, 1);
  173. Vector3 v110(1, 1, 0);
  174. Vector3 v111(1, 1, 1);
  175. Buffer buffer(100);
  176. addTriangle(buffer, v000, v100, v001);
  177. addTriangle(buffer, v100, v101, v001);
  178. addTriangle(buffer, v010, v011, v110);
  179. addTriangle(buffer, v110, v011, v111);
  180. addTriangle(buffer, v000, v001, v010);
  181. addTriangle(buffer, v001, v011, v010);
  182. addTriangle(buffer, v100, v110, v101);
  183. addTriangle(buffer, v101, v110, v111);
  184. addTriangle(buffer, v001, v101, v011);
  185. addTriangle(buffer, v111, v011, v101);
  186. addTriangle(buffer, v000, v010, v100);
  187. addTriangle(buffer, v110, v100, v010);
  188. markVertexBuffer.setStaticData(buffer.getLength(), buffer);
  189. Client::setPacketHandler(onPacket);
  190. Client::setDisconnectHandler(onDisconnect);
  191. leftKey = Window::Controls::add("Left");
  192. Window::Controls::bindKey(leftKey, GLFW_KEY_A);
  193. rightKey = Window::Controls::add("Right");
  194. Window::Controls::bindKey(rightKey, GLFW_KEY_D);
  195. upKey = Window::Controls::add("Up");
  196. Window::Controls::bindKey(upKey, GLFW_KEY_W);
  197. downKey = Window::Controls::add("Right");
  198. Window::Controls::bindKey(downKey, GLFW_KEY_S);
  199. jumpKey = Window::Controls::add("Jump");
  200. Window::Controls::bindKey(jumpKey, GLFW_KEY_SPACE);
  201. sneakKey = Window::Controls::add("Sneak");
  202. Window::Controls::bindKey(sneakKey, GLFW_KEY_LEFT_SHIFT);
  203. escapeKey = Window::Controls::add("Escape");
  204. Window::Controls::bindKey(escapeKey, GLFW_KEY_ESCAPE);
  205. chatKey = Window::Controls::add("Chat");
  206. Window::Controls::bindKey(chatKey, GLFW_KEY_T);
  207. sendChatKey = Window::Controls::add("Send Chat");
  208. Window::Controls::bindKey(sendChatKey, GLFW_KEY_ENTER);
  209. primaryClick = Window::Controls::add("Primary Click");
  210. Window::Controls::bindMouse(primaryClick, GLFW_MOUSE_BUTTON_LEFT);
  211. return false;
  212. }
  213. static void updateDirections(float lag) {
  214. front.setAngles(Math::interpolate(lastLengthAngle, lengthAngle, lag),
  215. Math::interpolate(lastWidthAngle, widthAngle, lag));
  216. back = -front;
  217. right = front.cross(Vector3(0.0f, 1.0f, 0.0f));
  218. right.normalize();
  219. left = -right;
  220. up = front.cross(left);
  221. down = -up;
  222. }
  223. static bool isAir(int x, int y, int z) {
  224. if(x < 0 || x >= WORLD_SIZE || y < 0 || y >= WORLD_SIZE || z < 0 ||
  225. z >= WORLD_SIZE) {
  226. return true;
  227. }
  228. return !world[x * WORLD_SIZE * WORLD_SIZE + y * WORLD_SIZE + z];
  229. }
  230. static List<Box> getBoxes(const Box& box) {
  231. int minX = floorf(box.getMin()[0]);
  232. int minY = floorf(box.getMin()[1]);
  233. int minZ = floorf(box.getMin()[2]);
  234. int maxX = floorf(box.getMax()[0]);
  235. int maxY = floorf(box.getMax()[1]);
  236. int maxZ = floorf(box.getMax()[2]);
  237. Box base(Vector3(1.0f, 1.0f, 1.0f));
  238. List<Box> boxes;
  239. for(int x = minX; x <= maxX; x++) {
  240. for(int y = minY; y <= maxY; y++) {
  241. for(int z = minZ; z <= maxZ; z++) {
  242. if(!isAir(x, y, z)) {
  243. boxes.add(base.offset(Vector3(x, y, z)));
  244. }
  245. }
  246. }
  247. }
  248. return boxes;
  249. }
  250. static Vector3 limitMove() {
  251. Vector3 move = velocity;
  252. Box box(Vector3(0.8f, 0.8f, 0.8f));
  253. box = box.offset(position - Vector3(0.4f, 0.0f, 0.4f));
  254. List<Box> boxes = getBoxes(box.expand(move));
  255. if(boxes.getLength() == 0) {
  256. return move;
  257. }
  258. Vector3 realMove;
  259. constexpr float step = 0.05f;
  260. while(move[0] != 0.0f || move[1] != 0.0f || move[2] != 0.0f) {
  261. for(int i = 0; i < 3; i++) {
  262. Vector3 old = realMove;
  263. if(move[i] > step) {
  264. realMove[i] += step;
  265. move[i] -= step;
  266. } else if(move[i] < -step) {
  267. realMove[i] -= step;
  268. move[i] += step;
  269. } else if(move[i] != 0.0f) {
  270. realMove[i] += move[i];
  271. move[i] = 0.0f;
  272. }
  273. Box moved = box.offset(realMove);
  274. for(const Box& box : boxes) {
  275. if(box.collidesWith(moved)) {
  276. move[i] = 0.0f;
  277. realMove = old;
  278. break;
  279. }
  280. }
  281. }
  282. }
  283. return realMove;
  284. }
  285. static void tick() {
  286. if(renderInput) {
  287. if(Window::Controls::wasReleased(sendChatKey)) {
  288. OutPacket out = Packet::build(Packet::Type::CHAT);
  289. for(uint32 u : Window::Input::getUnicode()) {
  290. out.writeU32(u);
  291. }
  292. Client::send(out, PacketType::RELIABLE);
  293. Window::Input::reset();
  294. }
  295. if(Window::Controls::wasReleased(escapeKey)) {
  296. Window::Input::disable();
  297. Window::trapCursor();
  298. trappedMoused = true;
  299. renderInput = false;
  300. }
  301. } else {
  302. if(Window::Controls::isDown(chatKey)) {
  303. Window::Input::enable();
  304. Window::freeCursor();
  305. trappedMoused = false;
  306. renderInput = true;
  307. }
  308. if(Window::Controls::wasReleased(primaryClick)) {
  309. Window::trapCursor();
  310. trappedMoused = true;
  311. }
  312. if(Window::Controls::wasReleased(escapeKey)) {
  313. Window::freeCursor();
  314. trappedMoused = false;
  315. }
  316. }
  317. lastPosition = position;
  318. lastWidthAngle = widthAngle;
  319. lastLengthAngle = lengthAngle;
  320. for(Player& p : players.values()) {
  321. p.lastPosition = p.position;
  322. }
  323. Client::tick();
  324. updateDirections(0.0f);
  325. Vector3 b = back;
  326. b[1] = 0.0f;
  327. b.normalize();
  328. Vector3 r = right;
  329. r[1] = 0.0f;
  330. r.normalize();
  331. if(!renderInput) {
  332. Vector3 force;
  333. if(Window::Controls::isDown(downKey)) {
  334. force += b;
  335. }
  336. if(Window::Controls::isDown(upKey)) {
  337. force -= b;
  338. }
  339. if(Window::Controls::isDown(leftKey)) {
  340. force -= r;
  341. }
  342. if(Window::Controls::isDown(rightKey)) {
  343. force += r;
  344. }
  345. if(force.squareLength() > 0.0f) {
  346. force.normalize();
  347. }
  348. acceleration += force * 0.1f;
  349. if(Window::Controls::isDown(jumpKey) && onGround) {
  350. acceleration[1] += (0.42f / 0.98f + 0.08f);
  351. }
  352. }
  353. if(trappedMoused) {
  354. Vector2 diff = (Window::Controls::getLastMousePosition() -
  355. Window::Controls::getMousePosition()) *
  356. 0.1f;
  357. widthAngle += diff[1];
  358. lengthAngle += diff[0];
  359. if(widthAngle > 89.0f) {
  360. widthAngle = 89.0f;
  361. }
  362. if(widthAngle < -89.0f) {
  363. widthAngle = -89.0f;
  364. }
  365. }
  366. hasFocus = false;
  367. Vector3 p = position + Vector3(0.0f, 0.8f, 0.0f);
  368. Vector3 step = front * 0.125f;
  369. for(int i = 0; i < 80; i++) {
  370. if(!isAir(p[0], p[1], p[2])) {
  371. hasFocus = true;
  372. focus = Vector3(static_cast<int>(p[0]), static_cast<int>(p[1]),
  373. static_cast<int>(p[2]));
  374. break;
  375. }
  376. p += step;
  377. }
  378. if(hasFocus && Window::Controls::wasReleased(primaryClick) &&
  379. !renderInput) {
  380. set(focus[0], focus[1], focus[2], false);
  381. dirtyVertexBuffer = true;
  382. OutPacket out = Packet::build(Packet::Type::SET_BLOCK);
  383. out.writeFloat(focus[0]);
  384. out.writeFloat(focus[1]);
  385. out.writeFloat(focus[2]);
  386. out.writeU8(0);
  387. Client::send(out, PacketType::RELIABLE);
  388. }
  389. OutPacket out = Packet::build(Packet::Type::PLAYER);
  390. out.writeFloat(position[0]);
  391. out.writeFloat(position[1]);
  392. out.writeFloat(position[2]);
  393. out.writeS32(-1);
  394. Client::send(out, PacketType::RELIABLE);
  395. velocity += acceleration;
  396. velocity *= Vector3(0.686f, 0.98f, 0.686f);
  397. acceleration = Vector3(0.0f, -0.08f, 0.0f);
  398. Vector3 move = limitMove();
  399. if(move[1] + position[1] < 0.0f) {
  400. move[1] = -position[1];
  401. }
  402. position += move;
  403. onGround = move[1] == 0.0f && velocity[1] < 0.0f;
  404. velocity = move;
  405. }
  406. static void addCube(Buffer& buffer, int x, int y, int z) {
  407. if(isAir(x, y, z)) {
  408. return;
  409. }
  410. Vector3 v000(x, y, z);
  411. Vector3 v001(x, y, z + 1);
  412. Vector3 v010(x, y + 1, z);
  413. Vector3 v011(x, y + 1, z + 1);
  414. Vector3 v100(x + 1, y, z);
  415. Vector3 v101(x + 1, y, z + 1);
  416. Vector3 v110(x + 1, y + 1, z);
  417. Vector3 v111(x + 1, y + 1, z + 1);
  418. if(isAir(x, y - 1, z)) {
  419. addTriangle(buffer, v000, v100, v001);
  420. addTriangle(buffer, v100, v101, v001);
  421. }
  422. if(isAir(x, y + 1, z)) {
  423. addTriangle(buffer, v010, v011, v110);
  424. addTriangle(buffer, v110, v011, v111);
  425. }
  426. if(isAir(x - 1, y, z)) {
  427. addTriangle(buffer, v000, v001, v010);
  428. addTriangle(buffer, v001, v011, v010);
  429. }
  430. if(isAir(x + 1, y, z)) {
  431. addTriangle(buffer, v100, v110, v101);
  432. addTriangle(buffer, v101, v110, v111);
  433. }
  434. if(isAir(x, y, z + 1)) {
  435. addTriangle(buffer, v001, v101, v011);
  436. addTriangle(buffer, v111, v011, v101);
  437. }
  438. if(isAir(x, y, z - 1)) {
  439. addTriangle(buffer, v000, v010, v100);
  440. addTriangle(buffer, v110, v100, v010);
  441. }
  442. }
  443. static void buildRenderingBuffer() {
  444. Buffer buffer(100);
  445. for(int x = 0; x < WORLD_SIZE; x++) {
  446. for(int y = 0; y < WORLD_SIZE; y++) {
  447. for(int z = 0; z < WORLD_SIZE; z++) {
  448. addCube(buffer, x, y, z);
  449. }
  450. }
  451. }
  452. vertices = buffer.getLength() / (2 * sizeof(Vector3));
  453. vertexBuffer.setStaticData(buffer.getLength(), buffer);
  454. }
  455. static void renderString(const char* text) {
  456. static Buffer buffer(50);
  457. buffer.clear();
  458. constexpr float fontSize = 8.0f;
  459. constexpr float fontStep = 8.0f / 128.0f;
  460. int index = 0;
  461. Vector3 pos;
  462. int vertices = 0;
  463. while(text[index] != '\0') {
  464. Vector3 right = pos + Vector3(fontSize, 0.0f, 0.0f);
  465. Vector3 down = pos + Vector3(0.0f, fontSize, 0.0f);
  466. Vector3 downRight = pos + Vector3(fontSize, fontSize, 0.0f);
  467. int i = text[index];
  468. if(i < 0 && text[index + 1] != '\0') {
  469. index++;
  470. i = ((i & 0x1F) << 6) | (text[index] & 0x3F);
  471. }
  472. Vector2 tPos(fontStep * (i % 16), fontStep * (i / 16));
  473. Vector2 tRight = tPos + Vector2(fontStep, 0.0f);
  474. Vector2 tDown = tPos + Vector2(0.0f, fontStep);
  475. Vector2 tDownRight = tPos + Vector2(fontStep, fontStep);
  476. buffer.add(pos).add(tPos).add(down).add(tDown).add(right).add(tRight);
  477. buffer.add(down).add(tDown).add(right).add(tRight).add(downRight).add(
  478. tDownRight);
  479. pos += Vector3(fontSize, 0.0f, 0.0f);
  480. vertices += 6;
  481. index++;
  482. }
  483. fontBuffer.setDynamicData(buffer.getLength(), buffer);
  484. fontBuffer.draw(vertices);
  485. }
  486. static void render(float lag) {
  487. GL::clear();
  488. GL::enableDepthTesting();
  489. if(dirtyVertexBuffer) {
  490. dirtyVertexBuffer = false;
  491. buildRenderingBuffer();
  492. puts("rebuilt buffer");
  493. }
  494. shader.use();
  495. GL::setViewport(Window::getSize()[0], Window::getSize()[1]);
  496. const Matrix& proj = frustum.updateProjection(Window::getSize());
  497. shader.setMatrix("proj", proj.getValues());
  498. updateDirections(lag);
  499. Matrix view;
  500. Vector3 center = Math::interpolate(lastPosition, position, lag) +
  501. Vector3(0.0f, 0.8f, 0.0f);
  502. view.set(0, Vector4(right[0], right[1], right[2], right.dot(-center)));
  503. view.set(1, Vector4(up[0], up[1], up[2], up.dot(-center)));
  504. view.set(2, Vector4(back[0], back[1], back[2], back.dot(-center)));
  505. view.set(3, Vector4(0.0f, 0.0f, 0.0f, 1.0f));
  506. shader.setMatrix("view", view.getValues());
  507. shader.setVector("color", Vector3(1.0f, 1.0f, 1.0f));
  508. Matrix model;
  509. shader.setMatrix("model", model.getValues());
  510. vertexBuffer.draw(vertices);
  511. if(hasFocus) {
  512. shader.setVector("color", Vector3(0.8f, 0.6f, 0.6f));
  513. model.translate(Vector3(-0.5f, -0.5f, -0.5f));
  514. model.scale(1.01f);
  515. model.translate(Vector3(0.5f, 0.5f, 0.5f));
  516. model.translate(focus);
  517. shader.setMatrix("model", model.getValues());
  518. markVertexBuffer.draw(36);
  519. }
  520. shader.setVector("color", Vector3(1.0f, 0.0f, 0.0f));
  521. for(const Player& p : players.values()) {
  522. model.translateTo(Vector3(-0.5f, -0.5f, -0.5f));
  523. model.scale(0.8f);
  524. model.translate(Math::interpolate(p.lastPosition, p.position, lag) +
  525. Vector3(0.0f, 0.4f, 0.0f));
  526. shader.setMatrix("model", model.getValues());
  527. markVertexBuffer.draw(36);
  528. }
  529. shader.setMatrix("proj", Matrix().getValues());
  530. shader.setMatrix("view", Matrix().getValues());
  531. shader.setVector("color", Vector3(1.0f, 0.0f, 1.0f));
  532. model.translateTo(Vector3(-0.5f, -0.5f, -0.5f));
  533. model.scale(0.05f);
  534. shader.setMatrix("model", model.getValues());
  535. markVertexBuffer.draw(36);
  536. GL::disableDepthTesting();
  537. GL::enableBlending();
  538. fontShader.use();
  539. fontShader.setMatrix("proj", Matrix().getValues());
  540. view.translateTo(Vector3(0.0f, 0.0f, 0.0f));
  541. IntVector2 size = Window::getSize();
  542. view.scale(Vector3(2.0f / size[0], -2.0f / size[1], 1.0f));
  543. view.translate(Vector3(-1.0f, 1.0f, 0.0f));
  544. fontShader.setMatrix("view", view.getValues());
  545. fontTexture.bindTo(0);
  546. for(int i = 0; i < chat.getLength(); i++) {
  547. model.translateTo(Vector3(0.0f, i * 8.0f, 0.0f)).scale(3.0f);
  548. fontShader.setMatrix("model", model.getValues());
  549. renderString(chat[(i + chatIndex) % chat.getLength()]);
  550. }
  551. if(renderInput) {
  552. model.translateTo(Vector3(0.0f, chat.getLength() * 8.0f, 0.0f))
  553. .scale(3.0f);
  554. fontShader.setMatrix("model", model.getValues());
  555. StringBuffer<256> s;
  556. Window::Input::toString(s);
  557. renderString(s);
  558. model
  559. .translateTo(Vector3(Window::Input::getCursor() * 8.0f,
  560. chat.getLength() * 8.0f + 2.0f, 0.0f))
  561. .scale(3.0f);
  562. fontShader.setMatrix("model", model.getValues());
  563. renderString("_");
  564. }
  565. GL::disableBlending();
  566. }
  567. int main(int argAmount, const char* const* args) {
  568. const char* server = "127.0.0.1";
  569. if(argAmount >= 2) {
  570. server = args[1];
  571. }
  572. Error e = Client::start();
  573. if(e.has()) {
  574. e.message.printLine();
  575. return 0;
  576. }
  577. e = Client::connect(server, 11196, 40);
  578. if(e.has()) {
  579. e.message.printLine();
  580. return 0;
  581. }
  582. Window::Options options(4, 3, IntVector2(1024, 600), false, "test");
  583. e = Window::open(options);
  584. if(e.has()) {
  585. e.message.printLine();
  586. Client::stop();
  587. return 0;
  588. }
  589. if(init()) {
  590. Client::stop();
  591. return 0;
  592. }
  593. Window::show();
  594. Window::run<isRunning, tick, render>(50'000'000);
  595. Window::close();
  596. Client::stop();
  597. return 0;
  598. }