Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "pch.h"
- #include <iostream>
- #include <algorithm>
- #include <thread>
- #include <Kore/IO/FileReader.h>
- #include <Kore/Math/Core.h>
- #include <Kore/System.h>
- #include <Kore/Input/Keyboard.h>
- #include <Kore/Input/Mouse.h>
- #include <Kore/Graphics1/Image.h>
- #include <Kore/Graphics4/Graphics.h>
- #include <Kore/Graphics4/PipelineState.h>
- #include <Kore/Threads/Thread.h>
- #include <Kore/Threads/Mutex.h>
- #include "Memory.h"
- #include "ObjLoader.h"
- #include <vector>
- #include <new>
- using namespace Kore;
- class MeshData {
- public:
- MeshData(const char* meshFile, const Graphics4::VertexStructure& structure) {
- mesh = loadObj(meshFile);
- vertexBuffer = new Graphics4::VertexBuffer(mesh->numVertices, structure);
- float* vertices = vertexBuffer->lock();
- for (int i = 0; i < mesh->numVertices; ++i) {
- vertices[i * 8 + 0] = mesh->vertices[i * 8 + 0];
- vertices[i * 8 + 1] = mesh->vertices[i * 8 + 1];
- vertices[i * 8 + 2] = mesh->vertices[i * 8 + 2];
- vertices[i * 8 + 3] = mesh->vertices[i * 8 + 3];
- vertices[i * 8 + 4] = 1.0f - mesh->vertices[i * 8 + 4];
- vertices[i * 8 + 5] = mesh->vertices[i * 8 + 5];
- vertices[i * 8 + 6] = mesh->vertices[i * 8 + 6];
- vertices[i * 8 + 7] = mesh->vertices[i * 8 + 7];
- }
- vertexBuffer->unlock();
- indexBuffer = new Graphics4::IndexBuffer(mesh->numFaces * 3);
- int* indices = indexBuffer->lock();
- for (int i = 0; i < mesh->numFaces * 3; i++) {
- indices[i] = mesh->indices[i];
- }
- indexBuffer->unlock();
- }
- Graphics4::VertexBuffer* vertexBuffer;
- Graphics4::IndexBuffer* indexBuffer;
- Mesh* mesh;
- };
- class MeshObject {
- public:
- MeshObject(MeshData* mesh, Graphics4::Texture* image, vec3 position) : mesh(mesh), image(image) {
- M = mat4::Translation(position.x(), position.y(), position.z());
- }
- void render(Graphics4::TextureUnit tex) {
- Graphics4::setTexture(tex, image);
- Graphics4::setVertexBuffer(*mesh->vertexBuffer);
- Graphics4::setIndexBuffer(*mesh->indexBuffer);
- Graphics4::drawIndexedVertices();
- }
- void setTexture(Graphics4::Texture* tex) {
- image = tex;
- }
- Graphics4::Texture* getTexture() {
- return image;
- }
- mat4 M;
- private:
- MeshData* mesh;
- Graphics4::Texture* image;
- };
- namespace {
- const int width = 1024;
- const int height = 768;
- double startTime;
- Graphics4::Shader* vertexShader;
- Graphics4::Shader* fragmentShader;
- Graphics4::PipelineState* pipeline;
- // null terminated array of MeshObject pointers
- MeshObject** objects;
- // The view projection matrix aka the camera
- mat4 P;
- mat4 V;
- vec3 position;
- bool up = false, down = false, left = false, right = false;
- Thread* streamingThread;
- Mutex streamMutex;
- // uniform locations - add more as you see fit
- Graphics4::TextureUnit tex;
- Graphics4::ConstantLocation pLocation;
- Graphics4::ConstantLocation vLocation;
- Graphics4::ConstantLocation mLocation;
- float angle;
- char* images;
- bool* imageLoaded;
- Graphics4::Image* imgs = (Graphics4::Image*)images;
- void loadImageAsyncHelper(Graphics4::Image* img, const char* filename, bool& loaded) {
- if (!loaded) {
- new(img) Graphics4::Image(filename, true);
- loaded = true;
- }
- }
- // load image if it hasn't been loaded yet
- void loadImageAsync(Graphics4::Image* img, const char* filename, bool& loaded) {
- std::thread t1([&]() {
- loadImageAsyncHelper(img, filename, loaded);
- });
- t1.join();
- }
- void stream(void*) {
- for (;;) {
- // to use a mutex, create a Mutex variable and call Create to initialize the mutex (see main()). Then you can use Lock/Unlock.
- streamMutex.Lock();
- // load darmstadt.jpg files for near boxes
- // reload darmstadt.jpg for every box, pretend that every box has a different texture (I don't want to upload 100 images though)
- // feel free to create more versions of darmstadt.jpg at different sizes
- // always use less than 1 million pixels of texture data (the example code uses 100 16x16 textures - that's 25600 pixels, darmstadt.jpg is 512x512 aka 262144 pixels)
- // Beware, neither OpenGL nor Direct3D is thread safe - you can't just create a Texture in a second thread. But you can create a Kore::Image
- // in another thread, access its pixels in the main thread and put them in a Kore::Texture using lock/unlock.
- // first get the position of every box
- // TODO: only consider those boxes that are visible to the camera
- std::vector<vec3> temp;
- for (int y = 0; y < 10; ++y) {
- for (int x = 0; x < 10; ++x) {
- // 0.. 99
- MeshObject** current = &objects[y * 10 + x];
- mat4 M = (*current)->M;
- vec3 currentPos(M.get(0, 3), M.get(1, 3), M.get(2, 3));
- if (currentPos.z() > position.z()) // TODO: not sufficient to filter out non-visible boxes
- temp.push_back(currentPos);
- }
- }
- // now sort them by their distance to the camera position
- struct distance_to_position {
- inline bool operator() (const vec3& objPosition1, const vec3& objPosition2) {
- float dist1 = position.distance(objPosition1);
- float dist2 = position.distance(objPosition2);
- return dist1 < dist2;
- }
- };
- std::sort(temp.begin(), temp.end(), distance_to_position());
- // the closest boxes get high resolution: 3 * 512^2 = 786432
- std::vector<vec3> nearestBoxes;
- nearestBoxes.push_back(temp[0]);
- nearestBoxes.push_back(temp[1]);
- nearestBoxes.push_back(temp[2]);
- // meidum resolution: 2 * 256^2 = 131072
- std::vector<vec3> second_nearestBoxes;
- second_nearestBoxes.push_back(temp[3]);
- second_nearestBoxes.push_back(temp[4]);
- // second_nearestBoxes.push_back(temp[5]);
- // small resolution: 3 * 128^2 = 49152
- std::vector<vec3> third_nearestBoxes;
- third_nearestBoxes.push_back(temp[5]);
- third_nearestBoxes.push_back(temp[6]); // 6 and 7 are not visible to the camera
- third_nearestBoxes.push_back(temp[7]);
- // 100 - 8 = 92 * 16^2 = 23552
- // total: 3*512^2 + 2*256^2 + 3*128^2 + 92*16^2 = 990208 < 1 million pixels
- /*Graphics4::Image* imgs = (Graphics4::Image*)images;*/
- for (int y = 0; y < 10; ++y) {
- for (int x = 0; x < 10; ++x) {
- MeshObject** current = &objects[y * 10 + x];
- mat4 M = (*current)->M;
- vec3 currentPos(M.get(0, 3), M.get(1, 3), M.get(2, 3));
- // if close (at most 3? using 4 of these already over 1 million pixels)
- if (std::find(nearestBoxes.begin(), nearestBoxes.end(), currentPos) != nearestBoxes.end()) {
- //if (imageLoaded[y * 10 + x]) { // Graphic is already loaded
- // (*current)->setTexture(new Graphics4::Texture(imgs[y * 10 + x].data, imgs[y * 10 + x].width, imgs[y * 10 + x].height,
- // imgs[y * 10 + x].dataSize, imgs[y * 10 + x].format, imgs[y * 10 + x].readable));
- //}
- //else { // Start loading thread
- // loadImageAsync(&imgs[y * 10 + x], "darmstadt.jpg", imageLoaded[y * 10 + x]);
- //}
- //(*current)->setTexture(new Graphics4::Texture("darmstadt.jpg", true));
- }
- else if (std::find(second_nearestBoxes.begin(), second_nearestBoxes.end(), currentPos) != second_nearestBoxes.end()) {
- //if (imageLoaded[y * 10 + x + 100]) { // Graphic is already loaded
- // (*current)->setTexture(new Graphics4::Texture(imgs[y * 10 + x + 100].data, imgs[y * 10 + x + 100].width, imgs[y * 10 + x + 100].height,
- // imgs[y * 10 + x + 100].dataSize, imgs[y * 10 + x + 100].format, imgs[y * 10 + x + 100].readable));
- //}
- //else { // Start loading thread
- // loadImageAsync(&imgs[y * 10 + x + 100], "darmstadtmedium.jpg", imageLoaded[y * 10 + x + 100]);
- //}
- //(*current)->setTexture(new Graphics4::Texture("darmstadtmedium.jpg", true));
- }
- else if (std::find(third_nearestBoxes.begin(), third_nearestBoxes.end(), currentPos) != third_nearestBoxes.end()) {
- //if (imageLoaded[y * 10 + x + 200]) { // Graphic is already loaded
- // (*current)->setTexture(new Graphics4::Texture(imgs[y * 10 + x + 200].data, imgs[y * 10 + x + 200].width, imgs[y * 10 + x + 200].height,
- // imgs[y * 10 + x + 200].dataSize, imgs[y * 10 + x + 200].format, imgs[y * 10 + x + 200].readable));
- //}
- //else { // Start loading thread
- // loadImageAsync(&imgs[y * 10 + x + 200], "darmstadtsmall.jpg", imageLoaded[y * 10 + x + 200]);
- //}
- //(*current)->setTexture(new Graphics4::Texture("darmstadtsmall.jpg", true));
- }
- else {
- //if (imageLoaded[y * 10 + x + 300]) { // Graphic is already loaded
- // (*current)->setTexture(new Graphics4::Texture(imgs[y * 10 + x + 300].data, imgs[y * 10 + x + 300].width, imgs[y * 10 + x + 300].height,
- // imgs[y * 10 + x + 300].dataSize, imgs[y * 10 + x + 300].format, imgs[y * 10 + x + 300].readable));
- //}
- //else { // Start loading thread
- // loadImageAsync(&imgs[y * 10 + x + 300], "darmstadtmini.png", imageLoaded[y * 10 + x + 300]);
- //}
- if (imageLoaded[y * 10 + x + 300]) {
- u8* texPointer = (*current)->getTexture()->lock();
- // memcpy(pointer, darmstadt16.data, (size_t) (darmstadt16.width * darmstadt16.height * darmstadt16.sizeOf(darmstadt16.format))); // use low res texture
- Graphics1::Image* imgPointer = &imgs[y * 10 + x + 300];
- memcpy(texPointer, imgPointer->data, (size_t)(imgPointer->width * imgPointer->height * imgPointer->sizeOf(imgPointer->format)));
- (*current)->getTexture()->unlock();
- }
- //(*current)->setTexture(new Graphics4::Texture("darmstadtmini.png", true));
- }
- }
- }
- streamMutex.Unlock();
- }
- }
- void update() {
- float t = (float)(System::time() - startTime);
- const float speed = 0.1f;
- if (up) position.z() += speed;
- if (down) position.z() -= speed;
- if (left) position.x() -= speed;
- if (right) position.x() += speed;
- Graphics4::begin();
- Graphics4::clear(Graphics4::ClearColorFlag | Graphics4::ClearDepthFlag, 0xff9999FF, 1.0f);
- Graphics4::setPipeline(pipeline);
- // set the camera
- P = mat4::Perspective(pi / 4.0f, (float)width / (float)height, 0.1f, 100);
- V = mat4::lookAt(position, vec3(0, 0, 1000), vec3(0, 1, 0));
- Graphics4::setMatrix(pLocation, P);
- Graphics4::setMatrix(vLocation, V);
- angle = t;
- //objects[0]->M = mat4::RotationY(angle) * mat4::RotationZ(Kore::pi / 4.0f);
- for (int y = 0; y < 10; ++y) {
- for (int x = 0; x < 10; ++x) {
- MeshObject** current = &objects[y * 10 + x];
- mat4 M = (*current)->M;
- vec3 currentPos(M.get(0, 3), M.get(1, 3), M.get(2, 3));
- if (!imageLoaded[y * 10 + x + 300]) {
- loadImageAsync(&imgs[y * 10 + x + 300], "darmstadtmini.png", imageLoaded[y * 10 + x + 300]);
- }
- }
- }
- // iterate the MeshObjects
- MeshObject** current = &objects[0];
- while (*current != nullptr) {
- // set the model matrix
- Graphics4::setMatrix(mLocation, (*current)->M);
- (*current)->render(tex);
- ++current;
- }
- Graphics4::end();
- Graphics4::swapBuffers();
- }
- void mouseMove(int windowId, int x, int y, int movementX, int movementY) {
- }
- void mousePress(int windowId, int button, int x, int y) {
- }
- void mouseRelease(int windowId, int button, int x, int y) {
- }
- void keyDown(KeyCode code) {
- switch (code) {
- case KeyLeft:
- left = true;
- break;
- case KeyRight:
- right = true;
- break;
- case KeyUp:
- up = true;
- break;
- case KeyDown:
- down = true;
- break;
- }
- }
- void keyUp(KeyCode code) {
- switch (code) {
- case KeyLeft:
- left = false;
- break;
- case KeyRight:
- right = false;
- break;
- case KeyUp:
- up = false;
- break;
- case KeyDown:
- down = false;
- break;
- }
- }
- void init() {
- images = (char*)malloc(400 * sizeof(Graphics4::Image)); // allocate memory for four versions of the image
- imageLoaded = new bool[400]; // boolean array to save if image was already loaded
- for (int i = 0; i < 400; i++)
- imageLoaded[i] = false;
- FileReader vs("shader.vert");
- FileReader fs("shader.frag");
- vertexShader = new Graphics4::Shader(vs.readAll(), vs.size(), Graphics4::VertexShader);
- fragmentShader = new Graphics4::Shader(fs.readAll(), fs.size(), Graphics4::FragmentShader);
- // This defines the structure of your Vertex Buffer
- Graphics4::VertexStructure structure;
- structure.add("pos", Graphics4::Float3VertexData);
- structure.add("tex", Graphics4::Float2VertexData);
- structure.add("nor", Graphics4::Float3VertexData);
- pipeline = new Graphics4::PipelineState;
- pipeline->inputLayout[0] = &structure;
- pipeline->inputLayout[1] = nullptr;
- pipeline->vertexShader = vertexShader;
- pipeline->fragmentShader = fragmentShader;
- pipeline->depthMode = Graphics4::ZCompareLess;
- pipeline->depthWrite = true;
- pipeline->compile();
- tex = pipeline->getTextureUnit("tex");
- pLocation = pipeline->getConstantLocation("P");
- vLocation = pipeline->getConstantLocation("V");
- mLocation = pipeline->getConstantLocation("M");
- objects = new MeshObject*[101];
- for (int i = 0; i < 101; ++i) objects[i] = nullptr;
- MeshData* mesh = new MeshData("box.obj", structure);
- for (int y = 0; y < 10; ++y) {
- for (int x = 0; x < 10; ++x) {
- objects[y * 10 + x] = new MeshObject(mesh, new Graphics4::Texture("darmstadtmini.png", true), vec3((x - 5.0f) * 10, 0, (y - 5.0f) * 10));
- }
- }
- angle = 0.0f;
- Graphics4::setTextureAddressing(tex, Graphics4::U, Graphics4::Repeat);
- Graphics4::setTextureAddressing(tex, Graphics4::V, Graphics4::Repeat);
- }
- }
- int kore(int argc, char** argv) {
- Kore::System::init("Exercise 10", width, height);
- Memory::init();
- init();
- Kore::System::setCallback(update);
- startTime = System::time();
- Keyboard::the()->KeyDown = keyDown;
- Keyboard::the()->KeyUp = keyUp;
- Mouse::the()->Move = mouseMove;
- Mouse::the()->Press = mousePress;
- Mouse::the()->Release = mouseRelease;
- streamMutex.Create();
- Kore::threadsInit();
- streamingThread = Kore::createAndRunThread(stream, nullptr);
- Kore::System::start();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement