2013-04-05 31 views
11

Tôi đã "hack" một trong những trò chơi yêu thích của mình từ khi tôi còn trẻ, và tôi đã quản lý để có thể chặn cuộc gọi OpenGL và tiêm mã C++ bằng cách sử dụng trình bao bọc opengl32.dll. Tôi đã có thể đưa ra một số cách sử dụng tuyệt vời cho mục đích này, nhưng mục tiêu hiện tại của tôi là triển khai các trình xử lý bài đăng glsl vào trò chơi cũ này để làm cho nó trông hiện đại hơn một chút. Trò chơi ban đầu được phát hành vào cuối những năm 90, do đó việc sử dụng OpenGL và mã kết xuất của nó bị giới hạn/nguyên thủy/lỗi thời.Tiêm bộ đệm khung

Tôi đã có thể tạo thành công các trình đổ bóng đỉnh và đoạn bằng cách chèn mã để khởi tạo và sử dụng các chương trình đổ bóng, nhưng vấn đề của tôi nằm trong việc tạo khung hình/hiển thị cảnh của tôi tới kết cấu để gửi đến trình tạo đoạn của tôi làm mẫu . Theo như tôi có thể nói, kết cấu tôi tạo ra thường là màu đen. Thật khó để tìm các tài nguyên có liên quan đến những gì tôi đang làm và kiểm tra các cuộc gọi thô (tôi đã cố gắng xác định nơi để chèn mã bằng cách đọc một dấu vết opengl của một khung hình duy nhất của trò chơi), vì vậy tôi đã không thể quấn đầu của tôi xung quanh những gì tôi đang làm sai.

Tôi đã thử đặt mã ở nhiều nơi, nhưng hiện tại, tôi đang ràng buộc framebuffer sau khi trò chơi gọi wglSwapBuffers() và tôi đang hủy liên kết ngay trước khi cuộc gọi glFlush() tiếp theo được thực hiện, nhưng tôi không chắc chắn nếu nhiều thiết lập viewports, hoặc hoạt động ma trận, hoặc bất cứ điều gì khác được tạo ra giữa những lần này là bằng cách nào đó rối tung với framebuffer.

Đây là mã để khởi tạo framebuffer:

void initFB() 
{ 
    /* Texture */ 
    glActiveTexture(GL_TEXTURE0); 
    glGenTextures(1, &fbo_texture); 
    glBindTexture(GL_TEXTURE_2D, fbo_texture); 

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

    glBindTexture(GL_TEXTURE_2D, 0); 

    /* Depth buffer */ 
    glGenRenderbuffers(1, &fbo_depth); 
    glBindRenderbuffer(GL_RENDERBUFFER, fbo_depth); 
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 1920, 1080); 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth); 
    glBindRenderbuffer(GL_RENDERBUFFER, 0); 

    /* Framebuffer to link everything together */ 
    glGenFramebuffers(1, &fbo); 
    glBindFramebuffer(GL_FRAMEBUFFER, fbo); 

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture, 0); 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth); 

    GLenum status; 
    if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) { 
    fprintf(stderr, "glCheckFramebufferStatus: error %p", status); 
    } 

    glBindFramebuffer(GL_FRAMEBUFFER, 0); 
} 

Đây là mã gọi sau wglSwapBuffers:

GLenum fboBuff[] = { GL_COLOR_ATTACHMENT0 }; 
glBindFramebuffer(GL_FRAMEBUFFER, fbo); 
glDrawBuffers(1, fboBuff); 
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); 

Đây là mã gọi trước khi glFlush():

glBindFramebuffer(GL_FRAMEBUFFER, 0); 
glPopAttrib(); // Restore our glEnable and glViewport states 

... Draw an Overlay containing with fbo texture binded ... 

Here là dấu vết gl của một khung hình duy nhất.

Đó là gần 800 dòng nhưng mắt opengl được đào tạo sẽ có thể xem những cuộc gọi nào được thực hiện khi nào. Tôi đã xóa vài trăm cuộc gọi vẽ mà tôi ít hiểu nhất.

+0

Có lẽ hãy thử cập nhật kết cấu qua glReadPixels thay vì chỉ để xem phần còn lại của mã của bạn có chính xác không? –

