123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660 |
- #include "GLFW/glfw3.h"
- #include "common/Box.h"
- #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();
- // return !Window::shouldClose() &&
- // (Client::isConnecting() || Client::isConnected());
- }
- 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;
- }
- Window::show();
- Window::run<isRunning, tick, render>(50'000'000);
- Window::close();
- Client::stop();
- return 0;
- }
|