martyj Posted January 21, 2019 Share Posted January 21, 2019 I'm trying to implement Ultralight into Leadwerks and I"m struggling to find the best way to do it. I can see to "easy" options. 1. Create a GPUDriver instance for Ultralight which utilizes Leadwerks rendering. (Requires my own custom 2D shader) 2. Use the OpenGL implementation for Ultralight but use a separate thread for rendering the browser and writing the image data to a shared buffer #1 seems very difficult and error prone as I have to provide my own shader and support for this rendering. #2 seems easier but I don't know quite the best way to do this. Would something like this work for #2? DWORD WINAPI MyThreadFunction(LPVOID lpParam) { System::Print("THread2"); HDC hdc = CreateCompatibleDC(0); HGLRC glrc = wglCreateContext(hdc); wglMakeCurrent(window->hdc, glrc); unsigned char buff[512 * 512 * 3]; while (true) { drawUI(); dumpToBuffer(512, 512); } wglDeleteContext(glrc); } What would you guys recommend? Quote Link to comment Share on other sites More sharing options...
Josh Posted January 21, 2019 Share Posted January 21, 2019 Would this be useful? Window* Window::Create(HWND hwnd) Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
martyj Posted January 21, 2019 Author Share Posted January 21, 2019 This is the approach I am taking. It doesn't work right now, but it should pass along the idea for #2. We would have two threads. Thread 1 would be the game in itself. Thread 2 would be the HTML render thread that uses OpenGL implementation for Ultralight UI Is this a good approach? const GLchar* vertexShader = R"EOF( #version 140 in vec3 in_Position; in vec3 in_Color; out vec3 ex_Color; void main(void) { gl_Position = vec4(in_Position, 1.0); ex_Color = in_Color; } )EOF"; const GLchar* fragShader = R"EOF( #version 140 precision highp float; // needed only for version 1.30 in vec3 ex_Color; out vec4 out_Color; void main(void) { out_Color = vec4(ex_Color,1.0); } )EOF"; unsigned int vertexArrayObjID[1]; unsigned int vertexBufferObjID[2]; void init(void) { /* set viewing projection */ glMatrixMode(GL_PROJECTION); glFrustum(-0.5F, 0.5F, -0.5F, 0.5F, 1.0F, 3.0F); /* position viewer */ glMatrixMode(GL_MODELVIEW); glTranslatef(0.0F, 0.0F, -2.0F); int vertSize = 9; int colorSize = 9; GLfloat vertData[]{ -0.3, 0.5, -1.0, -0.8, -0.5, -1.0, 0.2, -0.5, -1.0 }; GLfloat colorData[]{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 }; // Allocate Vertex Array Objects glGenVertexArrays(1, &vertexArrayObjID[0]); // Setup first Vertex Array Object glBindVertexArray(vertexArrayObjID[0]); glGenBuffers(2, vertexBufferObjID); // VBO for vertex data glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[0]); glBufferData(GL_ARRAY_BUFFER, vertSize * sizeof(GLfloat), vertData, GL_STATIC_DRAW); glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); // VBO for colour data glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[1]); glBufferData(GL_ARRAY_BUFFER, colorSize * sizeof(GLfloat), colorData, GL_STATIC_DRAW); glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(1); glBindVertexArray(0); GLuint renderBuffer[1]; glGenRenderbuffersEXT(1, renderBuffer); glBindRenderbufferEXT(GL_FRAMEBUFFER_EXT, renderBuffer[0]); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, 512, 512); } void initShaders(void) { GLuint glProgram; GLuint vertShaderPtr = glCreateShader(GL_VERTEX_SHADER); GLuint fragShaderPtr = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(vertShaderPtr, 1, &vertexShader, 0); glShaderSource(fragShaderPtr, 1, &fragShader, 0); GLint compiled; glCompileShader(vertShaderPtr); glGetShaderiv(vertShaderPtr, GL_COMPILE_STATUS, &compiled); if (!compiled) { cout << "Vertex shader not compiled." << endl; } glCompileShader(fragShaderPtr); glGetShaderiv(fragShaderPtr, GL_COMPILE_STATUS, &compiled); if (!compiled) { cout << "Fragment shader not compiled." << endl; } glProgram = glCreateProgram(); glBindAttribLocation(glProgram, 0, "in_Position"); glBindAttribLocation(glProgram, 1, "in_Color"); glAttachShader(glProgram, vertShaderPtr); glAttachShader(glProgram, fragShaderPtr); glLinkProgram(glProgram); glUseProgram(glProgram); } void display(void) { // clear the screen glClear(GL_COLOR_BUFFER_BIT); glBindVertexArray(vertexArrayObjID[0]); // First VAO glDrawArrays(GL_TRIANGLES, 0, 3); // draw first object glBindVertexArray(0); } void screendump(int W, int H) { FILE* out = fopen("screenshot.tga", "wb"); char* pixel_data = new char[3 * W*H]; short TGAhead[] = { 0, 2, 0, 0, 0, 0, W, H, 24 }; glReadBuffer(GL_RENDERBUFFER_EXT); glReadPixels(0, 0, W, H, GL_BGR, GL_UNSIGNED_BYTE, pixel_data); // TODO: Render to texture instead. Use texture with Context::drawImage fwrite(&TGAhead, sizeof(TGAhead), 1, out); fwrite(pixel_data, 3 * W*H, 1, out); fclose(out); delete[] pixel_data; } static Window* window; DWORD WINAPI MyThreadFunction(LPVOID lpParam) { System::Print("THread2"); HDC hdc = CreateCompatibleDC(0); HGLRC glrc = wglCreateContext(hdc); wglMakeCurrent(window->hdc, glrc); init(); initShaders(); int w = 512; int h = 512; glViewport(0, 0, (GLsizei)w, (GLsizei)h); while (true) { display(); SwapBuffers(window->hdc); //screendump(w, h); } wglDeleteContext(glrc); } int main(int argc,const char *argv[]) { // Leadwerks Stuff // ... // Game Setup window = Leadwerks::Window::Create(); Context* context = Context::Create(window); World* world = World::Create(); Light* light = DirectionalLight::Create(); light->SetRotation(35, 35, 0); //Create the ground Model* ground = Model::Box(10, 1, 10); ground->SetPosition(0, -0.5, 0); ground->SetColor(0.0, 1.0, 0.0); //Create a shape Shape* shape = Shape::Box(0, 0, 0, 0, 0, 0, 10, 1, 10); ground->SetShape(shape); shape->Release(); //Create a character Pivot* player = Pivot::Create(); Entity* visiblecapsule = Model::Cylinder(16, player); visiblecapsule->SetScale(1, 2, 1); visiblecapsule->SetPosition(0, 1, 0); player->SetMass(1); player->SetPhysicsMode(Entity::CharacterPhysics); Camera* camera = Camera::Create(); camera->SetPosition(Vec3(0, 1.5, 0), false); camera->SetParent(player); DWORD threadId; HANDLE thread = CreateThread(NULL, 0, MyThreadFunction, nullptr, 0, &threadId); System::Print("THread1"); while (true) { if (window->Closed() || window->KeyDown(Key::Escape)) return false; Leadwerks::Time::Update(); float move = (window->KeyDown(Key::W) - window->KeyDown(Key::S)) * 4; float strafe = (window->KeyDown(Key::D) - window->KeyDown(Key::A)) * 4; player->SetInput(0, move, strafe); world->Update(); world->Render(); context->Sync(); } Quote Link to comment Share on other sites More sharing options...
Josh Posted January 21, 2019 Share Posted January 21, 2019 I have no idea. This is some crazy stuff. Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
martyj Posted January 23, 2019 Author Share Posted January 23, 2019 This post is for future reference. I don't have it working with a 2nd off screen context. I have two threads rendering two scenes to two windows. I think my next steps is to ditch SDL and use Frame Buffer Objects. https://www.khronos.org/opengl/wiki/Framebuffer_Object I'll update people on my progress. #include <Leadwerks.h> #include <SDL.h> using namespace Leadwerks; #include <GL/glut.h> GLfloat light_diffuse[] = { 1.0, 0.0, 0.0, 1.0 }; /* Red diffuse light. */ GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; /* Infinite light location. */ GLfloat n[6][3] = { /* Normals for the 6 faces of a cube. */ {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0} }; GLint faces[6][4] = { /* Vertex indices for the 6 faces of a cube. */ {0, 1, 2, 3}, {3, 2, 6, 7}, {7, 6, 5, 4}, {4, 5, 1, 0}, {5, 6, 2, 1}, {7, 4, 0, 3} }; GLfloat v[8][3]; /* Will be filled in with X,Y,Z vertexes. */ void drawBox(void) { int i; for (i = 0; i < 6; i++) { glBegin(GL_QUADS); glNormal3fv(&n[i][0]); glVertex3fv(&v[faces[i][0]][0]); glVertex3fv(&v[faces[i][1]][0]); glVertex3fv(&v[faces[i][2]][0]); glVertex3fv(&v[faces[i][3]][0]); glEnd(); } } void screendump(int W, int H) { FILE* out = fopen("screenshot.tga", "wb"); char* pixel_data = new char[3 * W*H]; short TGAhead[] = { 0, 2, 0, 0, 0, 0, W, H, 24 }; glReadBuffer(GL_RENDERBUFFER_EXT); glReadPixels(0, 0, W, H, GL_BGR, GL_UNSIGNED_BYTE, pixel_data); // TODO: Render to texture instead. Use texture with Context::drawImage fwrite(&TGAhead, sizeof(TGAhead), 1, out); fwrite(pixel_data, 3 * W*H, 1, out); fclose(out); delete[] pixel_data; } void init(void) { /* Setup cube vertex data. */ v[0][0] = v[1][0] = v[2][0] = v[3][0] = -1; v[4][0] = v[5][0] = v[6][0] = v[7][0] = 1; v[0][1] = v[1][1] = v[4][1] = v[5][1] = -1; v[2][1] = v[3][1] = v[6][1] = v[7][1] = 1; v[0][2] = v[3][2] = v[4][2] = v[7][2] = 1; v[1][2] = v[2][2] = v[5][2] = v[6][2] = -1; /* Enable a single OpenGL light. */ glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); /* Use depth buffering for hidden surface elimination. */ glEnable(GL_DEPTH_TEST); /* Setup the view of the cube. */ glMatrixMode(GL_PROJECTION); gluPerspective( /* field of view in degree */ 40.0, /* aspect ratio */ 1.0, /* Z near */ 1.0, /* Z far */ 10.0); glMatrixMode(GL_MODELVIEW); gluLookAt(0.0, 0.0, 5.0, /* eye is at (0,0,5) */ 0.0, 0.0, 0.0, /* center is at (0,0,0) */ 0.0, 1.0, 0.); /* up is in positive Y direction */ /* Adjust cube position to be asthetic angle. */ glTranslatef(0.0, 0.0, -1.0); glRotatef(60, 1.0, 0.0, 0.0); glRotatef(-20, 0.0, 0.0, 1.0); } int webBrowserMain() { // Window mode MUST include SDL_WINDOW_OPENGL for use with OpenGL. SDL_Window *window = SDL_CreateWindow("Browser", 0, 0, 512, 512, SDL_WINDOW_OPENGL); // Create an OpenGL context associated with the window. SDL_GLContext glcontext = SDL_GL_CreateContext(window); init(); while (true) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); drawBox(); SDL_GL_SwapWindow(window); } SDL_GL_DeleteContext(glcontext); return 0; } DWORD WINAPI MyThreadFunction(LPVOID lpParam) { return webBrowserMain(); } #define GLUT int main(int argc, char *argv[]) { DWORD threadId = 0; CreateThread(NULL, 0, MyThreadFunction, nullptr, 0, &threadId); Window* window = Leadwerks::Window::Create(); Context* context = Context::Create(window); World* world = World::Create(); Light* light = DirectionalLight::Create(); light->SetRotation(35, 35, 0); //Create the ground Model* ground = Model::Box(10, 1, 10); ground->SetPosition(0, -0.5, 0); ground->SetColor(0.0, 1.0, 0.0); //Create a shape Shape* shape = Shape::Box(0, 0, 0, 0, 0, 0, 10, 1, 10); ground->SetShape(shape); shape->Release(); //Create a character Pivot* player = Pivot::Create(); Entity* visiblecapsule = Model::Cylinder(16, player); visiblecapsule->SetScale(1, 2, 1); visiblecapsule->SetPosition(0, 1, 0); player->SetMass(1); player->SetPhysicsMode(Entity::CharacterPhysics); Camera* camera = Camera::Create(); camera->SetPosition(Vec3(0, 1.5, 0), false); camera->SetParent(player); while (true) { if (window->Closed() || window->KeyDown(Key::Escape)) return false; Leadwerks::Time::Update(); float move = (window->KeyDown(Key::W) - window->KeyDown(Key::S)) * 4; float strafe = (window->KeyDown(Key::D) - window->KeyDown(Key::A)) * 4; player->SetInput(0, move, strafe); world->Update(); world->Render(); context->Sync(); } } Quote Link to comment Share on other sites More sharing options...
Josh Posted January 23, 2019 Share Posted January 23, 2019 FYI, the OpenGLBuffer class provides a way to access FBOs. They are not easy. You will need to look in the header file to get the FBO ID. 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
martyj Posted January 26, 2019 Author Share Posted January 26, 2019 So I have it rendering to a file/texture in a background thread. What I'd like to do now is to use wglShareLists to have textures synced between the Leadwerks Context and the SDL_Context to render a GL_TEXTURE_2D. What's the best way to create a Leadwerks::Texture from a GLuint? If I don't have to call glReadPixels to render a texture, it will probably help with performance. I assume if I set these values it will work to call context->DrawImage? int filtermode -> Pixel; int format -> RGBA8; int target -> Texture2D; bool hasmipmaps -> false; static float anisotropy -> What goes here? int bindindex -> output from glGenTextures; int width -> FBO Width; int height -> FBO height; int depth -> 0; bool clamp[3] -> What goes here? int currentmiplevel -> What goes here? int samples -> 0; Quote Link to comment Share on other sites More sharing options...
Josh Posted January 26, 2019 Share Posted January 26, 2019 For anisotropy you can just put 1.0, but I don't think it will even be used. clamp[3] should be {false,false,false} curentmiplevel should be 0. 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.