2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 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 Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
39 #include "../../renderer/tr_local.h"
40 #include "../../renderer/model_local.h" // for idRenderModelMD5
45 static char THIS_FILE[] = __FILE__;
47 extern void DrawPathLines();
49 int g_axialAnchor = -1;
51 bool g_bAxialMode = false;
53 void ValidateAxialPoints() {
54 int faceCount = g_ptrSelectedFaces.GetSize();
56 face_t *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(0));
57 if (g_axialAnchor >= selFace->face_winding->GetNumPoints()) {
60 if (g_axialDest >= selFace->face_winding->GetNumPoints()) {
70 IMPLEMENT_DYNCREATE(CCamWnd, CWnd);
73 =======================================================================================================================
74 =======================================================================================================================
78 memset(&m_Camera, 0, sizeof(camera_t));
79 m_pSide_select = NULL;
86 animationMode = false;
94 =======================================================================================================================
95 =======================================================================================================================
100 BEGIN_MESSAGE_MAP(CCamWnd, CWnd)
101 //{{AFX_MSG_MAP(CCamWnd)
123 =======================================================================================================================
124 =======================================================================================================================
126 LONG WINAPI CamWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
129 GetClientRect(hWnd, &rect);
135 SendMessage(hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0);
138 case WM_NCCALCSIZE: // don't let windows copy pixels
139 DefWindowProc(hWnd, uMsg, wParam, lParam);
143 return DefWindowProc(hWnd, uMsg, wParam, lParam);
147 // =======================================================================================================================
148 // CCamWnd message handlers
149 // =======================================================================================================================
151 BOOL CCamWnd::PreCreateWindow(CREATESTRUCT &cs) {
153 HINSTANCE hInstance = AfxGetInstanceHandle();
154 if (::GetClassInfo(hInstance, CAMERA_WINDOW_CLASS, &wc) == FALSE) {
155 // Register a new class
156 memset(&wc, 0, sizeof(wc));
158 // wc.style = CS_NOCLOSE | CS_OWNDC;
159 wc.style = CS_NOCLOSE;
160 wc.lpszClassName = CAMERA_WINDOW_CLASS;
161 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
162 wc.lpfnWndProc = CamWndProc;
163 if (AfxRegisterClass(&wc) == FALSE) {
164 Error("CCamWnd RegisterClass: failed");
168 cs.lpszClass = CAMERA_WINDOW_CLASS;
170 if (cs.style != QE3_CHILDSTYLE) {
171 cs.style = QE3_SPLITTER_STYLE;
174 BOOL bResult = CWnd::PreCreateWindow(cs);
177 // See if the class already exists and if not then we need to register our new
184 =======================================================================================================================
185 =======================================================================================================================
187 void CCamWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
188 g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags);
191 brush_t *g_pSplitList = NULL;
194 =======================================================================================================================
195 =======================================================================================================================
197 void CCamWnd::OnPaint() {
198 CPaintDC dc(this); // device context for painting
201 if (!qwglMakeCurrent(dc.m_hDC, win32.hGLRC)) {
202 common->Printf("ERROR: wglMakeCurrent failed..\n ");
203 common->Printf("Please restart " EDITOR_WINDOWTEXT " if the camera view is not working\n");
206 QE_CheckOpenGLForErrors();
209 if (g_Clip1.Set() && g_Clip2.Set()) {
210 g_pSplitList = ((g_pParentWnd->ActiveXY()->GetViewType() == XZ) ? !g_bSwitch : g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits;
215 QE_CheckOpenGLForErrors();
216 qwglSwapBuffers(dc.m_hDC);
221 =======================================================================================================================
222 =======================================================================================================================
224 void CCamWnd::SetXYFriend(CXYWnd *pWnd) {
229 =======================================================================================================================
230 =======================================================================================================================
232 void CCamWnd::OnDestroy() {
237 =======================================================================================================================
238 =======================================================================================================================
240 void CCamWnd::OnClose() {
244 extern void Select_RotateTexture(float amt, bool absolute);
247 =======================================================================================================================
248 =======================================================================================================================
250 void CCamWnd::OnMouseMove(UINT nFlags, CPoint point) {
253 if (GetCapture() == this && (GetAsyncKeyState(VK_MENU) & 0x8000) && !((GetAsyncKeyState(VK_SHIFT) & 0x8000) || (GetAsyncKeyState(VK_CONTROL) & 0x8000))) {
254 if (GetAsyncKeyState(VK_CONTROL) & 0x8000) {
255 Select_RotateTexture((float)point.y - m_ptLastCursor.y);
257 else if (GetAsyncKeyState(VK_SHIFT) & 0x8000) {
258 Select_ScaleTexture((float)point.x - m_ptLastCursor.x, (float)m_ptLastCursor.y - point.y);
261 Select_ShiftTexture((float)point.x - m_ptLastCursor.x, (float)m_ptLastCursor.y - point.y);
265 Cam_MouseMoved(point.x, r.bottom - 1 - point.y, nFlags);
268 m_ptLastCursor = point;
272 =======================================================================================================================
273 =======================================================================================================================
275 void CCamWnd::OnLButtonDown(UINT nFlags, CPoint point) {
276 m_ptLastCursor = point;
277 OriginalMouseDown(nFlags, point);
281 =======================================================================================================================
282 =======================================================================================================================
284 void CCamWnd::OnLButtonUp(UINT nFlags, CPoint point) {
285 OriginalMouseUp(nFlags, point);
289 =======================================================================================================================
290 =======================================================================================================================
292 void CCamWnd::OnMButtonDown(UINT nFlags, CPoint point) {
293 OriginalMouseDown(nFlags, point);
297 =======================================================================================================================
298 =======================================================================================================================
300 void CCamWnd::OnMButtonUp(UINT nFlags, CPoint point) {
301 OriginalMouseUp(nFlags, point);
305 =======================================================================================================================
306 =======================================================================================================================
308 void CCamWnd::OnRButtonDown(UINT nFlags, CPoint point) {
309 OriginalMouseDown(nFlags, point);
313 =======================================================================================================================
314 =======================================================================================================================
316 void CCamWnd::OnRButtonUp(UINT nFlags, CPoint point) {
317 OriginalMouseUp(nFlags, point);
321 =======================================================================================================================
322 =======================================================================================================================
324 int CCamWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
325 if (CWnd::OnCreate(lpCreateStruct) == -1) {
330 HDC hDC = pDC->GetSafeHdc();
332 QEW_SetupPixelFormat(hDC, true);
334 HFONT hfont = CreateFont(
335 12, // logical height of font
336 0, // logical average character width
337 0, // angle of escapement
338 0, // base-line orientation angle
340 0, // italic attribute flag
341 0, // underline attribute flag
342 0, // strikeout attribute flag
343 0, // character set identifier
344 0, // output precision
345 0, // clipping precision
347 FIXED_PITCH | FF_MODERN, // pitch and family
348 "Lucida Console" // pointer to typeface name string
352 Error("couldn't create font");
355 HFONT hOldFont = (HFONT)SelectObject(hDC, hfont);
357 wglMakeCurrent (hDC, win32.hGLRC);
359 if ((g_qeglobals.d_font_list = qglGenLists(256)) == 0) {
360 common->Warning( "couldn't create font dlists" );
363 // create the bitmap display lists we're making images of glyphs 0 thru 255
364 if ( !qwglUseFontBitmaps(hDC, 0, 255, g_qeglobals.d_font_list) ) {
365 common->Warning( "wglUseFontBitmaps failed (%d). Trying again.", GetLastError() );
367 // FIXME: This is really wacky, sometimes the first call fails, but calling it again makes it work
368 // This probably indicates there's something wrong somewhere else in the code, but I'm not sure what
369 if ( !qwglUseFontBitmaps(hDC, 0, 255, g_qeglobals.d_font_list) ) {
370 common->Warning( "wglUseFontBitmaps failed again (%d). Trying outlines.", GetLastError() );
372 if (!qwglUseFontOutlines(hDC, 0, 255, g_qeglobals.d_font_list, 0.0f, 0.1f, WGL_FONT_LINES, NULL)) {
373 common->Warning( "wglUseFontOutlines also failed (%d), no coordinate text will be visible.", GetLastError() );
378 SelectObject(hDC, hOldFont);
381 // indicate start of glyph display lists
382 qglListBase(g_qeglobals.d_font_list);
384 // report OpenGL information
385 common->Printf("GL_VENDOR: %s\n", qglGetString(GL_VENDOR));
386 common->Printf("GL_RENDERER: %s\n", qglGetString(GL_RENDERER));
387 common->Printf("GL_VERSION: %s\n", qglGetString(GL_VERSION));
388 common->Printf("GL_EXTENSIONS: %s\n", qglGetString(GL_EXTENSIONS));
394 =======================================================================================================================
395 =======================================================================================================================
397 void CCamWnd::OriginalMouseUp(UINT nFlags, CPoint point) {
400 Cam_MouseUp(point.x, r.bottom - 1 - point.y, nFlags);
401 if (!(nFlags & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON))) {
407 =======================================================================================================================
408 =======================================================================================================================
410 void CCamWnd::OriginalMouseDown(UINT nFlags, CPoint point) {
411 // if (GetTopWindow()->GetSafeHwnd() != GetSafeHwnd()) BringWindowToTop();
417 // if (!(GetAsyncKeyState(VK_MENU) & 0x8000))
418 Cam_MouseDown(point.x, r.bottom - 1 - point.y, nFlags);
422 =======================================================================================================================
423 =======================================================================================================================
425 void CCamWnd::Cam_Init() {
426 // m_Camera.draw_mode = cd_texture;
427 m_Camera.origin[0] = 0.0f;
428 m_Camera.origin[1] = 20.0f;
429 m_Camera.origin[2] = 72.0f;
430 m_Camera.color[0] = 0.3f;
431 m_Camera.color[1] = 0.3f;
432 m_Camera.color[2] = 0.3f;
436 =======================================================================================================================
437 =======================================================================================================================
439 void CCamWnd::Cam_BuildMatrix() {
444 xa = ((renderMode) ? -m_Camera.angles[PITCH] : m_Camera.angles[PITCH]) * idMath::M_DEG2RAD;
445 ya = m_Camera.angles[YAW] * idMath::M_DEG2RAD;
447 // the movement matrix is kept 2d
448 m_Camera.forward[0] = cos(ya);
449 m_Camera.forward[1] = sin(ya);
450 m_Camera.right[0] = m_Camera.forward[1];
451 m_Camera.right[1] = -m_Camera.forward[0];
453 qglGetFloatv(GL_PROJECTION_MATRIX, &matrix[0][0]);
455 for (i = 0; i < 3; i++) {
456 m_Camera.vright[i] = matrix[i][0];
457 m_Camera.vup[i] = matrix[i][1];
458 m_Camera.vpn[i] = matrix[i][2];
461 m_Camera.vright.Normalize();
462 m_Camera.vup.Normalize();
463 m_Camera.vpn.Normalize();
468 =======================================================================================================================
469 =======================================================================================================================
472 void CCamWnd::Cam_ChangeFloor(bool up) {
474 float d, bestd, current;
477 start[0] = m_Camera.origin[0];
478 start[1] = m_Camera.origin[1];
479 start[2] = HUGE_DISTANCE;
483 current = HUGE_DISTANCE - (m_Camera.origin[2] - 72);
488 bestd = HUGE_DISTANCE*2;
491 for (b = active_brushes.next; b != &active_brushes; b = b->next) {
492 if (!Brush_Ray(start, dir, b, &d)) {
496 if (up && d < current && d > bestd) {
500 if (!up && d > current && d < bestd) {
505 if (bestd == 0 || bestd == HUGE_DISTANCE*2) {
509 m_Camera.origin[2] += current - bestd;
510 Sys_UpdateWindows(W_CAMERA | W_Z_OVERLAY);
514 =======================================================================================================================
515 =======================================================================================================================
517 void CCamWnd::Cam_PositionDrag() {
519 Sys_GetCursorPos(&x, &y);
520 if (x != m_ptCursor.x || y != m_ptCursor.y) {
522 VectorMA(m_Camera.origin, x, m_Camera.vright, m_Camera.origin);
524 m_Camera.origin[2] -= y;
525 SetCursorPos(m_ptCursor.x, m_ptCursor.y);
526 Sys_UpdateWindows(W_CAMERA | W_XY_OVERLAY);
530 void CCamWnd::Cam_MouseLook() {
533 GetCursorPos(¤t);
534 if (current.x != m_ptCursor.x || current.y != m_ptCursor.y) {
536 current.x -= m_ptCursor.x;
537 current.y -= m_ptCursor.y;
539 m_Camera.angles[PITCH] -= (float)((float)current.y * 0.25f);
540 m_Camera.angles[YAW] -= (float)((float)current.x * 0.25f);
542 SetCursorPos(m_ptCursor.x, m_ptCursor.y);
549 =======================================================================================================================
550 =======================================================================================================================
552 void CCamWnd::Cam_MouseControl(float dtime) {
556 if (g_PrefsDlg.m_nMouseButtons == 2) {
557 if (m_nCambuttonstate != (MK_RBUTTON | MK_SHIFT)) {
562 if (m_nCambuttonstate != MK_RBUTTON) {
567 xf = (float)(m_ptButton.x - m_Camera.width / 2) / (m_Camera.width / 2);
568 yf = (float)(m_ptButton.y - m_Camera.height / 2) / (m_Camera.height / 2);
570 xl = m_Camera.width / 3;
572 yl = m_Camera.height / 3;
575 // common->Printf("xf-%f yf-%f xl-%i xh-i% yl-i% yh-i%\n",xf,yf,xl,xh,yl,yh);
579 if (buttony < yl && (buttonx < xl || buttonx > xh)) {
580 VectorMA(camera.origin, xf * dtime * g_nMoveSpeed, camera.right, camera.origin);
585 xf *= 1.0f - idMath::Fabs(yf);
599 VectorMA(m_Camera.origin, yf * dtime * g_PrefsDlg.m_nMoveSpeed, m_Camera.forward, m_Camera.origin);
600 m_Camera.angles[YAW] += xf * -dtime * g_PrefsDlg.m_nAngleSpeed;
604 int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA);
605 Sys_UpdateWindows(nUpdate);
606 g_pParentWnd->PostMessage(WM_TIMER, 0, 0);
610 =======================================================================================================================
611 =======================================================================================================================
613 void CCamWnd::Cam_MouseDown(int x, int y, int buttons) {
618 // calc ray direction
619 u = (float)(y - m_Camera.height / 2) / (m_Camera.width / 2);
620 r = (float)(x - m_Camera.width / 2) / (m_Camera.width / 2);
623 for (i = 0; i < 3; i++) {
624 dir[i] = m_Camera.vpn[i] * f + m_Camera.vright[i] * r + m_Camera.vup[i] * u;
629 GetCursorPos(&m_ptCursor);
631 m_nCambuttonstate = buttons;
636 // LBUTTON = manipulate selection shift-LBUTTON = select middle button = grab
637 // texture ctrl-middle button = set entire brush to texture ctrl-shift-middle
638 // button = set single face to texture
640 int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
643 (buttons == MK_LBUTTON) ||
644 (buttons == (MK_LBUTTON | MK_SHIFT)) ||
645 (buttons == (MK_LBUTTON | MK_CONTROL)) ||
646 (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ||
647 (buttons == nMouseButton) ||
648 (buttons == (nMouseButton | MK_SHIFT)) ||
649 (buttons == (nMouseButton | MK_CONTROL)) ||
650 (buttons == (nMouseButton | MK_SHIFT | MK_CONTROL))
652 if (g_PrefsDlg.m_nMouseButtons == 2 && (buttons == (MK_RBUTTON | MK_SHIFT))) {
653 Cam_MouseControl( 0.1f );
656 // something global needs to track which window is responsible for stuff
657 Patch_SetView(W_CAMERA);
658 Drag_Begin(x, y, buttons, m_Camera.vright, m_Camera.vup, m_Camera.origin, dir);
664 if ( buttons == MK_RBUTTON ) {
665 Cam_MouseControl( 0.1f );
671 =======================================================================================================================
672 =======================================================================================================================
674 void CCamWnd::Cam_MouseUp(int x, int y, int buttons) {
675 m_nCambuttonstate = 0;
676 Drag_MouseUp(buttons);
680 =======================================================================================================================
681 =======================================================================================================================
683 void CCamWnd::Cam_MouseMoved(int x, int y, int buttons) {
684 m_nCambuttonstate = buttons;
692 if (buttons == (MK_RBUTTON | MK_CONTROL)) {
694 Sys_UpdateWindows(W_XY | W_CAMERA | W_Z);
697 else if ( buttons == (MK_RBUTTON | MK_CONTROL | MK_SHIFT) ) {
699 Sys_UpdateWindows(W_XY | W_CAMERA | W_Z);
703 GetCursorPos(&m_ptCursor);
705 if (buttons & (MK_LBUTTON | MK_MBUTTON)) {
706 Drag_MouseMoved(x, y, buttons);
707 Sys_UpdateWindows(W_XY | W_CAMERA | W_Z);
712 =======================================================================================================================
713 =======================================================================================================================
715 void CCamWnd::InitCull() {
718 VectorSubtract(m_Camera.vpn, m_Camera.vright, m_vCull1);
719 VectorAdd(m_Camera.vpn, m_Camera.vright, m_vCull2);
721 for (i = 0; i < 3; i++) {
722 if (m_vCull1[i] > 0) {
723 m_nCullv1[i] = 3 + i;
729 if (m_vCull2[i] > 0) {
730 m_nCullv2[i] = 3 + i;
739 =======================================================================================================================
740 =======================================================================================================================
742 bool CCamWnd::CullBrush(brush_t *b, bool cubicOnly) {
747 if ( b->forceVisibile ) {
751 if (g_PrefsDlg.m_bCubicClipping) {
753 float distance = g_PrefsDlg.m_nCubicScale * 64;
756 for (int i = 0; i < 3; i++) {
757 mid[i] = (b->mins[i] + ((b->maxs[i] - b->mins[i]) / 2));
760 point = mid - m_Camera.origin;
761 if (point.Length() > distance) {
771 for (i = 0; i < 3; i++) {
772 point[i] = b->mins[m_nCullv1[i]] - m_Camera.origin[i];
775 d = DotProduct(point, m_vCull1);
780 for (i = 0; i < 3; i++) {
781 point[i] = b->mins[m_nCullv2[i]] - m_Camera.origin[i];
784 d = DotProduct(point, m_vCull2);
795 =======================================================================================================================
796 =======================================================================================================================
798 void CCamWnd::DrawLightRadius(brush_t *pBrush) {
800 int nRadius = Brush_LightRadius(pBrush);
802 Brush_SetLightColor(pBrush);
804 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
805 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
806 qglDisable(GL_BLEND);
807 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
813 =======================================================================================================================
814 =======================================================================================================================
816 void setGLMode(int mode) {
820 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
821 globalImages->BindNull();
822 qglDisable(GL_BLEND);
823 qglDisable(GL_DEPTH_TEST);
824 qglColor3f( 1.0f, 1.0f, 1.0f );
828 qglCullFace(GL_FRONT);
829 qglEnable(GL_CULL_FACE);
830 qglShadeModel(GL_FLAT);
831 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
832 globalImages->BindNull();
833 qglDisable(GL_BLEND);
834 qglEnable(GL_DEPTH_TEST);
835 qglDepthFunc(GL_LEQUAL);
839 qglCullFace(GL_FRONT);
840 qglEnable(GL_CULL_FACE);
841 qglShadeModel(GL_FLAT);
842 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
843 qglDisable(GL_BLEND);
844 qglEnable(GL_DEPTH_TEST);
845 qglDepthFunc(GL_LEQUAL);
849 qglCullFace(GL_FRONT);
850 qglEnable(GL_CULL_FACE);
851 qglShadeModel(GL_FLAT);
852 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
853 qglDisable(GL_DEPTH_TEST);
855 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
861 extern void glLabeledPoint(idVec4 &color, idVec3 &point, float size, const char *label);
862 void DrawAxial(face_t *selFace) {
866 for (int j = 0; j < selFace->face_winding->GetNumPoints(); j++) {
867 glLabeledPoint(idVec4(1, 1, 1, 1), (*selFace->face_winding)[j].ToVec3(), 3, va("%i", j));
870 ValidateAxialPoints();
871 points[0] = (*selFace->face_winding)[g_axialAnchor].ToVec3();
872 VectorMA (points[0], 1, selFace->plane, points[0]);
873 VectorMA (points[0], 4, selFace->plane, points[1]);
874 points[3] = (*selFace->face_winding)[g_axialDest].ToVec3();
875 VectorMA (points[3], 1, selFace->plane, points[3]);
876 VectorMA (points[3], 4, selFace->plane, points[2]);
877 glLabeledPoint(idVec4(1, 0, 0, 1), points[1], 3, "Anchor");
878 glLabeledPoint(idVec4(1, 1, 0, 1), points[2], 3, "Dest");
879 qglBegin (GL_LINE_STRIP);
880 qglVertex3fv( points[0].ToFloatPtr() );
881 qglVertex3fv( points[1].ToFloatPtr() );
882 qglVertex3fv( points[2].ToFloatPtr() );
883 qglVertex3fv( points[3].ToFloatPtr() );
890 =======================================================================================================================
892 =======================================================================================================================
894 void CCamWnd::SetProjectionMatrix() {
896 float yfov = 2 * atan((float)m_Camera.height / m_Camera.width) * idMath::M_RAD2DEG;
898 float screenaspect = (float)m_Camera.width / m_Camera.height;
900 gluPerspective(yfov, screenaspect, 2, 8192);
902 float xmin, xmax, ymin, ymax;
905 float projectionMatrix[16];
908 // set up projection matrix
910 zNear = r_znear.GetFloat();
912 ymax = zNear * tan( yfov * idMath::PI / 360.0f );
915 xmax = zNear * tan( xfov * idMath::PI / 360.0f );
919 height = ymax - ymin;
921 projectionMatrix[0] = 2 * zNear / width;
922 projectionMatrix[4] = 0;
923 projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0
924 projectionMatrix[12] = 0;
926 projectionMatrix[1] = 0;
927 projectionMatrix[5] = 2 * zNear / height;
928 projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
929 projectionMatrix[13] = 0;
931 // this is the far-plane-at-infinity formulation
932 projectionMatrix[2] = 0;
933 projectionMatrix[6] = 0;
934 projectionMatrix[10] = -1;
935 projectionMatrix[14] = -2 * zNear;
937 projectionMatrix[3] = 0;
938 projectionMatrix[7] = 0;
939 projectionMatrix[11] = -1;
940 projectionMatrix[15] = 0;
942 qglLoadMatrixf( projectionMatrix );
946 void CCamWnd::Cam_Draw() {
953 if (!active_brushes.next) {
954 return; // not valid yet
957 // set the sound origin for both simple draw and rendered mode
958 // the editor uses opposite pitch convention
959 idMat3 axis = idAngles( -m_Camera.angles.pitch, m_Camera.angles.yaw, m_Camera.angles.roll ).ToMat3();
960 g_qeglobals.sw->PlaceListener( m_Camera.origin, axis, 0, Sys_Milliseconds(), "Undefined" );
966 qglViewport(0, 0, m_Camera.width, m_Camera.height);
967 qglScissor(0, 0, m_Camera.width, m_Camera.height);
968 qglClearColor(g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0], g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1], g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], 0);
971 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
974 qglDisable(GL_LIGHTING);
975 qglMatrixMode(GL_PROJECTION);
977 SetProjectionMatrix();
979 qglRotatef(-90, 1, 0, 0); // put Z going up
980 qglRotatef(90, 0, 0, 1); // put Z going up
981 qglRotatef(m_Camera.angles[0], 0, 1, 0);
982 qglRotatef(-m_Camera.angles[1], 0, 0, 1);
983 qglTranslatef(-m_Camera.origin[0], -m_Camera.origin[1], -m_Camera.origin[2]);
987 for (brush = active_brushes.next; brush != &active_brushes; brush = brush->next) {
989 if ( CullBrush(brush, false) ) {
993 if ( FilterBrush(brush) ) {
998 if (!(entityMode && brush->owner->eclass->fixedsize)) {
1003 setGLMode(m_Camera.draw_mode);
1008 //qglDepthMask ( 1 ); // Ok, write now
1009 qglMatrixMode(GL_PROJECTION);
1011 qglTranslatef(g_qeglobals.d_select_translate[0],g_qeglobals.d_select_translate[1],g_qeglobals.d_select_translate[2]);
1013 brush_t *pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes;
1017 for (brush = pList->next; brush != pList; brush = brush->next) {
1018 if (brush->pPatch) {
1021 setGLMode(m_Camera.draw_mode);
1022 Brush_Draw(brush, true);
1028 setGLMode(m_Camera.draw_mode);
1029 qglDisable(GL_LIGHTING);
1030 qglColor4f( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0],g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1],g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2], 0.25f );
1031 qglEnable(GL_BLEND);
1032 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1033 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1034 globalImages->BindNull();
1035 for (brush = pList->next; brush != pList; brush = brush->next) {
1036 if (brush->pPatch || brush->modelHandle > 0) {
1037 Brush_Draw(brush, true);
1039 // DHM - Nerve:: patch display lists/models mess with the state
1040 qglEnable(GL_BLEND);
1041 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1042 qglColor4f( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0],g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1],g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2], 0.25f );
1043 globalImages->BindNull();
1047 if ( brush->owner->eclass->entityModel ) {
1051 for (face = brush->brush_faces; face; face = face->next) {
1056 int nCount = g_ptrSelectedFaces.GetSize();
1059 for (int i = 0; i < nCount; i++) {
1060 face_t *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
1066 // non-zbuffered outline
1067 qglDisable(GL_BLEND);
1068 qglDisable(GL_DEPTH_TEST);
1069 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1072 qglColor3f(1, 0, 0);
1073 for (int i = 0; i < nCount; i++) {
1074 face_t *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
1079 qglColor3f(1, 1, 1);
1080 for (brush = pList->next; brush != pList; brush = brush->next) {
1081 if (brush->pPatch || brush->modelHandle > 0) {
1085 for (face = brush->brush_faces; face; face = face->next) {
1089 // edge / vertex flags
1090 if (g_qeglobals.d_select_mode == sel_vertex) {
1092 qglColor3f(0, 1, 0);
1093 qglBegin(GL_POINTS);
1094 for (i = 0; i < g_qeglobals.d_numpoints; i++) {
1095 qglVertex3fv( g_qeglobals.d_points[i].ToFloatPtr() );
1101 else if (g_qeglobals.d_select_mode == sel_edge) {
1105 qglColor3f(0, 0, 1);
1106 qglBegin(GL_POINTS);
1107 for (i = 0; i < g_qeglobals.d_numedges; i++) {
1108 v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1].ToFloatPtr();
1109 v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2].ToFloatPtr();
1110 qglVertex3f( (v1[0] + v2[0]) * 0.5f, (v1[1] + v2[1]) * 0.5f, (v1[2] + v2[2]) * 0.5f );
1117 g_splineList->draw (static_cast<bool>(g_qeglobals.d_select_mode == sel_addpoint || g_qeglobals.d_select_mode == sel_editpoint));
1119 if ( g_qeglobals.selectObject && (g_qeglobals.d_select_mode == sel_addpoint || g_qeglobals.d_select_mode == sel_editpoint) ) {
1120 g_qeglobals.selectObject->drawSelection();
1124 qglEnable(GL_DEPTH_TEST);
1128 if (g_qeglobals.d_pointfile_display_list) {
1133 // bind back to the default texture so that we don't have problems elsewhere
1134 // using/modifying texture maps between contexts
1136 globalImages->BindNull();
1139 QE_CheckOpenGLForErrors();
1142 // clean up any deffered tri's
1148 =======================================================================================================================
1149 =======================================================================================================================
1151 void CCamWnd::OnSize(UINT nType, int cx, int cy) {
1152 CWnd::OnSize(nType, cx, cy);
1155 GetClientRect(rect);
1156 m_Camera.width = rect.right;
1157 m_Camera.height = rect.bottom;
1158 InvalidateRect(NULL, false);
1163 =======================================================================================================================
1164 =======================================================================================================================
1166 void CCamWnd::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) {
1167 g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags, false);
1171 // =======================================================================================================================
1172 // Timo brush primitive texture shifting, using camera view to select translations::
1173 // =======================================================================================================================
1175 void CCamWnd::ShiftTexture_BrushPrimit(face_t *f, int x, int y) {
1178 idVec3 viewX, viewY;
1182 if (!g_qeglobals.m_bBrushPrimitMode) {
1183 common->Printf("Warning : unexpected call to CCamWnd::ShiftTexture_BrushPrimit with brush primitive mode disbaled\n");
1187 // compute face axis base
1188 //ComputeAxisBase(f->plane.Normal(), texS, texT);
1190 // compute camera view vectors
1191 VectorCopy(m_Camera.vup, viewY);
1192 VectorCopy(m_Camera.vright, viewX);
1194 // compute best vectors
1195 //ComputeBest2DVector(viewX, texS, texT, XS, XT);
1196 //ComputeBest2DVector(viewY, texS, texT, YS, YT);
1198 // check this is not a degenerate case
1199 if ((XS == YS) && (XT == YT))
1202 common->Printf("Warning : degenerate best vectors axis base in CCamWnd::ShiftTexture_BrushPrimit\n");
1205 Select_ShiftTexture_BrushPrimit(f, x, y, false);
1209 // compute best fitted translation in face axis base
1210 outS = XS * x + YS * y;
1211 outT = XT * x + YT * y;
1213 // call actual texture shifting code
1214 Select_ShiftTexture_BrushPrimit(f, outS, outT, false);
1219 bool IsBModel(brush_t *b) {
1220 const char *v = ValueForKey( b->owner, "model" );
1222 const char *n = ValueForKey( b->owner, "name");
1223 return (stricmp( n, v ) == 0);
1230 BuildEntityRenderState
1232 Creates or updates modelDef and lightDef for an entity
1235 int Brush_ToTris(brush_t *brush, idTriList *tris, idMatList *mats, bool models, bool bmodel);
1237 void CCamWnd::BuildEntityRenderState( entity_t *ent, bool update) {
1240 const char *name = NULL;
1242 Entity_UpdateSoundEmitter( ent );
1244 // delete the existing def if we aren't creating a brand new world
1246 if ( ent->lightDef >= 0 ) {
1247 g_qeglobals.rw->FreeLightDef( ent->lightDef );
1251 if ( ent->modelDef >= 0 ) {
1252 g_qeglobals.rw->FreeEntityDef( ent->modelDef );
1257 // if an entity doesn't have any brushes at all, don't do anything
1258 if ( ent->brushes.onext == &ent->brushes ) {
1262 // if the brush isn't displayed (filtered or culled), don't do anything
1263 if (FilterBrush(ent->brushes.onext)) {
1267 spawnArgs = ent->epairs;
1268 if (ent->eclass->defArgs.FindKey("model")) {
1269 spawnArgs.Set("model", ent->eclass->defArgs.GetString("model"));
1272 // any entity can have a model
1273 name = ValueForKey( ent, "name" );
1274 v = spawnArgs.GetString("model");
1276 renderEntity_t refent;
1278 refent.referenceSound = ent->soundEmitter;
1280 if ( !stricmp( name, v ) ) {
1281 // build the model from brushes
1282 idTriList tris(1024);
1283 idMatList mats(1024);
1285 for (brush_t *b = ent->brushes.onext; b != &ent->brushes; b = b->onext) {
1286 Brush_ToTris( b, &tris, &mats, false, true);
1289 if ( ent->modelDef >= 0 ) {
1290 g_qeglobals.rw->FreeEntityDef( ent->modelDef );
1294 idRenderModel *bmodel = renderModelManager->FindModel( name );
1297 renderModelManager->RemoveModel( bmodel );
1298 renderModelManager->FreeModel( bmodel );
1301 bmodel = renderModelManager->AllocModel();
1303 bmodel->InitEmpty( name );
1305 // add the surfaces to the renderModel
1306 modelSurface_t surf;
1307 for ( int i = 0 ; i < tris.Num() ; i++ ) {
1308 surf.geometry = tris[i];
1309 surf.shader = mats[i];
1310 bmodel->AddSurface( surf );
1313 bmodel->FinishSurfaces();
1315 renderModelManager->AddModel( bmodel );
1317 // FIXME: brush entities
1318 gameEdit->ParseSpawnArgsToRenderEntity( &spawnArgs, &refent );
1320 ent->modelDef = g_qeglobals.rw->AddEntityDef( &refent );
1323 // use the game's epair parsing code so
1324 // we can use the same renderEntity generation
1325 gameEdit->ParseSpawnArgsToRenderEntity( &spawnArgs, &refent );
1326 idRenderModelMD5 *md5 = dynamic_cast<idRenderModelMD5 *>( refent.hModel );
1329 spawnArgs.GetString("anim", "idle", str);
1330 refent.numJoints = md5->NumJoints();
1331 if ( update && refent.joints ) {
1332 Mem_Free16( refent.joints );
1334 refent.joints = ( idJointMat * )Mem_Alloc16( refent.numJoints * sizeof( *refent.joints ) );
1335 const idMD5Anim *anim = gameEdit->ANIM_GetAnimFromEntityDef(spawnArgs.GetString("classname"), str);
1336 int frame = spawnArgs.GetInt("frame") + 1;
1340 const idVec3 &offset = gameEdit->ANIM_GetModelOffsetFromEntityDef( spawnArgs.GetString("classname") );
1341 gameEdit->ANIM_CreateAnimFrame( md5, anim, refent.numJoints, refent.joints, ( frame * 1000 ) / 24, offset, false );
1343 if (ent->modelDef >= 0) {
1344 g_qeglobals.rw->FreeEntityDef( ent->modelDef );
1346 ent->modelDef = g_qeglobals.rw->AddEntityDef( &refent );
1350 // check for lightdefs
1351 if (!(ent->eclass->nShowFlags & ECLASS_LIGHT)) {
1355 if ( spawnArgs.GetBool( "start_off" ) ) {
1358 // use the game's epair parsing code so
1359 // we can use the same renderLight generation
1361 renderLight_t lightParms;
1363 gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &lightParms );
1364 lightParms.referenceSound = ent->soundEmitter;
1366 if (update && ent->lightDef >= 0) {
1367 g_qeglobals.rw->UpdateLightDef( ent->lightDef, &lightParms );
1369 if (ent->lightDef >= 0) {
1370 g_qeglobals.rw->FreeLightDef(ent->lightDef);
1372 ent->lightDef = g_qeglobals.rw->AddLightDef( &lightParms );
1377 void Tris_ToOBJ(const char *outFile, idTriList *tris, idMatList *mats) {
1378 idFile *f = fileSystem->OpenExplicitFileWrite( outFile );
1381 strcpy(out, outFile);
1382 StripExtension(out);
1384 idList<idStr*> matNames;
1387 idStr lastMaterial("");
1389 //idStr basePath = cvarSystem->GetCVarString( "fs_savepath" );
1390 f->Printf( "mtllib %s.mtl\n", out );
1391 for (i = 0; i < tris->Num(); i++) {
1392 srfTriangles_t *tri = (*tris)[i];
1393 for (j = 0; j < tri->numVerts; j++) {
1394 f->Printf( "v %f %f %f\n", tri->verts[j].xyz.x, tri->verts[j].xyz.z, -tri->verts[j].xyz.y );
1396 for (j = 0; j < tri->numVerts; j++) {
1397 f->Printf( "vt %f %f\n", tri->verts[j].st.x, 1.0f - tri->verts[j].st.y );
1399 for (j = 0; j < tri->numVerts; j++) {
1400 f->Printf( "vn %f %f %f\n", tri->verts[j].normal.x, tri->verts[j].normal.y, tri->verts[j].normal.z );
1403 if (stricmp( (*mats)[i]->GetName(), lastMaterial)) {
1404 lastMaterial = (*mats)[i]->GetName();
1407 for (k = 0; k < matNames.Num(); k++) {
1408 if ( idStr::Icmp(matNames[k]->c_str(), lastMaterial.c_str()) == 0 ) {
1410 // f->Printf( "usemtl m%i\n", k );
1411 f->Printf( "usemtl %s\n", lastMaterial.c_str() );
1417 // f->Printf( "usemtl m%i\n", matCount++ );
1418 f->Printf( "usemtl %s\n", lastMaterial.c_str() );
1419 matNames.Append(new idStr(lastMaterial));
1423 for (int j = 0; j < tri->numIndexes; j += 3) {
1425 i1 = tri->indexes[j+2] + indexBase;
1426 i2 = tri->indexes[j+1] + indexBase;
1427 i3 = tri->indexes[j] + indexBase;
1428 f->Printf( "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i1,i1,i1, i2,i2,i2, i3,i3,i3 );
1431 indexBase += tri->numVerts;
1434 fileSystem->CloseFile( f );
1436 strcat(out, ".mtl");
1437 f = fileSystem->OpenExplicitFileWrite( out );
1439 for (k = 0; k < matNames.Num(); k++) {
1440 // This presumes the diffuse tga name matches the material name
1441 f->Printf( "newmtl %s\n\tNs 0\n\td 1\n\tillum 2\n\tKd 0 0 0 \n\tKs 0.22 0.22 0.22 \n\tKa 0 0 0 \n\tmap_Kd %s/base/%s.tga\n\n\n", matNames[k]->c_str(), "z:/d3xp", matNames[k]->c_str() );
1443 fileSystem->CloseFile( f );
1449 int Brush_TransformModel(brush_t *brush, idTriList *tris, idMatList *mats) {
1451 if (brush->modelHandle > 0 ) {
1452 idRenderModel *model = brush->modelHandle;
1454 float a = FloatForKey(brush->owner, "angle");
1456 //FIXME: support full rotation matrix
1457 bool matrix = false;
1459 s = sin( DEG2RAD(a) );
1460 c = cos( DEG2RAD(a) );
1463 if (GetMatrixForKey(brush->owner, "rotation", mat)) {
1468 for (int i = 0; i < model->NumSurfaces() ; i++) {
1469 const modelSurface_t *surf = model->Surface( i );
1470 srfTriangles_t *tri = surf->geometry;
1471 srfTriangles_t *tri2 = R_CopyStaticTriSurf(tri);
1472 for (int j = 0; j < tri2->numVerts; j++) {
1475 v = tri2->verts[j].xyz * brush->owner->rotation + brush->owner->origin;
1477 v = tri2->verts[j].xyz;
1478 VectorAdd(v, brush->owner->origin, v);
1482 float x2 = (((x - brush->owner->origin[0]) * c) - ((y - brush->owner->origin[1]) * s)) + brush->owner->origin[0];
1483 float y2 = (((x - brush->owner->origin[0]) * s) + ((y - brush->owner->origin[1]) * c)) + brush->owner->origin[1];
1490 tri2->verts[j].xyz = v;
1493 mats->Append( surf->shader );
1495 return model->NumSurfaces();
1502 #define MAX_TRI_SURFACES 16384
1503 int Brush_ToTris(brush_t *brush, idTriList *tris, idMatList *mats, bool models, bool bmodel) {
1505 srfTriangles_t *tri;
1509 if (brush->modelHandle > 0 ) {
1513 return Brush_TransformModel(brush, tris, mats);
1517 int numSurfaces = 0;
1519 if ( brush->owner->eclass->fixedsize && !brush->entityModel) {
1523 if ( brush->pPatch ) {
1529 // build a patch mesh
1530 idSurface_Patch *cp = new idSurface_Patch( pm->width * 6, pm->height * 6 );
1531 cp->SetSize( pm->width, pm->height );
1532 for ( i = 0; i < pm->width; i++ ) {
1533 for ( j = 0; j < pm->height; j++ ) {
1534 (*cp)[j*cp->GetWidth()+i].xyz = pm->ctrl(i, j).xyz;
1535 (*cp)[j*cp->GetWidth()+i].st = pm->ctrl(i, j).st;
1540 if ( pm->explicitSubdivisions ) {
1541 cp->SubdivideExplicit( pm->horzSubdivisions, pm->vertSubdivisions, true );
1543 cp->Subdivide( DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_LENGTH, true );
1545 width = cp->GetWidth();
1546 height = cp->GetHeight();
1548 // convert to srfTriangles
1549 tri = R_AllocStaticTriSurf();
1550 tri->numVerts = width * height;
1551 tri->numIndexes = 6 * ( width - 1 ) * ( height - 1 );
1552 R_AllocStaticTriSurfVerts( tri, tri->numVerts );
1553 R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
1554 for ( i = 0 ; i < tri->numVerts ; i++ ) {
1555 tri->verts[i] = (*cp)[i];
1557 tri->verts[i].xyz -= brush->owner->origin;
1561 tri->numIndexes = 0;
1562 for ( i = 1 ; i < width ; i++ ) {
1563 for ( j = 1 ; j < height ; j++ ) {
1564 tri->indexes[tri->numIndexes++] = ( j - 1 ) * width + i;
1565 tri->indexes[tri->numIndexes++] = ( j - 1 ) * width + i - 1;
1566 tri->indexes[tri->numIndexes++] = j * width + i - 1;
1568 tri->indexes[tri->numIndexes++] = j * width + i;
1569 tri->indexes[tri->numIndexes++] = ( j - 1 ) * width + i;
1570 tri->indexes[tri->numIndexes++] = j * width + i - 1;
1577 mats->Append(pm->d_texture);
1578 //surfaces[numSurfaces] = tri;
1579 //materials[numSurfaces] = pm->d_texture;
1586 for ( face_t *face = brush->brush_faces ; face; face = face->next ) {
1589 w = face->face_winding;
1591 continue; // freed or degenerate face
1594 tri = R_AllocStaticTriSurf();
1595 tri->numVerts = w->GetNumPoints();
1596 tri->numIndexes = ( w->GetNumPoints() - 2 ) * 3;
1597 R_AllocStaticTriSurfVerts( tri, tri->numVerts );
1598 R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
1600 for ( i = 0 ; i < tri->numVerts ; i++ ) {
1602 tri->verts[i].Clear();
1604 tri->verts[i].xyz[0] = (*w)[i][0];
1605 tri->verts[i].xyz[1] = (*w)[i][1];
1606 tri->verts[i].xyz[2] = (*w)[i][2];
1609 tri->verts[i].xyz -= brush->owner->origin;
1612 tri->verts[i].st[0] = (*w)[i][3];
1613 tri->verts[i].st[1] = (*w)[i][4];
1615 tri->verts[i].normal = face->plane.Normal();
1618 tri->numIndexes = 0;
1619 for ( i = 2 ; i < w->GetNumPoints() ; i++ ) {
1620 tri->indexes[tri->numIndexes++] = 0;
1621 tri->indexes[tri->numIndexes++] = i-1;
1622 tri->indexes[tri->numIndexes++] = i;
1626 mats->Append(face->d_texture);
1633 void Select_ToOBJ() {
1635 CFileDialog dlgFile(FALSE, "obj", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "Wavefront object files (*.obj)|*.obj||", g_pParentWnd);
1636 if (dlgFile.DoModal() == IDOK) {
1637 idTriList tris(1024);
1638 idMatList mats(1024);
1640 for (brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) {
1642 if ( b->hiddenBrush ) {
1646 if (FilterBrush(b)) {
1650 Brush_ToTris(b, &tris, &mats, true, false);
1653 Tris_ToOBJ(dlgFile.GetPathName().GetBuffer(0), &tris, &mats);
1655 for( i = 0; i < tris.Num(); i++ ) {
1656 R_FreeStaticTriSurf( tris[i] );
1662 void Select_ToCM() {
1663 CFileDialog dlgFile( FALSE, "lwo, ase", NULL, 0, "(*.lwo)|*.lwo|(*.ase)|*.ase|(*.ma)|*.ma||", g_pParentWnd );
1665 if ( dlgFile.DoModal() == IDOK ) {
1666 idMapEntity *mapEnt;
1670 name = fileSystem->OSPathToRelativePath( dlgFile.GetPathName() );
1671 name.BackSlashesToSlashes();
1673 mapEnt = new idMapEntity();
1674 mapEnt->epairs.Set( "name", name.c_str() );
1676 for ( brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next ) {
1678 if ( b->hiddenBrush ) {
1682 if ( FilterBrush( b ) ) {
1686 p = BrushToMapPrimitive( b, b->owner->origin );
1688 mapEnt->AddPrimitive( p );
1692 collisionModelManager->WriteCollisionModelForMapEntity( mapEnt, name.c_str() );
1703 Builds models, lightdefs, and modeldefs for the current editor data
1704 so it can be rendered by the game renderSystem
1707 void CCamWnd::BuildRendererState() {
1708 renderEntity_t worldEntity;
1712 FreeRendererState();
1714 // the renderWorld holds all the references and defs
1715 g_qeglobals.rw->InitFromMap( NULL );
1717 // create the raw model for all the brushes
1719 int numSurfaces = 0;
1721 // the renderModel for the world holds all the geometry that isn't in an entity
1722 worldModel = renderModelManager->AllocModel();
1723 worldModel->InitEmpty( "EditorWorldModel" );
1725 for ( brush_t *brushList = &active_brushes ; brushList ;
1726 brushList = (brushList == &active_brushes) ? &selected_brushes : NULL ) {
1728 for (brush = brushList->next; brush != brushList; brush = brush->next) {
1730 if ( brush->hiddenBrush ) {
1734 if (FilterBrush(brush)) {
1738 if (CullBrush(brush, true)) {
1742 idTriList tris(1024);
1743 idMatList mats(1024);
1745 if (!IsBModel(brush)) {
1746 numSurfaces += Brush_ToTris( brush, &tris, &mats, false, false );
1749 // add the surfaces to the renderModel
1750 modelSurface_t surf;
1751 for ( int i = 0 ; i < tris.Num() ; i++ ) {
1752 surf.geometry = tris[i];
1753 surf.shader = mats[i];
1754 worldModel->AddSurface( surf );
1761 // bound and clean the triangles
1762 worldModel->FinishSurfaces();
1764 // the worldEntity just has the handle for the worldModel
1765 memset( &worldEntity, 0, sizeof( worldEntity ) );
1766 worldEntity.hModel = worldModel;
1767 worldEntity.axis = mat3_default;
1768 worldEntity.shaderParms[0] = 1;
1769 worldEntity.shaderParms[1] = 1;
1770 worldEntity.shaderParms[2] = 1;
1771 worldEntity.shaderParms[3] = 1;
1773 worldModelDef = g_qeglobals.rw->AddEntityDef( &worldEntity );
1775 // create the light and model entities exactly the way the game code would
1776 for ( ent = entities.next ; ent != &entities ; ent = ent->next ) {
1777 if ( ent->brushes.onext == &ent->brushes ) {
1781 if (CullBrush(ent->brushes.onext, true)) {
1785 if (Map_IsBrushFiltered(ent->brushes.onext)) {
1789 BuildEntityRenderState( ent, false );
1792 //common->Printf("Render data used %d brushes\n", numBrushes);
1798 ===============================
1799 CCamWnd::UpdateRenderEntities
1801 Creates a new entity state list
1802 returns true if a repaint is needed
1803 ===============================
1805 bool CCamWnd::UpdateRenderEntities() {
1812 for ( entity_t *ent = entities.next ; ent != &entities ; ent = ent->next ) {
1813 BuildEntityRenderState( ent, (ent->lightDef != -1 || ent->modelDef != -1 || ent->soundEmitter ) ? true : false );
1814 if (ret == false && ent->modelDef || ent->lightDef) {
1822 ============================
1823 CCamWnd::FreeRendererState
1825 Frees the render state data
1826 ============================
1828 void CCamWnd::FreeRendererState() {
1830 for ( entity_t *ent = entities.next ; ent != &entities ; ent = ent->next ) {
1831 if (ent->lightDef >= 0) {
1832 g_qeglobals.rw->FreeLightDef( ent->lightDef );
1836 if (ent->modelDef >= 0) {
1837 renderEntity_t *refent = const_cast<renderEntity_t *>(g_qeglobals.rw->GetRenderEntity( ent->modelDef ));
1839 if ( refent->callbackData ) {
1840 Mem_Free( refent->callbackData );
1841 refent->callbackData = NULL;
1843 if ( refent->joints ) {
1844 Mem_Free16(refent->joints);
1845 refent->joints = NULL;
1848 g_qeglobals.rw->FreeEntityDef( ent->modelDef );
1854 renderModelManager->FreeModel( worldModel );
1862 ========================
1863 CCamWnd::UpdateCaption
1865 updates the caption based on rendermode and whether the render mode needs updated
1866 ========================
1868 void CCamWnd::UpdateCaption() {
1876 strCaption += (renderMode) ? "RENDER" : "CAM";
1878 strCaption += (rebuildMode) ? " (Realtime)" : "";
1879 strCaption += (entityMode) ? " +lights" : "";
1880 strCaption += (selectMode) ? " +selected" : "";
1881 strCaption += (animationMode) ? " +anim" : "";
1883 strCaption += (soundMode) ? " +snd" : "";
1884 SetWindowText(strCaption);
1888 ===========================
1889 CCamWnd::ToggleRenderMode
1891 Toggles the render mode
1892 ===========================
1894 void CCamWnd::ToggleRenderMode() {
1900 ===========================
1901 CCamWnd::ToggleRebuildMode
1903 Toggles the rebuild mode
1904 ===========================
1906 void CCamWnd::ToggleRebuildMode() {
1912 ===========================
1913 CCamWnd::ToggleEntityMode
1915 Toggles the entity mode
1916 ===========================
1918 void CCamWnd::ToggleEntityMode() {
1925 ===========================
1926 CCamWnd::ToggleRenderMode
1928 Toggles the render mode
1929 ===========================
1931 void CCamWnd::ToggleAnimationMode() {
1933 if (animationMode) {
1934 SetTimer(0, 10, NULL);
1942 ===========================
1943 CCamWnd::ToggleSoundMode
1945 Toggles the sound mode
1946 ===========================
1948 void CCamWnd::ToggleSoundMode() {
1953 for ( entity_t *ent = entities.next ; ent != &entities ; ent = ent->next ) {
1954 Entity_UpdateSoundEmitter( ent );
1959 ===========================
1960 CCamWnd::ToggleRenderMode
1962 Toggles the render mode
1963 ===========================
1965 void CCamWnd::ToggleSelectMode() {
1971 =========================
1972 CCamWnd::MarkWorldDirty
1974 marks the render world as dirty
1975 =========================
1977 void CCamWnd::MarkWorldDirty() {
1984 =========================
1985 CCamWnd::DrawEntityData
1987 Draws entity data ( experimental )
1988 =========================
1990 extern void glBox(idVec4 &color, idVec3 &point, float size);
1992 void CCamWnd::DrawEntityData() {
1994 qglMatrixMode( GL_MODELVIEW );
1996 qglMatrixMode( GL_PROJECTION );
1999 SetProjectionMatrix();
2001 qglRotatef(-90, 1, 0, 0); // put Z going up
2002 qglRotatef(90, 0, 0, 1); // put Z going up
2003 qglRotatef(m_Camera.angles[0], 0, 1, 0);
2004 qglRotatef(-m_Camera.angles[1], 0, 0, 1);
2005 qglTranslatef(-m_Camera.origin[0], -m_Camera.origin[1], -m_Camera.origin[2]);
2009 if (!(entityMode || selectMode)) {
2013 qglDisable(GL_BLEND);
2014 qglDisable(GL_DEPTH_TEST);
2015 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2016 globalImages->BindNull();
2017 idVec3 color(0, 1, 0);
2018 qglColor3fv( color.ToFloatPtr() );
2020 brush_t *brushList = &active_brushes;
2023 for (brush_t *brush = brushList->next; brush != brushList; brush = brush->next) {
2025 if (CullBrush(brush, true)) {
2029 if (FilterBrush(brush)) {
2033 if ((pass == 1 && selectMode) || (entityMode && pass == 0 && brush->owner->lightDef >= 0)) {
2034 Brush_DrawXY(brush, 0, true, true);
2038 brushList = (brushList == &active_brushes) ? &selected_brushes : NULL;
2042 qglColor3fv( color.ToFloatPtr() );
2049 =======================================================================================================================
2052 This used the renderSystem to draw a fully lit view of the world
2053 =======================================================================================================================
2055 void CCamWnd::Cam_Render() {
2057 renderView_t refdef;
2058 CPaintDC dc(this); // device context for painting
2061 if (!active_brushes.next) {
2062 return; // not valid yet
2065 if (!qwglMakeCurrent(dc.m_hDC, win32.hGLRC)) {
2066 common->Printf("ERROR: wglMakeCurrent failed..\n ");
2067 common->Printf("Please restart " EDITOR_WINDOWTEXT " if the camera view is not working\n");
2071 // save the editor state
2072 //qglPushAttrib( GL_ALL_ATTRIB_BITS );
2073 qglClearColor( 0.1f, 0.1f, 0.1f, 0.0f );
2074 qglScissor( 0, 0, m_Camera.width, m_Camera.height );
2075 qglClear( GL_COLOR_BUFFER_BIT );
2077 // qwglSwapBuffers(dc.m_hDC);
2079 // create the model, using explicit normals
2080 if ( rebuildMode && worldDirty ) {
2081 BuildRendererState();
2085 renderSystem->BeginFrame( m_Camera.width, m_Camera.height );
2087 memset( &refdef, 0, sizeof( refdef ) );
2088 refdef.vieworg = m_Camera.origin;
2090 // the editor uses opposite pitch convention
2091 refdef.viewaxis = idAngles( -m_Camera.angles.pitch, m_Camera.angles.yaw, m_Camera.angles.roll ).ToMat3();
2093 refdef.width = SCREEN_WIDTH;
2094 refdef.height = SCREEN_HEIGHT;
2096 refdef.fov_y = 2 * atan((float)m_Camera.height / m_Camera.width) * idMath::M_RAD2DEG;
2098 // only set in animation mode to give a consistent look
2099 if (animationMode) {
2100 refdef.time = eventLoop->Milliseconds();
2103 g_qeglobals.rw->RenderScene( &refdef );
2105 int frontEnd, backEnd;
2107 renderSystem->EndFrame( &frontEnd, &backEnd );
2108 //common->Printf( "front:%i back:%i\n", frontEnd, backEnd );
2113 //qwglSwapBuffers(dc.m_hDC);
2114 // get back to the editor state
2115 qglMatrixMode( GL_MODELVIEW );
2121 void CCamWnd::OnTimer(UINT nIDEvent)
2123 if (animationMode || nIDEvent == 1) {
2124 Sys_UpdateWindows(W_CAMERA);
2126 if (nIDEvent == 1) {
2130 if (!animationMode ) {
2136 void CCamWnd::UpdateCameraView() {
2137 if (QE_SingleBrush(true, true)) {
2138 brush_t *b = selected_brushes.next;
2139 if (b->owner->eclass->nShowFlags & ECLASS_CAMERAVIEW) {
2140 // find the entity that targets this
2141 const char *name = ValueForKey(b->owner, "name");
2142 entity_t *ent = FindEntity("target", name);
2145 saveOrg = m_Camera.origin;
2146 saveAng = m_Camera.angles;
2149 idVec3 v = b->owner->origin - ent->origin;
2151 idAngles ang = v.ToMat3().ToAngles();
2152 ang.pitch = -ang.pitch;
2154 SetView( ent->origin, ang );
2156 Sys_UpdateWindows( W_CAMERA );
2162 SetView(saveOrg, saveAng);
2164 Sys_UpdateWindows(W_CAMERA);