Trả lời

0

Như tôi đã hiểu, bạn đang cố gắng cập nhật phần đồ họa của trò chơi cũ, nhưng bạn đang gặp phải những hạn chế trong mã ban đầu khiến bạn không thể trang bị thêm các phần bạn cần.

Mặc dù không có trải nghiệm mã trò chơi liên quan, khi tôi có ứng dụng mà tôi đang cố gắng trang bị thêm, tôi sẽ tháo rời ứng dụng để nghiên cứu cấu trúc của nó và áp dụng chọn lọc các bản vá trong bộ nhớ để chuyển hướng các chức năng nhất định và phân đoạn mã để thay thế mà tôi đã cung cấp.

Tôi sẽ tải trước một thư viện dùng chung để ghi đè các phần nhất định của bộ nhớ chương trình với các lệnh nhảy/cuộc gọi có điều kiện/vô điều kiện và NOP'ing chọn lọc sao cho mã của tôi trở thành một phần không thể thiếu của chương trình. Nó chắc chắn không thanh lịch bằng bất kỳ phương tiện nào, nhưng nó cho phép tôi làm việc xung quanh sự thiếu sót trong mã ban đầu một cách nhanh chóng.

2

Tôi không hoàn toàn chắc chắn những gì bạn muốn làm. Chạy trò chơi để hiển thị cho bạn fbo? Hiển thị nội dung trên đầu trang? Để bắt đầu, hãy thử lấy tất cả các cuộc gọi wgl và gl. http://research.microsoft.com/en-us/projects/detours/ là một nơi tốt để bắt đầu.

Nhưng đọc lại bài đăng của bạn, tôi đoán bạn đã biết điều đó.Nó sẽ giúp để biết những gì bạn muốn làm.

  • Rendering lớp phủ: SwapBuffers Hook, làm công cụ của bạn có
  • chụp: Một lần nữa, SwapBuffers móc
  • Rendering đến kết cấu và bài làm ảnh hưởng: Hook BindFramebuffer. Nhưng có một catch: frame buffer 0 là mặc định khi khởi động, vì vậy code không sử dụng nó sẽ không gọi BindFramebuffer để bắt đầu, chỉ để thiết lập nó trở lại 0. Hãy thử hooking glClear hoặc bất cứ cuộc gọi nào đến trước.

Hãy thoải mái cho tôi biết thêm chi tiết. Có vẻ như một dự án giáo dục thú vị mà tôi muốn trợ giúp :)

Tôi vừa đọc lại bài đăng của bạn trước khi đăng và sự cố của bạn có thể dễ dàng hơn rất nhiều. Là một chương trình cửa sổ, mục tiêu của bạn giả định rằng fbo 0 bị ràng buộc khi nó bắt đầu hiển thị một khung. Cứ làm đi. Trước khi nó được thực hiện, nó sẽ chuyển trở lại fbo 0. Đừng làm điều push/pop. Chỉ cần chắc chắn rằng fbo của bạn có cùng kích thước (trên cửa sổ lớn hơn cũng ok) nó mong đợi. Bạn cần phải móc BindFramebuffer mặc dù. Bất cứ khi nào cuộc gọi trò chơi của bạn ràng buộc 0, bạn cần phải liên kết với bạn thay thế. Nhưng không cần phải làm bất cứ điều gì khác như chạm vào khung nhìn, trò chơi phải chăm sóc nó. Khi bạn cuối cùng render trong hook swapBuffers của bạn, chỉ cần chắc chắn để khôi phục lại bất cứ điều gì bạn thay đổi.

Ngoài ra, bạn thực sự không cần cuộc gọi DrawBuffers. Nó nhầm lẫn nốt ruồi ra khỏi tôi và có lẽ cũng là mục tiêu của bạn. :) Mục tiêu của bạn là mã GL 1.2, bạn đang thực hiện 3 ... 4 ...

1

Từ kinh nghiệm của tôi, những thứ bạn đang cố gắng thực hiện hoàn toàn có thể với cách tiếp cận đánh chặn GL cho ứng dụng GL1.x không bóng .

