CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Windows/GEDebugger/SimpleGLWindow.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "Common/CommonTypes.h"18#include "Common/CommonWindows.h"19#include "Common/Log.h"20#include "Common/GPU/OpenGL/GLCommon.h"21#include "Common/GPU/OpenGL/GLFeatures.h"22#include "Common/GPU/OpenGL/GLSLProgram.h"23#include "Common/Math/lin/matrix4x4.h"24#include "GL/gl.h"25#include "GL/wglew.h"26#include "Windows/GEDebugger/SimpleGLWindow.h"27#include "Windows/W32Util/ContextMenu.h"2829#include "Core/System.h"3031const wchar_t *SimpleGLWindow::windowClass = L"SimpleGLWindow";3233using namespace Lin;3435void SimpleGLWindow::RegisterClass() {36WNDCLASSEX wndClass;3738wndClass.cbSize = sizeof(wndClass);39wndClass.lpszClassName = windowClass;40wndClass.hInstance = GetModuleHandle(0);41wndClass.lpfnWndProc = WndProc;42wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);43wndClass.hIcon = 0;44wndClass.lpszMenuName = 0;45wndClass.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);46wndClass.style = CS_DBLCLKS;47wndClass.cbClsExtra = 0;48wndClass.cbWndExtra = sizeof(SimpleGLWindow *);49wndClass.hIconSm = 0;5051RegisterClassEx(&wndClass);52}5354static const char tex_fs[] =55"#ifdef GL_ES\n"56"precision mediump float;\n"57"#endif\n"58"uniform sampler2D sampler0;\n"59"varying vec2 v_texcoord0;\n"60"void main() {\n"61" gl_FragColor = texture2D(sampler0, v_texcoord0);\n"62" gl_FragColor.a = clamp(gl_FragColor.a, 0.2, 1.0);\n"63"}\n";6465static const char basic_vs[] =66"#version 120\n"67"attribute vec4 a_position;\n"68"attribute vec2 a_texcoord0;\n"69"uniform mat4 u_viewproj;\n"70"varying vec2 v_texcoord0;\n"71"void main() {\n"72" v_texcoord0 = a_texcoord0;\n"73" gl_Position = u_viewproj * a_position;\n"74"}\n";7576SimpleGLWindow::SimpleGLWindow(HWND wnd)77: hWnd_(wnd) {78SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR) this);79}8081SimpleGLWindow::~SimpleGLWindow() {82if (vao_ != 0) {83glDeleteVertexArrays(1, &vao_);84}85if (drawProgram_ != nullptr) {86glsl_destroy(drawProgram_);87}88if (tex_) {89glDeleteTextures(1, &tex_);90glDeleteTextures(1, &checker_);91}92delete [] reformatBuf_;93};9495void SimpleGLWindow::Initialize(u32 flags) {96RECT rect;97GetWindowRect(hWnd_, &rect);9899SetFlags(flags);100SetupGL();101ResizeGL(rect.right-rect.left,rect.bottom-rect.top);102CreateProgram();103GenerateChecker();104}105106void SimpleGLWindow::SetupGL() {107int pixelFormat;108109static PIXELFORMATDESCRIPTOR pfd = {0};110pfd.nSize = sizeof(pfd);111pfd.nVersion = 1;112pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;113pfd.iPixelType = PFD_TYPE_RGBA;114pfd.cColorBits = 32;115pfd.cDepthBits = 16;116pfd.iLayerType = PFD_MAIN_PLANE;117118#define ENFORCE(x, msg) { if (!(x)) { ERROR_LOG(Log::Common, "SimpleGLWindow: %s (%08x)", msg, (uint32_t)GetLastError()); return; } }119120ENFORCE(hDC_ = GetDC(hWnd_), "Unable to create DC.");121ENFORCE(pixelFormat = ChoosePixelFormat(hDC_, &pfd), "Unable to match pixel format.");122ENFORCE(SetPixelFormat(hDC_, pixelFormat, &pfd), "Unable to set pixel format.");123ENFORCE(hGLRC_ = wglCreateContext(hDC_), "Unable to create GL context.");124ENFORCE(wglMakeCurrent(hDC_, hGLRC_), "Unable to activate GL context.");125126valid_ = glewInit() == GLEW_OK;127128// Switch to a modern context so RenderDoc doesn't get mad.129HGLRC oldGL = hGLRC_;130if (wglewIsSupported("WGL_ARB_create_context") == 1) {131static const int attribs33[] = {132WGL_CONTEXT_MAJOR_VERSION_ARB, 3,133WGL_CONTEXT_MINOR_VERSION_ARB, 3,134WGL_CONTEXT_FLAGS_ARB, 0,135WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,1360,137};138hGLRC_ = wglCreateContextAttribsARB(hDC_, 0, attribs33);139140if (!hGLRC_) {141hGLRC_ = oldGL;142} else {143// Switch to the new ARB context.144wglMakeCurrent(nullptr, nullptr);145wglDeleteContext(oldGL);146wglMakeCurrent(hDC_, hGLRC_);147148valid_ = glewInit() == GLEW_OK;149}150}151}152153void SimpleGLWindow::ResizeGL(int w, int h) {154if (!valid_) {155return;156}157158w_ = w;159h_ = h;160}161162void SimpleGLWindow::CreateProgram() {163if (!valid_) {164return;165}166167wglMakeCurrent(hDC_, hGLRC_);168169drawProgram_ = glsl_create_source(basic_vs, tex_fs);170glGenTextures(1, &tex_);171glGenTextures(1, &checker_);172173glsl_bind(drawProgram_);174glUniform1i(drawProgram_->sampler0, 0);175glsl_unbind();176177if (gl_extensions.ARB_vertex_array_object) {178glGenVertexArrays(1, &vao_);179glBindVertexArray(vao_);180181glGenBuffers(1, &ibuf_);182glGenBuffers(1, &vbuf_);183184const GLubyte indices[4] = {0, 1, 3, 2};185glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf_);186glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);187188glBindBuffer(GL_ARRAY_BUFFER, vbuf_);189} else {190vao_ = 0;191}192193glEnableVertexAttribArray(drawProgram_->a_position);194glEnableVertexAttribArray(drawProgram_->a_texcoord0);195}196197void SimpleGLWindow::GenerateChecker() {198if (!valid_) {199return;200}201202// 2x2 RGBA bitmap203static const u8 checkerboard[] = {204192,192,192,255, 128,128,128,255,205128,128,128,255, 192,192,192,255,206};207208wglMakeCurrent(hDC_, hGLRC_);209210glPixelStorei(GL_UNPACK_ALIGNMENT, 4);211glBindTexture(GL_TEXTURE_2D, checker_);212glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, checkerboard);213glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);214glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);215glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);216glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);217}218219void SimpleGLWindow::DrawChecker() {220wglMakeCurrent(hDC_, hGLRC_);221222glClearColor(0.0f, 0.0f, 0.0f, 1.0f);223glClear(GL_COLOR_BUFFER_BIT);224225glBindTexture(GL_TEXTURE_2D, checker_);226227glDisable(GL_BLEND);228glViewport(0, 0, w_, h_);229glScissor(0, 0, w_, h_);230231glsl_bind(drawProgram_);232233float fw = (float)w_, fh = (float)h_;234const float pos[12] = {0,0,0, fw,0,0, fw,fh,0, 0,fh,0};235const float texCoords[8] = {0,fh/22, fw/22,fh/22, fw/22,0, 0,0};236const GLubyte indices[4] = {0,1,3,2};237238Matrix4x4 ortho;239ortho.setOrtho(0, (float)w_, (float)h_, 0, -1, 1);240glUniformMatrix4fv(drawProgram_->u_viewproj, 1, GL_FALSE, ortho.getReadPtr());241if (vao_) {242glBufferData(GL_ARRAY_BUFFER, sizeof(pos) + sizeof(texCoords), nullptr, GL_DYNAMIC_DRAW);243glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pos), pos);244glBufferSubData(GL_ARRAY_BUFFER, sizeof(pos), sizeof(texCoords), texCoords);245glVertexAttribPointer(drawProgram_->a_position, 3, GL_FLOAT, GL_FALSE, 12, 0);246glVertexAttribPointer(drawProgram_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, (const void *)sizeof(pos));247} else {248glVertexAttribPointer(drawProgram_->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);249glVertexAttribPointer(drawProgram_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, texCoords);250}251glActiveTexture(GL_TEXTURE0);252glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, vao_ ? 0 : indices);253}254255void SimpleGLWindow::Draw(const u8 *data, int w, int h, bool flipped, Format fmt) {256wglMakeCurrent(hDC_, hGLRC_);257258GLint components = GL_RGBA;259GLint memComponents = 0;260GLenum glfmt = GL_UNSIGNED_BYTE;261const u8 *finalData = data;262if (fmt == FORMAT_8888) {263glPixelStorei(GL_UNPACK_ALIGNMENT, 4);264glfmt = GL_UNSIGNED_BYTE;265} else if (fmt == FORMAT_8888_BGRA) {266glPixelStorei(GL_UNPACK_ALIGNMENT, 4);267glfmt = GL_UNSIGNED_BYTE;268memComponents = GL_BGRA;269} else if (fmt == FORMAT_FLOAT) {270glfmt = GL_FLOAT;271components = GL_RED;272} else if (fmt == FORMAT_FLOAT_DIV_256) {273glfmt = GL_UNSIGNED_INT;274components = GL_RED;275finalData = Reformat(data, fmt, w * h);276} else if (fmt == FORMAT_24BIT_8X) {277glfmt = GL_UNSIGNED_INT;278components = GL_RED;279finalData = Reformat(data, fmt, w * h);280} else if (fmt == FORMAT_24BIT_8X_DIV_256) {281glfmt = GL_UNSIGNED_INT;282components = GL_RED;283finalData = Reformat(data, fmt, w * h);284} else if (fmt == FORMAT_24X_8BIT) {285glPixelStorei(GL_UNPACK_ALIGNMENT, 1);286glfmt = GL_UNSIGNED_BYTE;287components = GL_RED;288finalData = Reformat(data, fmt, w * h);289} else {290glPixelStorei(GL_UNPACK_ALIGNMENT, 2);291if (fmt == FORMAT_4444) {292glfmt = GL_UNSIGNED_SHORT_4_4_4_4;293} else if (fmt == FORMAT_5551) {294glfmt = GL_UNSIGNED_SHORT_5_5_5_1;295} else if (fmt == FORMAT_565) {296glfmt = GL_UNSIGNED_SHORT_5_6_5;297components = GL_RGB;298} else if (fmt == FORMAT_4444_REV) {299glfmt = GL_UNSIGNED_SHORT_4_4_4_4_REV;300} else if (fmt == FORMAT_5551_REV) {301glfmt = GL_UNSIGNED_SHORT_1_5_5_5_REV;302} else if (fmt == FORMAT_565_REV) {303glfmt = GL_UNSIGNED_SHORT_5_6_5_REV;304components = GL_RGB;305} else if (fmt == FORMAT_5551_BGRA_REV) {306glfmt = GL_UNSIGNED_SHORT_1_5_5_5_REV;307memComponents = GL_BGRA;308} else if (fmt == FORMAT_4444_BGRA_REV) {309glfmt = GL_UNSIGNED_SHORT_4_4_4_4_REV;310memComponents = GL_BGRA;311} else if (fmt == FORMAT_16BIT) {312glfmt = GL_UNSIGNED_SHORT;313components = GL_RED;314} else if (fmt == FORMAT_8BIT) {315glPixelStorei(GL_UNPACK_ALIGNMENT, 1);316glfmt = GL_UNSIGNED_BYTE;317components = GL_RED;318} else {319_dbg_assert_msg_(false, "Invalid SimpleGLWindow format.");320}321}322323if (memComponents == 0) {324memComponents = components;325}326327glBindTexture(GL_TEXTURE_2D, tex_);328glTexImage2D(GL_TEXTURE_2D, 0, components, w, h, 0, memComponents, glfmt, finalData);329glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);330glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);331glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);332glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);333334// Reset offset when the texture size changes.335if (tw_ != w || th_ != h) {336tw_ = w;337th_ = h;338offsetX_ = 0;339offsetY_ = 0;340}341tflipped_ = flipped;342343Redraw();344}345346void SimpleGLWindow::GetContentSize(float &x, float &y, float &fw, float &fh) {347fw = (float)tw_;348fh = (float)th_;349x = 0.0f;350y = 0.0f;351352if ((flags_ & RESIZE_SHRINK_FIT) != 0 && !zoom_) {353float wscale = fw / w_, hscale = fh / h_;354355// Too wide, and width is the biggest problem, so scale based on that.356if (wscale > 1.0f && wscale > hscale) {357fw = (float)w_;358fh /= wscale;359} else if (hscale > 1.0f) {360fw /= hscale;361fh = (float)h_;362}363}364if ((flags_ & RESIZE_GROW_FIT) != 0 && !zoom_) {365float wscale = fw / w_, hscale = fh / h_;366367if (wscale > hscale && wscale < 1.0f) {368fw = (float)w_;369fh /= wscale;370} else if (hscale > wscale && hscale < 1.0f) {371fw /= hscale;372fh = (float)h_;373}374}375if (flags_ & RESIZE_CENTER) {376x = ((float)w_ - fw) / 2;377y = ((float)h_ - fh) / 2;378}379380x += offsetX_;381y += offsetY_;382}383384void SimpleGLWindow::Redraw(bool andSwap) {385DrawChecker();386387auto swapWithCallback = [andSwap, this]() {388if (andSwap) {389swapped_ = false;390if (redrawCallback_ && !inRedrawCallback_) {391inRedrawCallback_ = true;392redrawCallback_();393inRedrawCallback_ = false;394}395// In case the callback swaps, don't do it twice.396if (!swapped_) {397Swap();398}399}400};401402if (tw_ == 0 && th_ == 0) {403swapWithCallback();404return;405}406407if (flags_ & ALPHA_BLEND) {408glEnable(GL_BLEND);409glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);410glBlendEquation(GL_FUNC_ADD);411} else {412glDisable(GL_BLEND);413}414glViewport(0, 0, w_, h_);415glScissor(0, 0, w_, h_);416417glBindTexture(GL_TEXTURE_2D, tex_);418glsl_bind(drawProgram_);419420float fw, fh;421float x, y;422GetContentSize(x, y, fw, fh);423424const float pos[12] = {x,y,0, x+fw,y,0, x+fw,y+fh,0, x,y+fh,0};425static const float texCoordsNormal[8] = {0,0, 1,0, 1,1, 0,1};426static const float texCoordsFlipped[8] = {0,1, 1,1, 1,0, 0,0};427static const GLubyte indices[4] = {0,1,3,2};428const float *texCoords = tflipped_ ? texCoordsFlipped : texCoordsNormal;429430Matrix4x4 ortho;431ortho.setOrtho(0, (float)w_, (float)h_, 0, -1, 1);432glUniformMatrix4fv(drawProgram_->u_viewproj, 1, GL_FALSE, ortho.getReadPtr());433if (vao_) {434glBufferData(GL_ARRAY_BUFFER, sizeof(pos) + sizeof(texCoordsNormal), nullptr, GL_DYNAMIC_DRAW);435glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pos), pos);436glBufferSubData(GL_ARRAY_BUFFER, sizeof(pos), sizeof(texCoordsNormal), texCoords);437glVertexAttribPointer(drawProgram_->a_position, 3, GL_FLOAT, GL_FALSE, 12, 0);438glVertexAttribPointer(drawProgram_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, (const void *)sizeof(pos));439} else {440glVertexAttribPointer(drawProgram_->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);441glVertexAttribPointer(drawProgram_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, texCoords);442}443glActiveTexture(GL_TEXTURE0);444glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, vao_ ? 0 : indices);445446if (andSwap) {447swapWithCallback();448}449}450451void SimpleGLWindow::Clear() {452tw_ = 0;453th_ = 0;454Redraw();455}456457void SimpleGLWindow::Begin() {458if (!inRedrawCallback_) {459Redraw(false);460}461462if (vao_) {463glBindVertexArray(0);464glBindBuffer(GL_ARRAY_BUFFER, 0);465glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);466} else {467glDisableVertexAttribArray(drawProgram_->a_position);468glDisableVertexAttribArray(drawProgram_->a_texcoord0);469}470}471472void SimpleGLWindow::End() {473if (vao_) {474glBindVertexArray(vao_);475glBindBuffer(GL_ARRAY_BUFFER, vbuf_);476glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf_);477} else {478glEnableVertexAttribArray(drawProgram_->a_position);479glEnableVertexAttribArray(drawProgram_->a_texcoord0);480}481482Swap();483}484485bool SimpleGLWindow::DragStart(int mouseX, int mouseY) {486// Only while zoomed in, otherwise it's shrink to fit mode or fixed.487if (!zoom_) {488return false;489}490491dragging_ = true;492SetCapture(hWnd_);493dragStartX_ = mouseX - offsetX_;494dragStartY_ = mouseY - offsetY_;495dragLastUpdate_ = GetTickCount();496497return true;498}499500bool SimpleGLWindow::DragContinue(int mouseX, int mouseY) {501if (!dragging_) {502return false;503}504505offsetX_ = mouseX - dragStartX_;506offsetY_ = mouseY - dragStartY_;507508const u32 MS_BETWEEN_DRAG_REDRAWS = 5;509if (GetTickCount() - dragLastUpdate_ > MS_BETWEEN_DRAG_REDRAWS) {510Redraw();511}512513return true;514}515516bool SimpleGLWindow::DragEnd(int mouseX, int mouseY) {517if (!dragging_) {518return false;519}520521dragging_ = false;522ReleaseCapture();523Redraw();524525return true;526}527528bool SimpleGLWindow::ToggleZoom() {529// Reset the offset when zooming out (or in, doesn't matter.)530offsetX_ = 0;531offsetY_ = 0;532533zoom_ = !zoom_;534Redraw();535536return true;537}538539POINT SimpleGLWindow::PosFromMouse(int mouseX, int mouseY) {540float fw, fh;541float x, y;542GetContentSize(x, y, fw, fh);543544if (mouseX < x || mouseX >= x + fw || mouseY < y || mouseY >= y + fh) {545// Outside of bounds.546return POINT{ -1, -1 };547}548549float tx = (mouseX - x) * (tw_ / fw);550float ty = (mouseY - y) * (th_ / fh);551552return POINT{ (int)tx, (int)ty };553}554555bool SimpleGLWindow::Hover(int mouseX, int mouseY) {556if (hoverCallback_ == nullptr) {557return false;558}559560POINT pos = PosFromMouse(mouseX, mouseY);561hoverCallback_(pos.x, pos.y);562563if (pos.x == -1 || pos.y == -1) {564// Outside of bounds, don't track.565return true;566}567568// Find out when they are done.569TRACKMOUSEEVENT tracking = {0};570tracking.cbSize = sizeof(tracking);571tracking.dwFlags = TME_LEAVE;572tracking.hwndTrack = hWnd_;573TrackMouseEvent(&tracking);574575return true;576}577578bool SimpleGLWindow::Leave() {579if (hoverCallback_ == nullptr) {580return false;581}582583hoverCallback_(-1, -1);584return true;585}586587bool SimpleGLWindow::RightClick(int mouseX, int mouseY) {588if (rightClickCallback_ == nullptr) {589return false;590}591592POINT pt{mouseX, mouseY};593POINT pos = PosFromMouse(mouseX, mouseY);594595rightClickCallback_(0, pos.x, pos.y);596597// We don't want to let the users play with deallocated or uninitialized debugging objects598GlobalUIState state = GetUIState();599if (state != UISTATE_INGAME && state != UISTATE_PAUSEMENU) {600return true;601}602603int result = TriggerContextMenu(rightClickMenu_, hWnd_, ContextPoint::FromClient(pt));604if (result > 0) {605rightClickCallback_(result, pos.x, pos.y);606}607608return true;609}610611const u8 *SimpleGLWindow::Reformat(const u8 *data, Format fmt, u32 numPixels) {612if (!reformatBuf_ || reformatBufSize_ < numPixels) {613delete [] reformatBuf_;614reformatBuf_ = new u32[numPixels];615reformatBufSize_ = numPixels;616}617618const u32 *data32 = (const u32 *)data;619if (fmt == FORMAT_24BIT_8X) {620for (u32 i = 0; i < numPixels; ++i) {621reformatBuf_[i] = (data32[i] << 8) | ((data32[i] >> 16) & 0xFF);622}623} else if (fmt == FORMAT_24BIT_8X_DIV_256) {624for (u32 i = 0; i < numPixels; ++i) {625int z24 = data32[i] & 0x00FFFFFF;626int z16 = z24 - 0x800000 + 0x8000;627reformatBuf_[i] = (z16 << 16) | z16;628}629} else if (fmt == FORMAT_FLOAT_DIV_256) {630for (u32 i = 0; i < numPixels; ++i) {631double z = *(float *)&data32[i];632int z24 = (int)(z * 16777215.0);633int z16 = z24 - 0x800000 + 0x8000;634reformatBuf_[i] = (z16 << 16) | z16;635}636} else if (fmt == FORMAT_24X_8BIT) {637u8 *buf8 = (u8 *)reformatBuf_;638for (u32 i = 0; i < numPixels; ++i) {639u32 v = (data32[i] >> 24) & 0xFF;640buf8[i] = v;641}642}643return (const u8 *)reformatBuf_;644}645646SimpleGLWindow *SimpleGLWindow::GetFrom(HWND hwnd) {647return (SimpleGLWindow*) GetWindowLongPtr(hwnd, GWLP_USERDATA);648}649650LRESULT CALLBACK SimpleGLWindow::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {651SimpleGLWindow *win = SimpleGLWindow::GetFrom(hwnd);652653int mouseX = 0, mouseY = 0;654switch (msg) {655case WM_LBUTTONDOWN:656case WM_LBUTTONUP:657case WM_RBUTTONUP:658case WM_MOUSEMOVE:659mouseX = (int)(short)LOWORD(lParam);660mouseY = (int)(short)HIWORD(lParam);661break;662default:663break;664}665666switch (msg) {667case WM_NCCREATE:668win = new SimpleGLWindow(hwnd);669670// Continue with window creation.671return win != nullptr ? TRUE : FALSE;672673case WM_NCDESTROY:674delete win;675return 0;676677case WM_LBUTTONDBLCLK:678if (win->ToggleZoom()) {679return 0;680}681break;682683case WM_LBUTTONDOWN:684if (win->DragStart(mouseX, mouseY)) {685return 0;686}687break;688689case WM_LBUTTONUP:690if (win->DragEnd(mouseX, mouseY)) {691return 0;692}693break;694695case WM_MOUSEMOVE:696if (win->DragContinue(mouseX, mouseY)) {697return 0;698}699if (win->Hover(mouseX, mouseY)) {700return 0;701}702break;703704case WM_RBUTTONUP:705if (win->RightClick(mouseX, mouseY)) {706return 0;707}708break;709710case WM_MOUSELEAVE:711if (win->Leave()) {712return 0;713}714break;715716case WM_PAINT:717win->Redraw();718break;719}720721return DefWindowProc(hwnd, msg, wParam, lParam);722}723724725