static void readBitmapPixels(JNIEnv* env, jclass /* clazz */, jobject jbitmap, jint fd) { // Read the info. AndroidBitmapInfo readInfo; bool read = readAllBytes(fd, (void*) &readInfo, sizeof(AndroidBitmapInfo)); if (!read) { throwIllegalStateException(env, (char*) "Cannot read bitmap info"); return; } // Get the info of the target bitmap. AndroidBitmapInfo targetInfo; int result = AndroidBitmap_getInfo(env, jbitmap, &targetInfo); if (result < 0) { throwIllegalStateException(env, (char*) "Cannot get bitmap info"); return; } // Enforce we can reuse the bitmap. if (readInfo.width != targetInfo.width || readInfo.height != targetInfo.height || readInfo.stride != targetInfo.stride || readInfo.format != targetInfo.format || readInfo.flags != targetInfo.flags) { throwIllegalArgumentException(env, (char*) "Cannot reuse bitmap"); return; } // Lock the pixels. void* pixels; result = AndroidBitmap_lockPixels(env, jbitmap, &pixels); if (result < 0) { throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels"); return; } // Read the pixels. size_t byteCount = readInfo.stride * readInfo.height; read = readAllBytes(fd, (void*) pixels, byteCount); if (!read) { throwIllegalStateException(env, (char*) "Cannot read bitmap pixels"); return; } // Unlock the pixels. result = AndroidBitmap_unlockPixels(env, jbitmap); if (result < 0) { throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels"); } }
int main(int argc, char ** argv) { auto pathToRom = std::string(); if (argc == 2) { pathToRom = argv[1]; } else { printf("Chip8 Error: Wrong number of arguments\n"); return -1; } sf::SoundBuffer beepSnd; if (! beepSnd.loadFromFile("data/sounds/beep.wav")) { printf("Chip8 Error: Can't load the beeping sound.\n"); return -1; } sf::Sound sndSrc; sndSrc.setBuffer(beepSnd); sndSrc.setLoop(false); auto window = setupWindow(WIDTH, HEIGHT, TITLE); cee::Chip8 chip; chip.loadProgram(readAllBytes(pathToRom.c_str())); constexpr GLfloat pxVerts[] = { -1.0f, 1.0f, 0.0f, // Top Left 1.0f, 1.0f, 0.0f, // Top Right -1.0f, -1.0f, 0.0f, // Bottom Left 1.0f, -1.0f, 0.0f // Bottom Right }; constexpr GLuint pxIndices[] = { 0, 1, 2, 2, 1, 3 }; // Initialize the VAO and other buffers associated // with drawing an emulated pixel. GLuint vao, vbo, ibo; glGenVertexArrays(1, &vao); glBindVertexArray(vao); { glGenBuffers(1, &vbo); glGenBuffers(1, &ibo); // VBO glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(pxVerts), &pxVerts, GL_STATIC_DRAW); // IBO glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(pxIndices), &pxIndices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr); glEnableVertexAttribArray(0); } glBindVertexArray(0); // Current Vertex Shader const auto pxVertexSrc = readAllChars("data/shaders/px_vertex.glsl"); const auto pxVertex = makeShader(GL_VERTEX_SHADER, pxVertexSrc); // Current Fragment Shader const auto pxFragmentSrc = readAllChars("data/shaders/px_fragment.glsl"); const auto pxFragment = makeShader(GL_FRAGMENT_SHADER, pxFragmentSrc); // Current Shader Program const auto pxProgram = makeProgram({pxVertex, pxFragment}); glUseProgram(pxProgram); glfwShowWindow(window); while (! glfwWindowShouldClose(window)) { chip.updateKeys(getKeyStates(window)); chip.updateCycle(); if (chip.isBeeping() && sndSrc.getStatus() != sf::SoundSource::Playing) sndSrc.play(); // Clear back buffer and background color. glClear(GL_COLOR_BUFFER_BIT); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glBindVertexArray(vao); const auto gfx = chip.getGfx(); for (int i = 0; i < 32; ++i) { // Maps the width resolution [0-HEIGHT] to [-1.0-1.0] auto y = - mapRangeHeight(i); auto l = i * 64; for (int j = 0; j < 64; ++j) { if (gfx[l + j] == 1) { // Maps the width resolution [0-WIDTH] to [-1.0-1.0] auto x = mapRangeWidth(j); auto ident = glGetUniformLocation(pxProgram, "PxModel"); auto model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(x, y, 0.0f)); model = glm::scale(model, glm::vec3(PX_WIDTH, PX_HEIGHT, 1.0f)); glUniformMatrix4fv(ident, 1, GL_FALSE, glm::value_ptr(model)); glDrawElements(GL_TRIANGLES, sizeof(pxIndices), GL_UNSIGNED_INT, nullptr); } } } glBindVertexArray(0); glfwSwapBuffers(window); glfwPollEvents(); } // Cleanup resources glDeleteProgram(pxProgram); glDeleteShader(pxVertex); glDeleteShader(pxFragment); glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &ibo); glDeleteBuffers(1, &vbo); glfwTerminate(); return 0; }