Khi tôi nhanh chóng hack, bạn chỉ có thể quên FBO ngay bây giờ và chỉ sử dụng glCopyTexSubImage() khi nào ứng dụng gốc hoán đổi bộ đệm, sao chép nội dung được hiển thị thành kết cấu và nhắn tin cho các chức năng hậu xử lý của bạn.

Một số điều bạn nên chăm sóc, khi thực hiện một tiêm cách tiếp cận như vậy GL:

  • có thể có bối cảnh GL khác nhau (mặc dù điều này có nhiều khả năng cho các ứng dụng CAD hơn trò chơi điển hình)
  • cũ GL cho phép người dùng quản lý trực tiếp ID đối tượng - không có cuộc gọi đến các chức năng glGen* nếu cần (các ứng dụng đẹp vẫn làm). Nếu bạn tự tạo đối tượng mới, ứng dụng gốc sẽ không biết và có thể sử dụng lại các ID đó. Nếu bạn muốn nhận được quyền này, bạn sẽ phải minh bạch remap Object ID (có thể sử dụng một số bảng băm) - đó là rất nhiều công việc, như nhiều chức năng GL có liên quan. Một hack ác sẽ là sử dụng một số ID đối tượng không chính mình.
  • GL là máy trạng thái, vì vậy bạn nên cẩn thận khi khôi phục trạng thái mà trò chơi đang mong đợi (nhiều nhất có thể). OTOH tay, bạn cũng nên chuẩn bị sẵn sàng rằng các ứng dụng ban đầu có thể có bất kỳ trạng thái GL thiết lập khi bạn có sự thay đổi để đánh chặn nó - vì vậy bạn có thể phải thiết lập lại rất nhiều thứ.

Tôi có thể đảm bảo với bạn rằng thực sự có thể đưa hình ảnh vào kết cấu vào một số ứng dụng GL cũ, như tôi đã tự làm. Làm việc rất tốt với Quake3 và các trò chơi nổi tiếng khác của thời đại. Tôi không thấy lỗi obviuos với cách tiếp cận hiện tại của bạn. Tôi ít điều mặc dù: Bạn cũng nên đánh chặn glDrawBuffer() và chuyển tiếp bất kỳ bản vẽ nào mà ứng dụng sẽ thực hiện tới GL_BACK (giả sử ứng dụng đệm đôi ở đây) vào tệp đính kèm màu của bạn. Tuy nhiên, nhật ký bạn đăng không có dấu vết của hàm này, do đó trò chơi có thể đã đặt nó khi khởi động.

Tôi cũng không hiểu tại sao bạn sử dụng glFlush. Nó không phải là một dấu hiệu tốt cho bất cứ điều gì đặc biệt. Nếu trò chơi sử dụng bộ đệm đôi, SwapBuffers sẽ là phép tính gần đúng nhất của "khung hình" mà bạn có thể nhận được. Chỉ cần chèn nội dung sáng tạo đối tượng init của riêng bạn ngay sau khi tạo ngữ cảnh (bạn cũng có thể chặn wglCreateCintext() và bạn bè) và đã thiết lập hiển thị cho FBO. Trên SwapBuffers, chỉ cần vẽ nội dung của kết cấu bằng cách sử dụng bộ đổ bóng của bạn để đệm thực sự trở lại, thực hiện trao đổi bộ đệm thực, và khôi phục lại kết xuất để thiết lập FBO.

Tôi không biết bạn đã biết hay chưa, nhưng dự án mã nguồn mở Chromium không cung cấp một fframework tốt cho việc chặn OpenGL. Trong khi trọng tâm của điều này có thể là phân cụm cụm, nó cũng sẽ hoạt động trong thiết lập tiêu điểm và cho phép bạn viết SPUs (đơn vị xử lý luồng), nơi bạn có thể đơn giản chỉ định một hàm C cho bất kỳ hàm GL nào bạn muốn . Dự án đã lỗi thời và không hoạt động develpoment kể từ 5 năm trở lên, bởi vì các loại GL thao tác dòng nó được desgined để ist sẽ không làm việc với các đường ống lập trình hiện đại hơn, nhưng nó vẫn sẽ làm việc tốt với GL1 cũ tốt. x đường ống chức năng cố định ...

Các vấn đề liên quan