Changeset View
Changeset View
Standalone View
Standalone View
source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
| Context not available. | |||||
| * \ingroup blroutines | * \ingroup blroutines | ||||
| */ | */ | ||||
| #include "glew-mx.h" | |||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "KX_BlenderCanvas.h" | #include "KX_BlenderCanvas.h" | ||||
| #include "KX_Globals.h" | |||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_windowmanager_types.h" | #include "DNA_windowmanager_types.h" | ||||
| #include "BLI_string.h" | |||||
| #include "BLI_path_util.h" | |||||
| #include "BKE_image.h" | #include "BKE_image.h" | ||||
| #include "RAS_IRasterizer.h" | |||||
| #include "GHOST_IWindow.h" | |||||
| #include <assert.h> | #include <assert.h> | ||||
| #include <iostream> | #include <iostream> | ||||
| extern "C" { | extern "C" { | ||||
| #include "WM_api.h" | # include "WM_api.h" | ||||
| #include "wm_cursors.h" | # include "wm_cursors.h" | ||||
| #include "wm_window.h" | # include "wm_window.h" | ||||
| } | } | ||||
| KX_BlenderCanvas::KX_BlenderCanvas(wmWindowManager *wm, wmWindow *win, RAS_Rect &rect, struct ARegion *ar) : | KX_BlenderCanvas::KX_BlenderCanvas(RAS_IRasterizer *rasty, wmWindowManager *wm, wmWindow *win, RAS_Rect &rect, struct ARegion *ar) | ||||
| m_wm(wm), | :RAS_ICanvas(rasty), | ||||
| m_win(win), | m_wm(wm), | ||||
| m_frame_rect(rect) | m_win(win), | ||||
| m_area_rect(rect), // initialize area so that it's available for game logic on frame 1 (ImageViewport) | |||||
| m_ar(ar) | |||||
| { | { | ||||
| // initialize area so that it's available for game logic on frame 1 (ImageViewport) | |||||
| m_area_rect = rect; | |||||
| // area boundaries needed for mouse coordinates in Letterbox framing mode | |||||
| m_area_left = ar->winrct.xmin; | |||||
| m_area_top = ar->winrct.ymax; | |||||
| m_frame = 1; | m_frame = 1; | ||||
| glGetIntegerv(GL_VIEWPORT, (GLint *)m_viewport); | m_rasterizer->GetViewport(m_viewport); | ||||
| } | } | ||||
| KX_BlenderCanvas::~KX_BlenderCanvas() | KX_BlenderCanvas::~KX_BlenderCanvas() | ||||
| Context not available. | |||||
| void KX_BlenderCanvas::Init() | void KX_BlenderCanvas::Init() | ||||
| { | { | ||||
| glDepthFunc(GL_LEQUAL); | |||||
| } | } | ||||
| void KX_BlenderCanvas::SwapBuffers() | void KX_BlenderCanvas::SwapBuffers() | ||||
| { | { | ||||
| wm_window_swap_buffers(m_win); | wm_window_swap_buffers(m_win); | ||||
| Context not available. | |||||
| // Not implemented for the embedded player | // Not implemented for the embedded player | ||||
| } | } | ||||
| void KX_BlenderCanvas::Resize(int width, int height) | |||||
| { | |||||
| // Not implemented for the embedded player | |||||
| } | |||||
| void KX_BlenderCanvas::SetFullScreen(bool enable) | void KX_BlenderCanvas::SetFullScreen(bool enable) | ||||
| { | { | ||||
| // Not implemented for the embedded player | // Not implemented for the embedded player | ||||
| Context not available. | |||||
| return false; | return false; | ||||
| } | } | ||||
| bool KX_BlenderCanvas::BeginDraw() | void KX_BlenderCanvas::BeginDraw() | ||||
| { | { | ||||
| // in case of multi-window we need to ensure we are drawing to the correct | // in case of multi-window we need to ensure we are drawing to the correct | ||||
| // window always, because it may change in window event handling | // window always, because it may change in window event handling | ||||
| wm_window_make_drawable(m_wm, m_win); | wm_window_make_drawable(m_wm, m_win); | ||||
| return true; | |||||
| } | } | ||||
| void KX_BlenderCanvas::EndDraw() | void KX_BlenderCanvas::EndDraw() | ||||
| { | { | ||||
| // nothing needs to be done here | // nothing needs to be done here | ||||
| Context not available. | |||||
| void KX_BlenderCanvas::BeginFrame() | void KX_BlenderCanvas::BeginFrame() | ||||
| { | { | ||||
| glEnable(GL_DEPTH_TEST); | |||||
| glDepthFunc(GL_LEQUAL); | |||||
| } | } | ||||
| void KX_BlenderCanvas::EndFrame() | void KX_BlenderCanvas::EndFrame() | ||||
| { | { | ||||
| glDisable(GL_FOG); | |||||
| } | } | ||||
| int KX_BlenderCanvas::GetWidth() const | |||||
| void KX_BlenderCanvas::ClearColor(float r,float g,float b,float a) | |||||
| { | { | ||||
| glClearColor(r,g,b,a); | return m_area_rect.GetWidth(); | ||||
| } | } | ||||
| int KX_BlenderCanvas::GetHeight() const | |||||
| void KX_BlenderCanvas::ClearBuffer(int type) | |||||
| { | { | ||||
| int ogltype = 0; | return m_area_rect.GetHeight(); | ||||
| if (type & RAS_ICanvas::COLOR_BUFFER ) | |||||
| ogltype |= GL_COLOR_BUFFER_BIT; | |||||
| if (type & RAS_ICanvas::DEPTH_BUFFER ) | |||||
| ogltype |= GL_DEPTH_BUFFER_BIT; | |||||
| glClear(ogltype); | |||||
| } | } | ||||
| int KX_BlenderCanvas::GetWidth( | void KX_BlenderCanvas::ConvertMousePosition(int x, int y, int &r_x, int &r_y, bool screen) | ||||
| ) const { | { | ||||
| return m_frame_rect.GetWidth(); | if (screen) { | ||||
| } | int _x, _y; | ||||
| ((GHOST_IWindow *)m_win->ghostwin)->screenToClient(x, y, _x, _y); | |||||
| x = _x; | |||||
| y = _y; | |||||
| } | |||||
| int KX_BlenderCanvas::GetHeight( | r_x = x - m_area_rect.GetLeft() - 1; | ||||
| ) const { | r_y = -y + m_area_rect.GetTop() - 1; | ||||
| return m_frame_rect.GetHeight(); | |||||
| } | } | ||||
| int KX_BlenderCanvas::GetMouseX(int x) | float KX_BlenderCanvas::GetMouseNormalizedX(int x) | ||||
| { | { | ||||
| int left = GetWindowArea().GetLeft(); | return float(x) / this->GetWidth(); | ||||
| return x - (left - m_area_left); | |||||
| } | } | ||||
| int KX_BlenderCanvas::GetMouseY(int y) | float KX_BlenderCanvas::GetMouseNormalizedY(int y) | ||||
| { | { | ||||
| int top = GetWindowArea().GetTop(); | return float(y) / this->GetHeight(); | ||||
| return y - (m_area_top - top); | |||||
| } | } | ||||
| float KX_BlenderCanvas::GetMouseNormalizedX(int x) | const RAS_Rect &KX_BlenderCanvas::GetDisplayArea() const | ||||
| { | { | ||||
| int can_x = GetMouseX(x); | return m_displayarea; | ||||
| return float(can_x)/this->GetWidth(); | |||||
| } | } | ||||
| float KX_BlenderCanvas::GetMouseNormalizedY(int y) | void KX_BlenderCanvas::SetDisplayArea(RAS_Rect *rect) | ||||
| { | { | ||||
| int can_y = GetMouseY(y); | m_displayarea = *rect; | ||||
| return float(can_y)/this->GetHeight(); | |||||
| } | } | ||||
| RAS_Rect & | RAS_Rect &KX_BlenderCanvas::GetWindowArea() | ||||
| KX_BlenderCanvas:: | { | ||||
| GetWindowArea( | |||||
| ) { | |||||
| return m_area_rect; | return m_area_rect; | ||||
| } | } | ||||
| void | void KX_BlenderCanvas::SetViewPort(int x1, int y1, int x2, int y2) | ||||
| KX_BlenderCanvas:: | { | ||||
| SetViewPort( | |||||
| int x1, int y1, | |||||
| int x2, int y2 | |||||
| ) { | |||||
| /* x1 and y1 are the min pixel coordinate (e.g. 0) | /* x1 and y1 are the min pixel coordinate (e.g. 0) | ||||
| * x2 and y2 are the max pixel coordinate | * x2 and y2 are the max pixel coordinate | ||||
| * the width,height is calculated including both pixels | * the width,height is calculated including both pixels | ||||
| Context not available. | |||||
| */ | */ | ||||
| int vp_width = (x2 - x1) + 1; | int vp_width = (x2 - x1) + 1; | ||||
| int vp_height = (y2 - y1) + 1; | int vp_height = (y2 - y1) + 1; | ||||
| int minx = m_frame_rect.GetLeft(); | int minx = m_area_rect.GetLeft(); | ||||
| int miny = m_frame_rect.GetBottom(); | int miny = m_area_rect.GetBottom(); | ||||
| m_area_rect.SetLeft(minx + x1); | m_area_rect.SetLeft(minx + x1); | ||||
| m_area_rect.SetBottom(miny + y1); | m_area_rect.SetBottom(miny + y1); | ||||
| m_area_rect.SetRight(minx + x2); | m_area_rect.SetRight(minx + x2); | ||||
| m_area_rect.SetTop(miny + y2); | m_area_rect.SetTop(miny + y2); | ||||
| m_viewport[0] = minx+x1; | m_viewport[0] = minx + x1; | ||||
| m_viewport[1] = miny+y1; | m_viewport[1] = miny + y1; | ||||
| m_viewport[2] = vp_width; | m_viewport[2] = vp_width; | ||||
| m_viewport[3] = vp_height; | m_viewport[3] = vp_height; | ||||
| glViewport(minx + x1, miny + y1, vp_width, vp_height); | |||||
| glScissor(minx + x1, miny + y1, vp_width, vp_height); | |||||
| } | } | ||||
| void | void KX_BlenderCanvas::UpdateViewPort(int x1, int y1, int x2, int y2) | ||||
| KX_BlenderCanvas:: | { | ||||
| UpdateViewPort( | |||||
| int x1, int y1, | |||||
| int x2, int y2 | |||||
| ) { | |||||
| m_viewport[0] = x1; | m_viewport[0] = x1; | ||||
| m_viewport[1] = y1; | m_viewport[1] = y1; | ||||
| m_viewport[2] = x2; | m_viewport[2] = x2; | ||||
| m_viewport[3] = y2; | m_viewport[3] = y2; | ||||
| } | } | ||||
| const int* | const int *KX_BlenderCanvas::GetViewPort() | ||||
| KX_BlenderCanvas:: | { | ||||
| GetViewPort() { | |||||
| #ifdef DEBUG | |||||
| // If we're in a debug build, we might as well make sure our values don't differ | |||||
| // from what the gpu thinks we have. This could lead to nasty, hard to find bugs. | |||||
| int viewport[4]; | |||||
| glGetIntegerv(GL_VIEWPORT, viewport); | |||||
| assert(viewport[0] == m_viewport[0]); | |||||
| assert(viewport[1] == m_viewport[1]); | |||||
| assert(viewport[2] == m_viewport[2]); | |||||
| assert(viewport[3] == m_viewport[3]); | |||||
| #endif | |||||
| return m_viewport; | return m_viewport; | ||||
| } | } | ||||
| Context not available. | |||||
| { | { | ||||
| m_mousestate = mousestate; | m_mousestate = mousestate; | ||||
| switch (mousestate) | switch (mousestate) { | ||||
| { | case MOUSE_INVISIBLE: | ||||
| case MOUSE_INVISIBLE: | |||||
| { | { | ||||
| WM_cursor_set(m_win, CURSOR_NONE); | WM_cursor_set(m_win, CURSOR_NONE); | ||||
| break; | break; | ||||
| } | } | ||||
| case MOUSE_WAIT: | case MOUSE_WAIT: | ||||
| { | { | ||||
| WM_cursor_set(m_win, CURSOR_WAIT); | WM_cursor_set(m_win, CURSOR_WAIT); | ||||
| break; | break; | ||||
| } | } | ||||
| case MOUSE_NORMAL: | case MOUSE_NORMAL: | ||||
| { | { | ||||
| WM_cursor_set(m_win, CURSOR_STD); | WM_cursor_set(m_win, CURSOR_STD); | ||||
| break; | break; | ||||
| } | } | ||||
| default: | default: | ||||
| { | { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| // (0,0) is top left, (width,height) is bottom right | // (0,0) is top left, (width,height) is bottom right | ||||
| void KX_BlenderCanvas::SetMousePosition(int x,int y) | void KX_BlenderCanvas::SetMousePosition(int x, int y) | ||||
| { | { | ||||
| int winX = m_frame_rect.GetLeft(); | int winX = m_area_rect.GetLeft(); | ||||
| int winY = m_frame_rect.GetBottom(); | int winY = m_area_rect.GetBottom(); | ||||
| int winH = m_frame_rect.GetHeight(); | int winH = m_area_rect.GetHeight(); | ||||
| WM_cursor_warp(m_win, winX + x, winY + (winH-y)); | |||||
| } | |||||
| WM_cursor_warp(m_win, winX + x + 1, winY + (winH - y - 1)); | |||||
| /* get shot from frontbuffer sort of a copy from screendump.c */ | |||||
| static unsigned int *screenshot(ScrArea *curarea, int *dumpsx, int *dumpsy) | |||||
| { | |||||
| int x=0, y=0; | |||||
| unsigned int *dumprect= NULL; | |||||
| x= curarea->totrct.xmin; | |||||
| y= curarea->totrct.ymin; | |||||
| *dumpsx= curarea->totrct.xmax-x; | |||||
| *dumpsy= curarea->totrct.ymax-y; | |||||
| if (*dumpsx && *dumpsy) { | |||||
| dumprect= (unsigned int *)MEM_mallocN(sizeof(int) * (*dumpsx) * (*dumpsy), "dumprect"); | |||||
| glReadBuffer(GL_FRONT); | |||||
| glReadPixels(x, y, *dumpsx, *dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, dumprect); | |||||
| glFinish(); | |||||
| glReadBuffer(GL_BACK); | |||||
| } | |||||
| return dumprect; | |||||
| } | } | ||||
| void KX_BlenderCanvas::MakeScreenShot(const char *filename) | void KX_BlenderCanvas::MakeScreenShot(const std::string& filename) | ||||
| { | { | ||||
| ScrArea area_dummy= {0}; | unsigned int *pixeldata; | ||||
| bScreen *screen = m_win->screen; | bScreen *screen = m_win->screen; | ||||
| unsigned int *dumprect; | |||||
| int dumpsx, dumpsy; | |||||
| area_dummy.totrct.xmin = m_frame_rect.GetLeft(); | int x = m_area_rect.GetLeft(); | ||||
| area_dummy.totrct.xmax = m_frame_rect.GetRight(); | int y = m_area_rect.GetBottom(); | ||||
| area_dummy.totrct.ymin = m_frame_rect.GetBottom(); | int width = m_area_rect.GetWidth(); | ||||
| area_dummy.totrct.ymax = m_frame_rect.GetTop(); | int height = m_area_rect.GetHeight(); | ||||
| dumprect = screenshot(&area_dummy, &dumpsx, &dumpsy); | pixeldata = m_rasterizer->MakeScreenshot(x, y, width, height); | ||||
| if (!dumprect) { | if (!pixeldata) { | ||||
| std::cerr << "KX_BlenderCanvas: Unable to take screenshot!" << std::endl; | std::cerr << "KX_BlenderCanvas: Unable to take screenshot!" << std::endl; | ||||
| return; | return; | ||||
| } | } | ||||
| /* initialize image file format data */ | /* initialize image file format data */ | ||||
| Scene *scene = (screen)? screen->scene: NULL; | Scene *scene = (screen) ? screen->scene : NULL; | ||||
| ImageFormatData *im_format = (ImageFormatData *)MEM_mallocN(sizeof(ImageFormatData), "im_format"); | ImageFormatData *im_format = (ImageFormatData *)MEM_mallocN(sizeof(ImageFormatData), "im_format"); | ||||
| if (scene) | if (scene) { | ||||
| *im_format = scene->r.im_format; | *im_format = scene->r.im_format; | ||||
| else | } | ||||
| else { | |||||
| BKE_imformat_defaults(im_format); | BKE_imformat_defaults(im_format); | ||||
| } | |||||
| // create file path | |||||
| char path[FILE_MAX]; | |||||
| BLI_strncpy(path, filename.c_str(), FILE_MAX); | |||||
| BLI_path_abs(path, KX_GetMainPath().c_str()); | |||||
| /* save_screenshot() frees dumprect and im_format */ | /* save_screenshot() frees dumprect and im_format */ | ||||
| save_screenshot(filename, dumpsx, dumpsy, dumprect, im_format); | save_screenshot(path, width, height, pixeldata, im_format); | ||||
| } | } | ||||
| Context not available. | |||||