mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
1076 lines
24 KiB
C++
1076 lines
24 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
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()));
|
|
}
|