/* =========================================================================== IceTech GPL Source Code Copyright (C) 2026 Justin Marshall This file is part of the IceTech GPL Source Code (?IceTech Source Code?). IceTech Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. IceTech Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with IceTech Source Code. If not, see . In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com =========================================================================== */ #include "precompiled.h" #pragma hdrstop #include "qe3.h" #include "Radiant.h" #include "GLWidget.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif static bool GLWidget_IsValidSize(int w, int h) { return (w > 0 && h > 0); } static void GLWidget_SetRawViewport(int x, int y, int w, int h) { if (!GLWidget_IsValidSize(w, h)) { return; } glViewport(x, y, w, h); glEnable(GL_SCISSOR_TEST); glScissor(x, y, w, h); } static void GLWidget_Set2DViewport(int x, int y, int w, int h) { GLWidget_SetRawViewport(x, y, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, w, 0, h, -256, 256); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } static float GLWidget_CalcFovY(int w, int h) { if (w <= 0 || h <= 0) { return 90.0f; } return 2.0f * atan((float)h / (float)w) * idMath::M_RAD2DEG; } ///////////////////////////////////////////////////////////////////////////// // idGLWidget class idMiniDrawVert { public: idVec3 xyz; idVec2 st; idMiniDrawVert(float x, float y, float z, float s, float t) : xyz(x, y, z), st(s, t) { }; }; static const idMiniDrawVert cubeData[] = { idMiniDrawVert(-1.0, -1.0, +1.0, 0.0, 0.0), idMiniDrawVert(+1.0, -1.0, +1.0, 1.0, 0.0), idMiniDrawVert(+1.0, +1.0, +1.0, 1.0, 1.0), idMiniDrawVert(-1.0, +1.0, +1.0, 0.0, 1.0), idMiniDrawVert(-1.0, -1.0, -1.0, 1.0, 0.0), idMiniDrawVert(-1.0, +1.0, +1.0, 1.0, 1.0), idMiniDrawVert(+1.0, +1.0, -1.0, 0.0, 1.0), idMiniDrawVert(+1.0, -1.0, -1.0, 0.0, 0.0), idMiniDrawVert(-1.0, +1.0, -1.0, 0.0, 1.0), idMiniDrawVert(-1.0, +1.0, +1.0, 0.0, 0.0), idMiniDrawVert(+1.0, +1.0, +1.0, 1.0, 0.0), idMiniDrawVert(+1.0, +1.0, -1.0, 1.0, 1.0), idMiniDrawVert(-1.0, -1.0, -1.0, 1.0, 1.0), idMiniDrawVert(+1.0, -1.0, -1.0, 0.0, 1.0), idMiniDrawVert(+1.0, -1.0, +1.0, 0.0, 0.0), idMiniDrawVert(-1.0, -1.0, +1.0, 1.0, 0.0), idMiniDrawVert(+1.0, -1.0, -1.0, 1.0, 0.0), idMiniDrawVert(+1.0, +1.0, -1.0, 1.0, 1.0), idMiniDrawVert(+1.0, +1.0, +1.0, 0.0, 1.0), idMiniDrawVert(+1.0, -1.0, +1.0, 0.0, 0.0), idMiniDrawVert(-1.0, -1.0, -1.0, 0.0, 0.0), idMiniDrawVert(-1.0, -1.0, +1.0, 1.0, 0.0), idMiniDrawVert(-1.0, +1.0, +1.0, 1.0, 1.0), idMiniDrawVert(-1.0, +1.0, -1.0, 0.0, 1.0) }; static const int cubeSides = sizeof(cubeData) / sizeof(cubeData[0]); static const int numQuads = cubeSides / 4; void glTexturedBox(idVec3& point, float size, const idMaterial* mat) { // The material is expected to be bound by the caller. Keep this function // free of glBegin/glEnd so stricter GL shims only have to handle draw calls. (void)mat; float xyz[cubeSides][3]; float st[cubeSides][2]; unsigned short indexes[numQuads * 6]; for (int i = 0; i < cubeSides; i++) { const idMiniDrawVert& src = cubeData[i]; xyz[i][0] = point.x + src.xyz.x * size; xyz[i][1] = point.y + src.xyz.y * size; xyz[i][2] = point.z + src.xyz.z * size; st[i][0] = src.st.x; st[i][1] = src.st.y; } for (int i = 0; i < numQuads; i++) { const unsigned short base = (unsigned short)(i * 4); indexes[i * 6 + 0] = base + 0; indexes[i * 6 + 1] = base + 1; indexes[i * 6 + 2] = base + 2; indexes[i * 6 + 3] = base + 0; indexes[i * 6 + 4] = base + 2; indexes[i * 6 + 5] = base + 3; } glDisableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(3, GL_FLOAT, 0, &xyz[0][0]); glTexCoordPointer(2, GL_FLOAT, 0, &st[0][0]); glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, indexes); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); } idGLWidget::idGLWidget() { initialized = false; drawable = NULL; } idGLWidget::~idGLWidget() { } BEGIN_MESSAGE_MAP(idGLWidget, CWnd) //{{AFX_MSG_MAP(idGLWidget) ON_WM_PAINT() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MBUTTONDOWN() ON_WM_MBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_MOUSEWHEEL() ON_WM_RBUTTONDOWN() ON_WM_RBUTTONUP() ON_WM_TIMER() ON_WM_ERASEBKGND() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // idGLWidget message handlers BOOL idGLWidget::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Add your specialized code here and/or call the base class return CWnd::PreCreateWindow(cs); } BOOL idGLWidget::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) { if (!CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext)) { return FALSE; } CDC* dc = GetDC(); if (dc == NULL) { return FALSE; } if (dc->m_hDC == NULL) { ReleaseDC(dc); return FALSE; } QEW_SetupPixelFormat(dc->m_hDC, false); if ((hglrc = (HGLRC)wglCreateContext(dc->m_hDC)) == 0) { common->FatalError("idGLWidget failed"); } ReleaseDC(dc); initialized = true; return TRUE; } void idGLWidget::OnPaint() { CPaintDC dc(this); // device context for painting CRect rect; GetClientRect(rect); const int width = rect.Width(); const int height = rect.Height(); if (!GLWidget_IsValidSize(width, height)) { return; } if (!initialized) { QEW_SetupPixelFormat(dc.m_hDC, false); if ((hglrc = (HGLRC)wglCreateContext(dc.m_hDC)) == 0) { common->FatalError("idGLWidget failed"); } initialized = true; } idGraphicsDeviceContextHelper context(dc.m_hDC, hglrc); GLWidget_Set2DViewport(0, 0, width, height); glClearColor(0.4f, 0.4f, 0.4f, 0.7f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); if (drawable) { drawable->draw(0, 0, width, height); } } extern bool Sys_KeyDown(int key); void idGLDrawable::buttonDown(int _button, float x, float y) { pressX = x; pressY = y; button = _button; if (button == MK_RBUTTON) { handleMove = true; } } void idGLDrawable::buttonUp(int button, float x, float y) { handleMove = false; } extern float fDiff(float f1, float f2); void idGLDrawable::mouseMove(float x, float y) { if (handleMove) { Update(); if (Sys_KeyDown(VK_MENU)) { // scale float* px = &x; float* px2 = &pressX; if (fDiff(y, pressY) > fDiff(x, pressX)) { px = &y; px2 = &pressY; } if (*px > *px2) { // zoom in scale += 0.1f; if (scale > 10.0f) { scale = 10.0f; } } else if (*px < *px2) { // zoom out scale -= 0.1f; if (scale <= 0.001f) { scale = 0.001f; } } *px2 = *px; ::SetCursorPos(pressX, pressY); } else if (Sys_KeyDown(VK_SHIFT)) { // rotate } else { // origin if (x != pressX) { xOffset += (x - pressX); pressX = x; } if (y != pressY) { yOffset -= (y - pressY); pressY = y; } //::SetCursorPos(pressX, pressY); } } } void idGLDrawable::draw(int x, int y, int w, int h) { if (!GLWidget_IsValidSize(w, h)) { return; } GL_State(GLS_DEFAULT); GLWidget_Set2DViewport(x, y, w, h); glClearColor(0.1f, 0.1f, 0.1f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); glLineWidth(1.0f); glColor3f(1, 1, 1); if (globalImages) { globalImages->BindNull(); } const float verts[4][2] = { { 3.0f, 3.0f }, { 3.0f, h - 3.0f }, { w - 3.0f, h - 3.0f }, { w - 3.0f, 3.0f } }; const float colors[4][4] = { { 1.0f, 0.0f, 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }; glDisableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(2, GL_FLOAT, 0, &verts[0][0]); glColorPointer(4, GL_FLOAT, 0, &colors[0][0]); glDrawArrays(GL_LINE_LOOP, 0, 4); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); } static int viewAngle = -98; void idGLDrawableMaterial::buttonDown(int button, float x, float y) { idGLDrawable::buttonDown(button, x, y); //viewAngle += (button == MK_LBUTTON) ? 15 : -15; } void idGLDrawableMaterial::mouseMove(float x, float y) { if (handleMove) { Update(); bool doScale = Sys_KeyDown(VK_MENU); bool doLight = Sys_KeyDown(VK_SHIFT); if (doScale || doLight) { // scale float* px = &x; float* px2 = &pressX; if (fDiff(y, pressY) > fDiff(x, pressX)) { px = &y; px2 = &pressY; } if (*px > *px2) { // zoom in if (doScale) { scale += 0.1f; if (scale > 10.0f) { scale = 10.0f; } } else { light += 0.05f; if (light > 2.0f) { light = 2.0f; } } worldDirty = true; } else if (*px < *px2) { // zoom out if (doScale) { scale -= 0.1f; if (scale <= 0.001f) { scale = 0.001f; } } else { light -= 0.05f; if (light < 0.0f) { light = 0.0f; } } worldDirty = true; } *px2 = *px; ::SetCursorPos(pressX, pressY); } else { // origin if (x != pressX) { xOffset += (x - pressX); pressX = x; worldDirty = true; } if (y != pressY) { yOffset -= (y - pressY); pressY = y; worldDirty = true; } //::SetCursorPos(pressX, pressY); } } } void idGLDrawableMaterial::draw(int x, int y, int w, int h) { const idMaterial* mat = material; if (!mat || !GLWidget_IsValidSize(w, h)) { return; } GLWidget_SetRawViewport(x, y, w, h); glClearColor(0.1f, 0.1f, 0.1f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (worldDirty) { InitWorld(); if (world == NULL || worldModel == NULL) { return; } renderLight_t parms; idDict spawnArgs; spawnArgs.Set("classname", "light"); spawnArgs.Set("name", "light_1"); spawnArgs.Set("origin", "0 0 0"); idStr str; sprintf(str, "%f %f %f", light, light, light); spawnArgs.Set("_color", str); gameEdit->ParseSpawnArgsToRenderLight(&spawnArgs, &parms); lightDef = world->AddLightDef(&parms); idImage* img = (mat->GetNumStages() > 0) ? mat->GetStage(0)->texture.image : mat->GetEditorImage(); if (img == NULL) { common->Warning("Unable to load image for preview for %s", mat->GetName()); return; } int width = (int)(img->uploadWidth * scale); int height = (int)(img->uploadHeight * scale); if (width < 1) { width = 1; } if (height < 1) { height = 1; } srfTriangles_t* tris = worldModel->AllocSurfaceTriangles(4, 6); tris->numVerts = 4; tris->numIndexes = 6; tris->indexes[0] = 0; tris->indexes[1] = 3; tris->indexes[2] = 1; tris->indexes[3] = 0; tris->indexes[4] = 1; tris->indexes[5] = 2; tris->verts[0].xyz.x = 64; tris->verts[0].xyz.y = -xOffset + 0 - width / 2; tris->verts[0].xyz.z = yOffset + 0 - height / 2; tris->verts[0].st.x = 1; tris->verts[0].st.y = 1; tris->verts[1].xyz.x = 64; tris->verts[1].xyz.y = -xOffset + width / 2; tris->verts[1].xyz.z = yOffset + height / 2; tris->verts[1].st.x = 0; tris->verts[1].st.y = 0; tris->verts[2].xyz.x = 64; tris->verts[2].xyz.y = -xOffset + 0 - width / 2; tris->verts[2].xyz.z = yOffset + height / 2; tris->verts[2].st.x = 1; tris->verts[2].st.y = 0; tris->verts[3].xyz.x = 64; tris->verts[3].xyz.y = -xOffset + width / 2; tris->verts[3].xyz.z = yOffset + 0 - height / 2; tris->verts[3].st.x = 0; tris->verts[3].st.y = 1; idVec3 edge1 = tris->verts[3].xyz - tris->verts[0].xyz; idVec3 edge2 = tris->verts[1].xyz - tris->verts[0].xyz; tris->verts[0].normal = edge1.Cross(edge2); tris->verts[0].normal.Normalize(); tris->verts[1].normal = tris->verts[2].normal = tris->verts[3].normal = tris->verts[0].normal; AddTris(tris, mat); worldModel->FinishSurfaces(); renderEntity_t worldEntity; memset(&worldEntity, 0, sizeof(worldEntity)); if (mat->HasGui()) { worldEntity.gui[0] = mat->GlobalGui(); } worldEntity.hModel = worldModel; worldEntity.axis = mat3_default; worldEntity.shaderParms[0] = 1; worldEntity.shaderParms[1] = 1; worldEntity.shaderParms[2] = 1; worldEntity.shaderParms[3] = 1; modelDef = world->AddEntityDef(&worldEntity); worldDirty = false; } renderView_t refdef; // render it renderSystem->BeginFrame(w, h); memset(&refdef, 0, sizeof(refdef)); refdef.vieworg.Set(viewAngle, 0, 0); refdef.viewaxis = idAngles(0, 0, 0).ToMat3(); refdef.shaderParms[0] = 1; refdef.shaderParms[1] = 1; refdef.shaderParms[2] = 1; refdef.shaderParms[3] = 1; refdef.width = w; refdef.height = h; refdef.fov_x = 90; refdef.fov_y = GLWidget_CalcFovY(w, h); refdef.time = eventLoop->Milliseconds(); world->RenderScene(&refdef); int frontEnd, backEnd; renderSystem->EndFrame(&frontEnd, &backEnd, false); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void idGLDrawableMaterial::setMedia(const char* name) { idImage* img = NULL; if (name && *name) { material = declManager->FindMaterial(name); if (material) { const shaderStage_t* stage = (material->GetNumStages() > 0) ? material->GetStage(0) : NULL; if (stage) { img = stage->texture.image; } else { img = material->GetEditorImage(); } } } else { material = NULL; } // set scale to get a good fit if (material && img) { float size = (img->uploadWidth > img->uploadHeight) ? img->uploadWidth : img->uploadHeight; // use 128 as base scale of 1.0 scale = (size > 0.0f) ? 128.0f / size : 1.0f; } else { scale = 1.0; } xOffset = 0.0; yOffset = 0.0; worldDirty = true; } idGLDrawableModel::idGLDrawableModel(const char* name) { worldModel = (name && *name) ? renderModelManager->FindModel(name) : renderModelManager->DefaultModel(); light = 1.0f; worldDirty = true; xOffset = 0.0f; yOffset = 0.0f; zOffset = -128.0f; rotation.Set(0.0f, 0.0f, 0.0f, 1.0f); radius = 2.6f; lastPress.Zero(); } idGLDrawableModel::idGLDrawableModel() { worldModel = renderModelManager->DefaultModel(); light = 1.0f; worldDirty = true; xOffset = 0.0f; yOffset = 0.0f; zOffset = -128.0f; rotation.Set(0.0f, 0.0f, 0.0f, 1.0f); radius = 2.6f; lastPress.Zero(); } void idGLDrawableModel::setMedia(const char* name) { worldModel = (name && *name) ? renderModelManager->FindModel(name) : renderModelManager->DefaultModel(); if (worldModel == NULL) { worldModel = renderModelManager->DefaultModel(); } worldDirty = true; xOffset = 0.0f; yOffset = 0.0f; zOffset = -128.0f; rotation.Set(0.0f, 0.0f, 0.0f, 1.0f); radius = 2.6f; lastPress.Zero(); } void idGLDrawableModel::SetSkin(const char* skin) { skinStr = skin ? skin : ""; worldDirty = true; } void idGLDrawableModel::buttonDown(int _button, float x, float y) { pressX = x; pressY = y; const float rw = (rect.z != 0.0f) ? rect.z : 1.0f; const float rh = (rect.w != 0.0f) ? rect.w : 1.0f; lastPress.y = -(float)(2 * x - rw) / rw; lastPress.x = -(float)(2 * y - rh) / rh; lastPress.z = 0.0f; button = _button; if (button == MK_RBUTTON || button == MK_LBUTTON) { handleMove = true; } } void idGLDrawableModel::mouseMove(float x, float y) { if (handleMove) { Update(); if (button == MK_LBUTTON) { const float rw = (rect.z != 0.0f) ? rect.z : 1.0f; const float rh = (rect.w != 0.0f) ? rect.w : 1.0f; float cury = (float)(2 * x - rw) / rw; float curx = (float)(2 * y - rh) / rh; idVec3 to(-curx, -cury, 0.0f); to.ProjectSelfOntoSphere(radius); lastPress.ProjectSelfOntoSphere(radius); idVec3 axis; axis.Cross(to, lastPress); float len = (lastPress - to).Length() / (2.0f * radius); len = idMath::ClampFloat(-1.0f, 1.0f, len); float phi = 2.0f * asin(len); axis.Normalize(); axis *= sin(phi / 2.0f); idQuat rot(axis.z, axis.y, axis.x, cos(phi / 2.0f)); rot.Normalize(); rotation *= rot; rotation.Normalize(); worldDirty = true; lastPress = to; lastPress.z = 0.0f; } else { bool doScale = Sys_KeyDown(VK_MENU); bool doLight = Sys_KeyDown(VK_SHIFT); if (doLight) { // scale float* px = &x; float* px2 = &pressX; if (fDiff(y, pressY) > fDiff(x, pressX)) { px = &y; px2 = &pressY; } if (*px > *px2) { light += 0.05f; if (light > 2.0f) { light = 2.0f; } worldDirty = true; } else if (*px < *px2) { light -= 0.05f; if (light < 0.0f) { light = 0.0f; } worldDirty = true; } *px2 = *px; ::SetCursorPos(pressX, pressY); } else { // origin if (x != pressX) { if (doScale) { zOffset += (x - pressX); } else { xOffset += (x - pressX); } pressX = x; } if (y != pressY) { if (doScale) { zOffset -= (y - pressY); } else { yOffset -= (y - pressY); } pressY = y; } //::SetCursorPos(pressX, pressY); } } } } void idGLDrawableModel::draw(int x, int y, int w, int h) { if (!worldModel || !GLWidget_IsValidSize(w, h)) { return; } if (worldModel->IsDynamicModel() != DM_STATIC) { // Keep dynamic models renderable for previews; the renderer will choose // the best static/dynamic representation available. } rect.Set(x, y, w, h); GLWidget_SetRawViewport(x, y, w, h); glClearColor(0.1f, 0.1f, 0.1f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (worldDirty) { if (world == NULL) { world = renderSystem->AllocRenderWorld(dxrWorldId_t::DXR_WIDGET_0); } if (world == NULL) { return; } world->InitFromMap(NULL); renderLight_t parms; idDict spawnArgs; spawnArgs.Set("classname", "light"); spawnArgs.Set("name", "light_1"); spawnArgs.Set("origin", "-128 0 0"); idStr str; sprintf(str, "%f %f %f", light, light, light); spawnArgs.Set("_color", str); gameEdit->ParseSpawnArgsToRenderLight(&spawnArgs, &parms); lightDef = world->AddLightDef(&parms); renderEntity_t worldEntity; memset(&worldEntity, 0, sizeof(worldEntity)); spawnArgs.Clear(); spawnArgs.Set("classname", "func_static"); spawnArgs.Set("name", "preview_model"); spawnArgs.Set("origin", "0 0 0"); if (skinStr.Length()) { spawnArgs.Set("skin", skinStr); } gameEdit->ParseSpawnArgsToRenderEntity(&spawnArgs, &worldEntity); worldEntity.hModel = worldModel; worldEntity.axis = rotation.ToMat3(); worldEntity.shaderParms[0] = 1; worldEntity.shaderParms[1] = 1; worldEntity.shaderParms[2] = 1; worldEntity.shaderParms[3] = 1; modelDef = world->AddEntityDef(&worldEntity); worldDirty = false; } renderView_t refdef; // render it renderSystem->BeginFrame(w, h); memset(&refdef, 0, sizeof(refdef)); refdef.vieworg.Set(zOffset, xOffset, -yOffset); refdef.viewaxis = idAngles(0, 0, 0).ToMat3(); refdef.shaderParms[0] = 1; refdef.shaderParms[1] = 1; refdef.shaderParms[2] = 1; refdef.shaderParms[3] = 1; refdef.width = w; refdef.height = h; refdef.fov_x = 90; refdef.fov_y = GLWidget_CalcFovY(w, h); refdef.time = eventLoop->Milliseconds(); world->RenderScene(&refdef); int frontEnd, backEnd; renderSystem->EndFrame(&frontEnd, &backEnd); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void idGLWidget::OnLButtonDown(UINT nFlags, CPoint point) { SetCapture(); if (drawable) { if (drawable->ScreenCoords()) { ClientToScreen(&point); } drawable->buttonDown(MK_LBUTTON, point.x, point.y); } } void idGLWidget::OnLButtonUp(UINT nFlags, CPoint point) { if (drawable) { if (drawable->ScreenCoords()) { ClientToScreen(&point); } drawable->buttonUp(MK_LBUTTON, point.x, point.y); } ReleaseCapture(); } void idGLWidget::OnMButtonDown(UINT nFlags, CPoint point) { SetCapture(); if (drawable) { if (drawable->ScreenCoords()) { ClientToScreen(&point); } drawable->buttonDown(MK_MBUTTON, point.x, point.y); } } void idGLWidget::OnMButtonUp(UINT nFlags, CPoint point) { if (drawable) { if (drawable->ScreenCoords()) { ClientToScreen(&point); } drawable->buttonUp(MK_MBUTTON, point.x, point.y); } ReleaseCapture(); } void idGLWidget::OnMouseMove(UINT nFlags, CPoint point) { if (drawable) { if (drawable->ScreenCoords()) { ClientToScreen(&point); } drawable->mouseMove(point.x, point.y); RedrawWindow(); } } BOOL idGLWidget::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { if (drawable) { float f = drawable->getScale(); if (zDelta > 0.0f) { f += 0.1f; } else { f -= 0.1f; } if (f <= 0.0f) { f = 0.1f; } if (f > 5.0f) { f = 5.0f; } drawable->Update(); drawable->setScale(f); Invalidate(FALSE); } return TRUE; } void idGLWidget::OnRButtonDown(UINT nFlags, CPoint point) { SetCapture(); if (drawable) { if (drawable->ScreenCoords()) { ClientToScreen(&point); } drawable->buttonDown(MK_RBUTTON, point.x, point.y); } } void idGLWidget::OnRButtonUp(UINT nFlags, CPoint point) { if (drawable) { if (drawable->ScreenCoords()) { ClientToScreen(&point); } drawable->buttonUp(MK_RBUTTON, point.x, point.y); } ReleaseCapture(); } void idGLWidget::setDrawable(idGLDrawable* d) { drawable = d; if (m_hWnd != NULL) { KillTimer(1); if (d && d->getRealTime()) { SetTimer(1, d->getRealTime(), NULL); } Invalidate(FALSE); } } void idGLWidget::OnTimer(UINT_PTR nIDEvent) { if (drawable && drawable->getRealTime()) { Invalidate(FALSE); } else { KillTimer(1); } } idGLDrawable::idGLDrawable() { scale = 1.0; xOffset = 0.0; yOffset = 0.0; handleMove = false; realTime = 0; } void idGLDrawableConsole::draw(int x, int y, int w, int h) { if (!GLWidget_IsValidSize(w, h)) { return; } GL_State(GLS_DEFAULT); GLWidget_SetRawViewport(x, y, w, h); glClearColor(0.1f, 0.1f, 0.1f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderSystem->BeginFrame(w, h); console->Draw(true); renderSystem->EndFrame(NULL, NULL); } void idGLConsoleWidget::init() { setDrawable(&console); } void idGLConsoleWidget::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { sysEvent_t ev; memset(&ev, 0, sizeof(ev)); ev.evType = SE_KEY; ev.evValue2 = 1; ev.evValue = nChar; ::console->ProcessEvent(&ev, true); } BEGIN_MESSAGE_MAP(idGLConsoleWidget, idGLWidget) //{{AFX_MSG_MAP(idGLConsoleWidget) ON_WM_PAINT() ON_WM_KEYDOWN() ON_WM_KEYUP() ON_WM_CHAR() ON_WM_LBUTTONDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() void idGLConsoleWidget::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { sysEvent_t ev; memset(&ev, 0, sizeof(ev)); ev.evType = SE_KEY; ev.evValue2 = 0; ev.evValue = nChar; ::console->ProcessEvent(&ev, true); } void idGLConsoleWidget::OnPaint() { idGLWidget::OnPaint(); } void idGLConsoleWidget::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { sysEvent_t ev; memset(&ev, 0, sizeof(ev)); ev.evType = SE_CHAR; ev.evValue = nChar; ::console->ProcessEvent(&ev, true); } void idGLConsoleWidget::OnLButtonDown(UINT nFlags, CPoint point) { SetFocus(); } BOOL idGLWidget::OnEraseBkgnd(CDC* pDC) { return TRUE; } idGLDrawableWorld::idGLDrawableWorld() { world = NULL; worldModel = NULL; InitWorld(); } idGLDrawableWorld::~idGLDrawableWorld() { delete world; } void idGLDrawableWorld::AddTris(srfTriangles_t* tris, const idMaterial* mat) { modelSurface_t surf; surf.geometry = tris; surf.shader = mat; worldModel->AddSurface(surf); } void idGLDrawableWorld::draw(int x, int y, int w, int h) { } void idGLDrawableWorld::InitWorld() { if (world == NULL) { world = renderSystem->AllocRenderWorld(dxrWorldId_t::DXR_WIDGET_0); } if (worldModel == NULL) { worldModel = renderModelManager->AllocModel(); } if (world == NULL || worldModel == NULL) { return; } world->InitFromMap(NULL); worldModel->InitEmpty(va("GLWorldModel_%i", Sys_Milliseconds())); }