|
@@ -1,11 +1,660 @@
|
|
-#include "client/Game.h"
|
|
+#include "GLFW/glfw3.h"
|
|
-#include "client/GameClient.h"
|
|
|
|
-#include "client/rendering/Engine.h"
|
|
|
|
|
|
|
|
-int main() {
|
|
+#include "common/Box.h"
|
|
- if(GameClient::init() || Engine::init() || Game::init()) {
|
|
+#include "common/Packets.h"
|
|
|
|
+#include "data/Array.h"
|
|
|
|
+#include "data/HashMap.h"
|
|
|
|
+#include "data/RingBuffer.h"
|
|
|
|
+#include "math/Frustum.h"
|
|
|
|
+#include "network/Client.h"
|
|
|
|
+#include "rendering/Shader.h"
|
|
|
|
+#include "rendering/Texture.h"
|
|
|
|
+#include "rendering/VertexBuffer.h"
|
|
|
|
+#include "rendering/Window.h"
|
|
|
|
+#include "utils/Buffer.h"
|
|
|
|
+
|
|
|
|
+static constexpr int WORLD_SIZE = 16;
|
|
|
|
+
|
|
|
|
+static Array<bool, WORLD_SIZE * WORLD_SIZE * WORLD_SIZE> world(true);
|
|
|
|
+static Shader shader;
|
|
|
|
+static Shader fontShader;
|
|
|
|
+static VertexBuffer vertexBuffer;
|
|
|
|
+static VertexBuffer markVertexBuffer;
|
|
|
|
+static VertexBuffer fontBuffer;
|
|
|
|
+static Texture fontTexture;
|
|
|
|
+static bool dirtyVertexBuffer = true;
|
|
|
|
+static int vertices = 0;
|
|
|
|
+static Frustum frustum(80.0f, 0.1f, 1000.0f);
|
|
|
|
+
|
|
|
|
+static Vector3 lastPosition(8.0f, 30.0f, 8.0f);
|
|
|
|
+static Vector3 position(lastPosition);
|
|
|
|
+static float lastWidthAngle = 0.0f;
|
|
|
|
+static float widthAngle = lastWidthAngle;
|
|
|
|
+static float lastLengthAngle = 0.0f;
|
|
|
|
+static float lengthAngle = lastLengthAngle;
|
|
|
|
+static Vector3 velocity;
|
|
|
|
+static Vector3 acceleration;
|
|
|
|
+static bool onGround = false;
|
|
|
|
+
|
|
|
|
+static Window::Controls::ButtonId leftKey;
|
|
|
|
+static Window::Controls::ButtonId rightKey;
|
|
|
|
+static Window::Controls::ButtonId upKey;
|
|
|
|
+static Window::Controls::ButtonId downKey;
|
|
|
|
+static Window::Controls::ButtonId jumpKey;
|
|
|
|
+static Window::Controls::ButtonId sneakKey;
|
|
|
|
+static Window::Controls::ButtonId escapeKey;
|
|
|
|
+static Window::Controls::ButtonId chatKey;
|
|
|
|
+static Window::Controls::ButtonId sendChatKey;
|
|
|
|
+static Window::Controls::ButtonId primaryClick;
|
|
|
|
+
|
|
|
|
+static bool trappedMoused = false;
|
|
|
|
+
|
|
|
|
+static Vector3 up;
|
|
|
|
+static Vector3 down;
|
|
|
|
+static Vector3 left;
|
|
|
|
+static Vector3 right;
|
|
|
|
+static Vector3 front;
|
|
|
|
+static Vector3 back;
|
|
|
|
+
|
|
|
|
+static Vector3 focus;
|
|
|
|
+static bool hasFocus = false;
|
|
|
|
+
|
|
|
|
+struct Player {
|
|
|
|
+ Vector3 lastPosition;
|
|
|
|
+ Vector3 position;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static HashMap<int, Player> players;
|
|
|
|
+
|
|
|
|
+typedef StringBuffer<50> ChatMessage;
|
|
|
|
+static Array<ChatMessage, 20> chat;
|
|
|
|
+static int chatIndex = 0;
|
|
|
|
+static bool renderInput = false;
|
|
|
|
+
|
|
|
|
+static void addToChat(const ChatMessage& msg) {
|
|
|
|
+ chat[chatIndex] = msg;
|
|
|
|
+ chatIndex = (chatIndex + 1) % chat.getLength();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool isRunning() {
|
|
|
|
+ return !Window::shouldClose();
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void set(int x, int y, int z, bool b) {
|
|
|
|
+ if(x < 0 || x >= WORLD_SIZE || y < 0 || y >= WORLD_SIZE || z < 0 ||
|
|
|
|
+ z >= WORLD_SIZE) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ world[x * WORLD_SIZE * WORLD_SIZE + y * WORLD_SIZE + z] = b;
|
|
|
|
+ dirtyVertexBuffer = true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void onPacket(InPacket& in) {
|
|
|
|
+ uint8 type = 0;
|
|
|
|
+ if(in.readU8(type)) {
|
|
|
|
+ puts("no data");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ switch(static_cast<Packet::Type>(type)) {
|
|
|
|
+ case Packet::Type::WORLD: {
|
|
|
|
+ for(bool& b : world) {
|
|
|
|
+ uint8 data = 0;
|
|
|
|
+ if(in.readU8(data)) {
|
|
|
|
+ puts("too less data in world packet");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ b = data;
|
|
|
|
+ }
|
|
|
|
+ dirtyVertexBuffer = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case Packet::Type::SET_BLOCK: {
|
|
|
|
+ Vector3 pos;
|
|
|
|
+ in.readFloat(pos[0]);
|
|
|
|
+ in.readFloat(pos[1]);
|
|
|
|
+ in.readFloat(pos[2]);
|
|
|
|
+ uint8 type;
|
|
|
|
+ in.readU8(type);
|
|
|
|
+ set(pos[0], pos[1], pos[2], type);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case Packet::Type::PLAYER: {
|
|
|
|
+ Vector3 pos;
|
|
|
|
+ in.readFloat(pos[0]);
|
|
|
|
+ in.readFloat(pos[1]);
|
|
|
|
+ in.readFloat(pos[2]);
|
|
|
|
+ int client = -1;
|
|
|
|
+ in.readS32(client);
|
|
|
|
+
|
|
|
|
+ Player* p = players.search(client);
|
|
|
|
+ if(p != nullptr) {
|
|
|
|
+ p->position = pos;
|
|
|
|
+ } else {
|
|
|
|
+ players.add(client, {pos, pos});
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case Packet::Type::CHAT: {
|
|
|
|
+ ChatMessage msg;
|
|
|
|
+ uint32 u;
|
|
|
|
+ int i = 0;
|
|
|
|
+ while(!in.readU32(u)) {
|
|
|
|
+ i++;
|
|
|
|
+ msg.appendUnicode(u);
|
|
|
|
+ }
|
|
|
|
+ printf("%d\n", i);
|
|
|
|
+ addToChat(msg);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ default: printf("invalid package type %d\n", static_cast<int>(type));
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void onDisconnect() {
|
|
|
|
+ puts("Disconnect");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void addTriangle(Buffer& buffer, const Vector3& a, const Vector3& b,
|
|
|
|
+ const Vector3& c) {
|
|
|
|
+ Vector3 normal = (b - a).cross(c - a);
|
|
|
|
+ buffer.add(a).add(normal).add(b).add(normal).add(c).add(normal);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool init() {
|
|
|
|
+ Error e =
|
|
|
|
+ shader.compile("resources/shader/test.vs", "resources/shader/test.fs");
|
|
|
|
+ if(e.has()) {
|
|
|
|
+ e.message.printLine();
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ e = fontShader.compile("resources/shader/fontTest.vs",
|
|
|
|
+ "resources/shader/fontTest.fs");
|
|
|
|
+ if(e.has()) {
|
|
|
|
+ e.message.printLine();
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ e = fontTexture.load("resources/font8x8.png", 0);
|
|
|
|
+ if(e.has()) {
|
|
|
|
+ e.message.printLine();
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ vertexBuffer.init(VertexBuffer::Attributes().addFloat(3).addFloat(3));
|
|
|
|
+ markVertexBuffer.init(VertexBuffer::Attributes().addFloat(3).addFloat(3));
|
|
|
|
+ fontBuffer.init(VertexBuffer::Attributes().addFloat(3).addFloat(2));
|
|
|
|
+
|
|
|
|
+ Vector3 v000(0, 0, 0);
|
|
|
|
+ Vector3 v001(0, 0, 1);
|
|
|
|
+ Vector3 v010(0, 1, 0);
|
|
|
|
+ Vector3 v011(0, 1, 1);
|
|
|
|
+ Vector3 v100(1, 0, 0);
|
|
|
|
+ Vector3 v101(1, 0, 1);
|
|
|
|
+ Vector3 v110(1, 1, 0);
|
|
|
|
+ Vector3 v111(1, 1, 1);
|
|
|
|
+
|
|
|
|
+ Buffer buffer(100);
|
|
|
|
+ addTriangle(buffer, v000, v100, v001);
|
|
|
|
+ addTriangle(buffer, v100, v101, v001);
|
|
|
|
+ addTriangle(buffer, v010, v011, v110);
|
|
|
|
+ addTriangle(buffer, v110, v011, v111);
|
|
|
|
+ addTriangle(buffer, v000, v001, v010);
|
|
|
|
+ addTriangle(buffer, v001, v011, v010);
|
|
|
|
+ addTriangle(buffer, v100, v110, v101);
|
|
|
|
+ addTriangle(buffer, v101, v110, v111);
|
|
|
|
+ addTriangle(buffer, v001, v101, v011);
|
|
|
|
+ addTriangle(buffer, v111, v011, v101);
|
|
|
|
+ addTriangle(buffer, v000, v010, v100);
|
|
|
|
+ addTriangle(buffer, v110, v100, v010);
|
|
|
|
+ markVertexBuffer.setStaticData(buffer.getLength(), buffer);
|
|
|
|
+
|
|
|
|
+ Client::setPacketHandler(onPacket);
|
|
|
|
+ Client::setDisconnectHandler(onDisconnect);
|
|
|
|
+
|
|
|
|
+ leftKey = Window::Controls::add("Left");
|
|
|
|
+ Window::Controls::bindKey(leftKey, GLFW_KEY_A);
|
|
|
|
+ rightKey = Window::Controls::add("Right");
|
|
|
|
+ Window::Controls::bindKey(rightKey, GLFW_KEY_D);
|
|
|
|
+ upKey = Window::Controls::add("Up");
|
|
|
|
+ Window::Controls::bindKey(upKey, GLFW_KEY_W);
|
|
|
|
+ downKey = Window::Controls::add("Right");
|
|
|
|
+ Window::Controls::bindKey(downKey, GLFW_KEY_S);
|
|
|
|
+ jumpKey = Window::Controls::add("Jump");
|
|
|
|
+ Window::Controls::bindKey(jumpKey, GLFW_KEY_SPACE);
|
|
|
|
+ sneakKey = Window::Controls::add("Sneak");
|
|
|
|
+ Window::Controls::bindKey(sneakKey, GLFW_KEY_LEFT_SHIFT);
|
|
|
|
+ escapeKey = Window::Controls::add("Escape");
|
|
|
|
+ Window::Controls::bindKey(escapeKey, GLFW_KEY_ESCAPE);
|
|
|
|
+ chatKey = Window::Controls::add("Chat");
|
|
|
|
+ Window::Controls::bindKey(chatKey, GLFW_KEY_T);
|
|
|
|
+ sendChatKey = Window::Controls::add("Send Chat");
|
|
|
|
+ Window::Controls::bindKey(sendChatKey, GLFW_KEY_ENTER);
|
|
|
|
+ primaryClick = Window::Controls::add("Primary Click");
|
|
|
|
+ Window::Controls::bindMouse(primaryClick, GLFW_MOUSE_BUTTON_LEFT);
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void updateDirections(float lag) {
|
|
|
|
+ front.setAngles(Math::interpolate(lastLengthAngle, lengthAngle, lag),
|
|
|
|
+ Math::interpolate(lastWidthAngle, widthAngle, lag));
|
|
|
|
+ back = -front;
|
|
|
|
+ right = front.cross(Vector3(0.0f, 1.0f, 0.0f));
|
|
|
|
+ right.normalize();
|
|
|
|
+ left = -right;
|
|
|
|
+ up = front.cross(left);
|
|
|
|
+ down = -up;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool isAir(int x, int y, int z) {
|
|
|
|
+ if(x < 0 || x >= WORLD_SIZE || y < 0 || y >= WORLD_SIZE || z < 0 ||
|
|
|
|
+ z >= WORLD_SIZE) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return !world[x * WORLD_SIZE * WORLD_SIZE + y * WORLD_SIZE + z];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static List<Box> getBoxes(const Box& box) {
|
|
|
|
+ int minX = floorf(box.getMin()[0]);
|
|
|
|
+ int minY = floorf(box.getMin()[1]);
|
|
|
|
+ int minZ = floorf(box.getMin()[2]);
|
|
|
|
+ int maxX = floorf(box.getMax()[0]);
|
|
|
|
+ int maxY = floorf(box.getMax()[1]);
|
|
|
|
+ int maxZ = floorf(box.getMax()[2]);
|
|
|
|
+
|
|
|
|
+ Box base(Vector3(1.0f, 1.0f, 1.0f));
|
|
|
|
+ List<Box> boxes;
|
|
|
|
+ for(int x = minX; x <= maxX; x++) {
|
|
|
|
+ for(int y = minY; y <= maxY; y++) {
|
|
|
|
+ for(int z = minZ; z <= maxZ; z++) {
|
|
|
|
+ if(!isAir(x, y, z)) {
|
|
|
|
+ boxes.add(base.offset(Vector3(x, y, z)));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return boxes;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static Vector3 limitMove() {
|
|
|
|
+ Vector3 move = velocity;
|
|
|
|
+ Box box(Vector3(0.8f, 0.8f, 0.8f));
|
|
|
|
+ box = box.offset(position - Vector3(0.4f, 0.0f, 0.4f));
|
|
|
|
+
|
|
|
|
+ List<Box> boxes = getBoxes(box.expand(move));
|
|
|
|
+ if(boxes.getLength() == 0) {
|
|
|
|
+ return move;
|
|
|
|
+ }
|
|
|
|
+ Vector3 realMove;
|
|
|
|
+
|
|
|
|
+ constexpr float step = 0.05f;
|
|
|
|
+ while(move[0] != 0.0f || move[1] != 0.0f || move[2] != 0.0f) {
|
|
|
|
+ for(int i = 0; i < 3; i++) {
|
|
|
|
+ Vector3 old = realMove;
|
|
|
|
+ if(move[i] > step) {
|
|
|
|
+ realMove[i] += step;
|
|
|
|
+ move[i] -= step;
|
|
|
|
+ } else if(move[i] < -step) {
|
|
|
|
+ realMove[i] -= step;
|
|
|
|
+ move[i] += step;
|
|
|
|
+ } else if(move[i] != 0.0f) {
|
|
|
|
+ realMove[i] += move[i];
|
|
|
|
+ move[i] = 0.0f;
|
|
|
|
+ }
|
|
|
|
+ Box moved = box.offset(realMove);
|
|
|
|
+ for(const Box& box : boxes) {
|
|
|
|
+ if(box.collidesWith(moved)) {
|
|
|
|
+ move[i] = 0.0f;
|
|
|
|
+ realMove = old;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return realMove;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void tick() {
|
|
|
|
+ if(renderInput) {
|
|
|
|
+ if(Window::Controls::wasReleased(sendChatKey)) {
|
|
|
|
+ OutPacket out = Packet::build(Packet::Type::CHAT);
|
|
|
|
+ for(uint32 u : Window::Input::getUnicode()) {
|
|
|
|
+ out.writeU32(u);
|
|
|
|
+ }
|
|
|
|
+ Client::send(out, PacketType::RELIABLE);
|
|
|
|
+ Window::Input::reset();
|
|
|
|
+ }
|
|
|
|
+ if(Window::Controls::wasReleased(escapeKey)) {
|
|
|
|
+ Window::Input::disable();
|
|
|
|
+ Window::trapCursor();
|
|
|
|
+ trappedMoused = true;
|
|
|
|
+ renderInput = false;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if(Window::Controls::isDown(chatKey)) {
|
|
|
|
+ Window::Input::enable();
|
|
|
|
+ Window::freeCursor();
|
|
|
|
+ trappedMoused = false;
|
|
|
|
+ renderInput = true;
|
|
|
|
+ }
|
|
|
|
+ if(Window::Controls::wasReleased(primaryClick)) {
|
|
|
|
+ Window::trapCursor();
|
|
|
|
+ trappedMoused = true;
|
|
|
|
+ }
|
|
|
|
+ if(Window::Controls::wasReleased(escapeKey)) {
|
|
|
|
+ Window::freeCursor();
|
|
|
|
+ trappedMoused = false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ lastPosition = position;
|
|
|
|
+ lastWidthAngle = widthAngle;
|
|
|
|
+ lastLengthAngle = lengthAngle;
|
|
|
|
+
|
|
|
|
+ for(Player& p : players.values()) {
|
|
|
|
+ p.lastPosition = p.position;
|
|
|
|
+ }
|
|
|
|
+ Client::tick();
|
|
|
|
+
|
|
|
|
+ updateDirections(0.0f);
|
|
|
|
+
|
|
|
|
+ Vector3 b = back;
|
|
|
|
+ b[1] = 0.0f;
|
|
|
|
+ b.normalize();
|
|
|
|
+
|
|
|
|
+ Vector3 r = right;
|
|
|
|
+ r[1] = 0.0f;
|
|
|
|
+ r.normalize();
|
|
|
|
+
|
|
|
|
+ if(!renderInput) {
|
|
|
|
+ Vector3 force;
|
|
|
|
+ if(Window::Controls::isDown(downKey)) {
|
|
|
|
+ force += b;
|
|
|
|
+ }
|
|
|
|
+ if(Window::Controls::isDown(upKey)) {
|
|
|
|
+ force -= b;
|
|
|
|
+ }
|
|
|
|
+ if(Window::Controls::isDown(leftKey)) {
|
|
|
|
+ force -= r;
|
|
|
|
+ }
|
|
|
|
+ if(Window::Controls::isDown(rightKey)) {
|
|
|
|
+ force += r;
|
|
|
|
+ }
|
|
|
|
+ if(force.squareLength() > 0.0f) {
|
|
|
|
+ force.normalize();
|
|
|
|
+ }
|
|
|
|
+ acceleration += force * 0.1f;
|
|
|
|
+
|
|
|
|
+ if(Window::Controls::isDown(jumpKey) && onGround) {
|
|
|
|
+ acceleration[1] += (0.42f / 0.98f + 0.08f);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(trappedMoused) {
|
|
|
|
+ Vector2 diff = (Window::Controls::getLastMousePosition() -
|
|
|
|
+ Window::Controls::getMousePosition()) *
|
|
|
|
+ 0.1f;
|
|
|
|
+ widthAngle += diff[1];
|
|
|
|
+ lengthAngle += diff[0];
|
|
|
|
+ if(widthAngle > 89.0f) {
|
|
|
|
+ widthAngle = 89.0f;
|
|
|
|
+ }
|
|
|
|
+ if(widthAngle < -89.0f) {
|
|
|
|
+ widthAngle = -89.0f;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ hasFocus = false;
|
|
|
|
+ Vector3 p = position + Vector3(0.0f, 0.8f, 0.0f);
|
|
|
|
+ Vector3 step = front * 0.125f;
|
|
|
|
+ for(int i = 0; i < 80; i++) {
|
|
|
|
+ if(!isAir(p[0], p[1], p[2])) {
|
|
|
|
+ hasFocus = true;
|
|
|
|
+ focus = Vector3(static_cast<int>(p[0]), static_cast<int>(p[1]),
|
|
|
|
+ static_cast<int>(p[2]));
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ p += step;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(hasFocus && Window::Controls::wasReleased(primaryClick) &&
|
|
|
|
+ !renderInput) {
|
|
|
|
+ set(focus[0], focus[1], focus[2], false);
|
|
|
|
+ dirtyVertexBuffer = true;
|
|
|
|
+
|
|
|
|
+ OutPacket out = Packet::build(Packet::Type::SET_BLOCK);
|
|
|
|
+ out.writeFloat(focus[0]);
|
|
|
|
+ out.writeFloat(focus[1]);
|
|
|
|
+ out.writeFloat(focus[2]);
|
|
|
|
+ out.writeU8(0);
|
|
|
|
+ Client::send(out, PacketType::RELIABLE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ OutPacket out = Packet::build(Packet::Type::PLAYER);
|
|
|
|
+ out.writeFloat(position[0]);
|
|
|
|
+ out.writeFloat(position[1]);
|
|
|
|
+ out.writeFloat(position[2]);
|
|
|
|
+ out.writeS32(-1);
|
|
|
|
+ Client::send(out, PacketType::RELIABLE);
|
|
|
|
+
|
|
|
|
+ velocity += acceleration;
|
|
|
|
+ velocity *= Vector3(0.686f, 0.98f, 0.686f);
|
|
|
|
+ acceleration = Vector3(0.0f, -0.08f, 0.0f);
|
|
|
|
+
|
|
|
|
+ Vector3 move = limitMove();
|
|
|
|
+ if(move[1] + position[1] < 0.0f) {
|
|
|
|
+ move[1] = -position[1];
|
|
|
|
+ }
|
|
|
|
+ position += move;
|
|
|
|
+ onGround = move[1] == 0.0f && velocity[1] < 0.0f;
|
|
|
|
+ velocity = move;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void addCube(Buffer& buffer, int x, int y, int z) {
|
|
|
|
+ if(isAir(x, y, z)) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ Vector3 v000(x, y, z);
|
|
|
|
+ Vector3 v001(x, y, z + 1);
|
|
|
|
+ Vector3 v010(x, y + 1, z);
|
|
|
|
+ Vector3 v011(x, y + 1, z + 1);
|
|
|
|
+ Vector3 v100(x + 1, y, z);
|
|
|
|
+ Vector3 v101(x + 1, y, z + 1);
|
|
|
|
+ Vector3 v110(x + 1, y + 1, z);
|
|
|
|
+ Vector3 v111(x + 1, y + 1, z + 1);
|
|
|
|
+
|
|
|
|
+ if(isAir(x, y - 1, z)) {
|
|
|
|
+ addTriangle(buffer, v000, v100, v001);
|
|
|
|
+ addTriangle(buffer, v100, v101, v001);
|
|
|
|
+ }
|
|
|
|
+ if(isAir(x, y + 1, z)) {
|
|
|
|
+ addTriangle(buffer, v010, v011, v110);
|
|
|
|
+ addTriangle(buffer, v110, v011, v111);
|
|
|
|
+ }
|
|
|
|
+ if(isAir(x - 1, y, z)) {
|
|
|
|
+ addTriangle(buffer, v000, v001, v010);
|
|
|
|
+ addTriangle(buffer, v001, v011, v010);
|
|
|
|
+ }
|
|
|
|
+ if(isAir(x + 1, y, z)) {
|
|
|
|
+ addTriangle(buffer, v100, v110, v101);
|
|
|
|
+ addTriangle(buffer, v101, v110, v111);
|
|
|
|
+ }
|
|
|
|
+ if(isAir(x, y, z + 1)) {
|
|
|
|
+ addTriangle(buffer, v001, v101, v011);
|
|
|
|
+ addTriangle(buffer, v111, v011, v101);
|
|
|
|
+ }
|
|
|
|
+ if(isAir(x, y, z - 1)) {
|
|
|
|
+ addTriangle(buffer, v000, v010, v100);
|
|
|
|
+ addTriangle(buffer, v110, v100, v010);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void buildRenderingBuffer() {
|
|
|
|
+ Buffer buffer(100);
|
|
|
|
+ for(int x = 0; x < WORLD_SIZE; x++) {
|
|
|
|
+ for(int y = 0; y < WORLD_SIZE; y++) {
|
|
|
|
+ for(int z = 0; z < WORLD_SIZE; z++) {
|
|
|
|
+ addCube(buffer, x, y, z);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ vertices = buffer.getLength() / (2 * sizeof(Vector3));
|
|
|
|
+ vertexBuffer.setStaticData(buffer.getLength(), buffer);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void renderString(const char* text) {
|
|
|
|
+ static Buffer buffer(50);
|
|
|
|
+ buffer.clear();
|
|
|
|
+ constexpr float fontSize = 8.0f;
|
|
|
|
+ constexpr float fontStep = 8.0f / 128.0f;
|
|
|
|
+ int index = 0;
|
|
|
|
+ Vector3 pos;
|
|
|
|
+ int vertices = 0;
|
|
|
|
+ while(text[index] != '\0') {
|
|
|
|
+ Vector3 right = pos + Vector3(fontSize, 0.0f, 0.0f);
|
|
|
|
+ Vector3 down = pos + Vector3(0.0f, fontSize, 0.0f);
|
|
|
|
+ Vector3 downRight = pos + Vector3(fontSize, fontSize, 0.0f);
|
|
|
|
+
|
|
|
|
+ int i = text[index];
|
|
|
|
+ if(i < 0 && text[index + 1] != '\0') {
|
|
|
|
+ index++;
|
|
|
|
+ i = ((i & 0x1F) << 6) | (text[index] & 0x3F);
|
|
|
|
+ }
|
|
|
|
+ Vector2 tPos(fontStep * (i % 16), fontStep * (i / 16));
|
|
|
|
+ Vector2 tRight = tPos + Vector2(fontStep, 0.0f);
|
|
|
|
+ Vector2 tDown = tPos + Vector2(0.0f, fontStep);
|
|
|
|
+ Vector2 tDownRight = tPos + Vector2(fontStep, fontStep);
|
|
|
|
+
|
|
|
|
+ buffer.add(pos).add(tPos).add(down).add(tDown).add(right).add(tRight);
|
|
|
|
+ buffer.add(down).add(tDown).add(right).add(tRight).add(downRight).add(
|
|
|
|
+ tDownRight);
|
|
|
|
+ pos += Vector3(fontSize, 0.0f, 0.0f);
|
|
|
|
+ vertices += 6;
|
|
|
|
+ index++;
|
|
|
|
+ }
|
|
|
|
+ fontBuffer.setDynamicData(buffer.getLength(), buffer);
|
|
|
|
+ fontBuffer.draw(vertices);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void render(float lag) {
|
|
|
|
+ GL::clear();
|
|
|
|
+ GL::enableDepthTesting();
|
|
|
|
+ if(dirtyVertexBuffer) {
|
|
|
|
+ dirtyVertexBuffer = false;
|
|
|
|
+ buildRenderingBuffer();
|
|
|
|
+ puts("rebuilt buffer");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ shader.use();
|
|
|
|
+ GL::setViewport(Window::getSize()[0], Window::getSize()[1]);
|
|
|
|
+ const Matrix& proj = frustum.updateProjection(Window::getSize());
|
|
|
|
+ shader.setMatrix("proj", proj.getValues());
|
|
|
|
+ updateDirections(lag);
|
|
|
|
+ Matrix view;
|
|
|
|
+ Vector3 center = Math::interpolate(lastPosition, position, lag) +
|
|
|
|
+ Vector3(0.0f, 0.8f, 0.0f);
|
|
|
|
+ view.set(0, Vector4(right[0], right[1], right[2], right.dot(-center)));
|
|
|
|
+ view.set(1, Vector4(up[0], up[1], up[2], up.dot(-center)));
|
|
|
|
+ view.set(2, Vector4(back[0], back[1], back[2], back.dot(-center)));
|
|
|
|
+ view.set(3, Vector4(0.0f, 0.0f, 0.0f, 1.0f));
|
|
|
|
+ shader.setMatrix("view", view.getValues());
|
|
|
|
+ shader.setVector("color", Vector3(1.0f, 1.0f, 1.0f));
|
|
|
|
+ Matrix model;
|
|
|
|
+ shader.setMatrix("model", model.getValues());
|
|
|
|
+ vertexBuffer.draw(vertices);
|
|
|
|
+
|
|
|
|
+ if(hasFocus) {
|
|
|
|
+ shader.setVector("color", Vector3(0.8f, 0.6f, 0.6f));
|
|
|
|
+ model.translate(Vector3(-0.5f, -0.5f, -0.5f));
|
|
|
|
+ model.scale(1.01f);
|
|
|
|
+ model.translate(Vector3(0.5f, 0.5f, 0.5f));
|
|
|
|
+ model.translate(focus);
|
|
|
|
+ shader.setMatrix("model", model.getValues());
|
|
|
|
+ markVertexBuffer.draw(36);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ shader.setVector("color", Vector3(1.0f, 0.0f, 0.0f));
|
|
|
|
+ for(const Player& p : players.values()) {
|
|
|
|
+ model.translateTo(Vector3(-0.5f, -0.5f, -0.5f));
|
|
|
|
+ model.scale(0.8f);
|
|
|
|
+ model.translate(Math::interpolate(p.lastPosition, p.position, lag) +
|
|
|
|
+ Vector3(0.0f, 0.4f, 0.0f));
|
|
|
|
+ shader.setMatrix("model", model.getValues());
|
|
|
|
+ markVertexBuffer.draw(36);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ shader.setMatrix("proj", Matrix().getValues());
|
|
|
|
+ shader.setMatrix("view", Matrix().getValues());
|
|
|
|
+ shader.setVector("color", Vector3(1.0f, 0.0f, 1.0f));
|
|
|
|
+ model.translateTo(Vector3(-0.5f, -0.5f, -0.5f));
|
|
|
|
+ model.scale(0.05f);
|
|
|
|
+ shader.setMatrix("model", model.getValues());
|
|
|
|
+ markVertexBuffer.draw(36);
|
|
|
|
+
|
|
|
|
+ GL::disableDepthTesting();
|
|
|
|
+ GL::enableBlending();
|
|
|
|
+ fontShader.use();
|
|
|
|
+ fontShader.setMatrix("proj", Matrix().getValues());
|
|
|
|
+ view.translateTo(Vector3(0.0f, 0.0f, 0.0f));
|
|
|
|
+ IntVector2 size = Window::getSize();
|
|
|
|
+ view.scale(Vector3(2.0f / size[0], -2.0f / size[1], 1.0f));
|
|
|
|
+ view.translate(Vector3(-1.0f, 1.0f, 0.0f));
|
|
|
|
+ fontShader.setMatrix("view", view.getValues());
|
|
|
|
+ fontTexture.bindTo(0);
|
|
|
|
+
|
|
|
|
+ for(int i = 0; i < chat.getLength(); i++) {
|
|
|
|
+ model.translateTo(Vector3(0.0f, i * 8.0f, 0.0f)).scale(3.0f);
|
|
|
|
+ fontShader.setMatrix("model", model.getValues());
|
|
|
|
+ renderString(chat[(i + chatIndex) % chat.getLength()]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(renderInput) {
|
|
|
|
+ model.translateTo(Vector3(0.0f, chat.getLength() * 8.0f, 0.0f))
|
|
|
|
+ .scale(3.0f);
|
|
|
|
+ fontShader.setMatrix("model", model.getValues());
|
|
|
|
+ StringBuffer<256> s;
|
|
|
|
+ Window::Input::toString(s);
|
|
|
|
+ renderString(s);
|
|
|
|
+
|
|
|
|
+ model
|
|
|
|
+ .translateTo(Vector3(Window::Input::getCursor() * 8.0f,
|
|
|
|
+ chat.getLength() * 8.0f + 2.0f, 0.0f))
|
|
|
|
+ .scale(3.0f);
|
|
|
|
+ fontShader.setMatrix("model", model.getValues());
|
|
|
|
+ renderString("_");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ GL::disableBlending();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int main(int argAmount, const char* const* args) {
|
|
|
|
+ const char* server = "127.0.0.1";
|
|
|
|
+ if(argAmount >= 2) {
|
|
|
|
+ server = args[1];
|
|
|
|
+ }
|
|
|
|
+ Error e = Client::start();
|
|
|
|
+ if(e.has()) {
|
|
|
|
+ e.message.printLine();
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ e = Client::connect(server, 11196, 40);
|
|
|
|
+ if(e.has()) {
|
|
|
|
+ e.message.printLine();
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ Window::Options options(4, 3, IntVector2(1024, 600), false, "test");
|
|
|
|
+ e = Window::open(options);
|
|
|
|
+ if(e.has()) {
|
|
|
|
+ e.message.printLine();
|
|
|
|
+ Client::stop();
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ if(init()) {
|
|
|
|
+ Client::stop();
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
- Engine::run();
|
|
+ Window::show();
|
|
|
|
+ Window::run<isRunning, tick, render>(50'000'000);
|
|
|
|
+ Window::close();
|
|
|
|
+ Client::stop();
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|