static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle, jint modeHandle, jint vertexCount, jfloatArray jverts, jint vertIndex, jfloatArray jtexs, jint texIndex, jintArray jcolors, jint colorIndex, jshortArray jindices, jint indexIndex, jint indexCount, jlong paintHandle) { AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount); AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount); AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount); AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount); const float* verts = vertA.ptr() + vertIndex; const float* texs = texA.ptr() + vertIndex; const int* colors = NULL; const uint16_t* indices = NULL; if (jcolors != NULL) { colors = colorA.ptr() + colorIndex; } if (jindices != NULL) { indices = (const uint16_t*)(indexA.ptr() + indexIndex); } SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle); const Paint* paint = reinterpret_cast<Paint*>(paintHandle); get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors, indices, indexCount, *paint); }
static void drawVertices(JNIEnv* env, jobject, SkCanvas* canvas, SkCanvas::VertexMode mode, int vertexCount, jfloatArray jverts, int vertIndex, jfloatArray jtexs, int texIndex, jintArray jcolors, int colorIndex, jshortArray jindices, int indexIndex, int indexCount, const SkPaint* paint) { AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount); AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount); AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount); AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount); const int ptCount = vertexCount >> 1; SkPoint* verts; SkPoint* texs = NULL; #ifdef SK_SCALAR_IS_FLOAT verts = (SkPoint*)(vertA.ptr() + vertIndex); if (jtexs != NULL) { texs = (SkPoint*)(texA.ptr() + texIndex); } #else int count = ptCount; // for verts if (jtexs != NULL) { count += ptCount; // += for texs } SkAutoMalloc storage(count * sizeof(SkPoint)); verts = (SkPoint*)storage.get(); const float* src = vertA.ptr() + vertIndex; for (int i = 0; i < ptCount; i++) { verts[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); src += 2; } if (jtexs != NULL) { texs = verts + ptCount; src = texA.ptr() + texIndex; for (int i = 0; i < ptCount; i++) { texs[i].set(SkFloatToFixed(src[0]), SkFloatToFixed(src[1])); src += 2; } } #endif const SkColor* colors = NULL; const uint16_t* indices = NULL; if (jcolors != NULL) { colors = (const SkColor*)(colorA.ptr() + colorIndex); } if (jindices != NULL) { indices = (const uint16_t*)(indexA.ptr() + indexIndex); } canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL, indices, indexCount, *paint); }
void liveAdvectTexture(){ Window::init(); Window window("Realtime Texture Advection"); //Set an fps cap const float FPS = 60.0f; //Setup a quad to draw too GL::VertexArray vao; vao.elementBuffer(quadElems); GL::VertexBuffer vbo(quad, GL::USAGE::STATIC_DRAW); //Setup program GL::Program prog("../res/shader.v.glsl", "../res/shader.f.glsl"); //Setup the attributes vao.setAttribPointer(vbo, prog.getAttribute("position"), 3, GL_FLOAT, GL_FALSE); vao.setAttribPointer(vbo, prog.getAttribute("texIn"), 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(glm::vec3) * 4)); glm::mat4 view = glm::lookAt<float>(glm::vec3(0, 0, 1), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0)); glm::mat4 proj = glm::perspective(60.0f, (float)(window.box().w) / (float)(window.box().h), 0.1f, 100.0f); glm::mat4 model = glm::scale(0.55f, 0.55f, 1.0f); glm::mat4 mvp = proj * view * model; prog.uniformMat4x4("mvp", mvp); /* * I don't think OpenCL or OpenGL provide a simple method for copying images/textures so * instead we'll flip the in/out image each step and draw the out image by setting active = out */ //Make textures to work with GL::Texture texA("../res/map.png", true, SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB); GL::Texture texB("../res/blank.png", true, SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB); //Active is the actual texture we will draw GL::Texture active = texB; //Setup our OpenCL context + program and kernel CL::TinyCL tiny(CL::DEVICE::GPU, true); cl::Program program = tiny.loadProgram("../res/simpleAdvect.cl"); cl::Kernel kernel = tiny.loadKernel(program, "simpleAdvect"); //Setup our OpenCL data #ifdef CL_VERSION_1_2 cl::ImageGL imgA = tiny.imageFromTexture(CL::MEM::READ_WRITE, texA); cl::ImageGL imgB = tiny.imageFromTexture(CL::MEM::READ_WRITE, texB); #else cl::Image2DGL imgA = tiny.imageFromTexture(CL::MEM::READ_WRITE, texA); cl::Image2DGL imgB = tiny.imageFromTexture(CL::MEM::READ_WRITE, texB); #endif const float speed = 0.2f; float velocity[2] = { 0.0f, 0.0f }; cl::Buffer velBuf = tiny.buffer(CL::MEM::READ_ONLY, 2 * sizeof(float), velocity); //Setup our GL objects vector std::vector<cl::Memory> glObjs; glObjs.push_back(imgA); glObjs.push_back(imgB); //The time step will be constant and velocity won't change each step, so set'em now float dt = 1.0f / FPS; kernel.setArg(0, sizeof(float), &dt); kernel.setArg(1, velBuf); //Query the preferred work group size int workSize = tiny.preferredWorkSize(kernel); //fixed for now int imgSize = 256; cl::NDRange local(workSize, workSize); cl::NDRange global(imgSize, imgSize); //Track the run number so we know which texture to set as in/out and which to draw int run = 0; //Our event structure SDL_Event e; //Limit framerate with a timer Timer delta; //For tracking if we want to quit bool quit = false, paused = false; while (!quit){ delta.Start(); //Event Polling while (SDL_PollEvent(&e)){ //If user closes he window if (e.type == SDL_QUIT) quit = true; //If user presses any key if (e.type == SDL_KEYDOWN){ switch (e.key.keysym.sym){ //So we can change velocity case SDLK_w: velocity[1] = speed; tiny.writeData(velBuf, 2 * sizeof(float), velocity); break; case SDLK_s: velocity[1] = -speed; tiny.writeData(velBuf, 2 * sizeof(float), velocity); break; case SDLK_a: velocity[0] = -speed; tiny.writeData(velBuf, 2 * sizeof(float), velocity); break; case SDLK_d: velocity[0] = speed; tiny.writeData(velBuf, 2 * sizeof(float), velocity); break; case SDLK_r: velocity[0] = 0.0f; velocity[1] = 0.0f; tiny.writeData(velBuf, 2 * sizeof(float), velocity); break; //Toggle pause case SDLK_SPACE: paused = !paused; break; //For quitting, escape key case SDLK_ESCAPE: quit = true; break; default: break; } } } //Run the kernel, setting the in/out textures properly. On even runs the output will be //in texB, on odd runs output will be in texA if (!paused){ try { //On even runs and the first run texB/imgB is our output, on odd runs it's flipped //Is this really the best way to do this? Maybe there is some faster way to copy the image over //instead of updating this each time if (run % 2 == 0 || run == 0){ kernel.setArg(2, imgA); kernel.setArg(3, imgB); active = texB; } else { kernel.setArg(2, imgB); kernel.setArg(3, imgA); active = texA; } glFinish(); tiny.mQueue.enqueueAcquireGLObjects(&glObjs); tiny.runKernel(kernel, local, global); tiny.mQueue.enqueueReleaseGLObjects(&glObjs); tiny.mQueue.finish(); ++run; } catch (const cl::Error &e){ std::cout << "Error: " << e.what() << " code: " << e.err() << std::endl; } } //RENDERING window.clear(); prog.use(); glBindVertexArray(vao); glActiveTexture(GL_TEXTURE0); //Shouldn't we be drawing active here? glBindTexture(GL_TEXTURE_2D, texA); glDrawElements(GL_TRIANGLES, vao.numElements(), GL_UNSIGNED_SHORT, NULL); window.present(); //Cap fps if (delta.Ticks() < 1000 / FPS) SDL_Delay(1000 / FPS - delta.Ticks()); } window.close(); Window::quit(); }