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 static char THIS_FILE[] = __FILE__;
44 /////////////////////////////////////////////////////////////////////////////
46 class idMiniDrawVert {
50 idMiniDrawVert(float x, float y, float z, float s, float t) : xyz(x,y,z), st(s, t) {
54 static idMiniDrawVert cubeData[] = {
55 idMiniDrawVert(-1.0, -1.0, +1.0, 0.0, 0.0),
56 idMiniDrawVert(+1.0, -1.0, +1.0, 1.0, 0.0),
57 idMiniDrawVert(+1.0, +1.0, +1.0, 1.0, 1.0),
58 idMiniDrawVert(-1.0, +1.0, +1.0, 0.0, 1.0),
60 idMiniDrawVert(-1.0, -1.0, -1.0, 1.0, 0.0),
61 idMiniDrawVert(-1.0, +1.0, +1.0, 1.0, 1.0),
62 idMiniDrawVert(+1.0, +1.0, -1.0, 0.0, 1.0),
63 idMiniDrawVert(+1.0, -1.0, -1.0, 0.0, 0.0),
65 idMiniDrawVert(-1.0, +1.0, -1.0, 0.0, 1.0),
66 idMiniDrawVert(-1.0, +1.0, +1.0, 0.0, 0.0),
67 idMiniDrawVert(+1.0, +1.0, +1.0, 1.0, 0.0),
68 idMiniDrawVert(+1.0, +1.0, -1.0, 1.0, 1.0),
70 idMiniDrawVert(-1.0, -1.0, -1.0, 1.0, 1.0),
71 idMiniDrawVert(+1.0, -1.0, -1.0, 0.0, 1.0),
72 idMiniDrawVert(+1.0, -1.0, +1.0, 0.0, 0.0),
73 idMiniDrawVert(-1.0, -1.0, +1.0, 1.0, 0.0),
75 idMiniDrawVert(+1.0, -1.0, -1.0, 1.0, 0.0),
76 idMiniDrawVert(+1.0, +1.0, -1.0, 1.0, 1.0),
77 idMiniDrawVert(+1.0, +1.0, +1.0, 0.0, 1.0),
78 idMiniDrawVert(+1.0, -1.0, +1.0, 0.0, 0.0),
80 idMiniDrawVert(-1.0, -1.0, -1.0, 0.0, 0.0),
81 idMiniDrawVert(-1.0, -1.0, +1.0, 1.0, 0.0),
82 idMiniDrawVert(-1.0, +1.0, +1.0, 1.0, 1.0),
83 idMiniDrawVert(-1.0, +1.0, -1.0, 0.0, 1.0)
86 static int cubeSides = sizeof(cubeData) / sizeof(idMiniDrawVert);
87 static int numQuads = cubeSides / 4;
89 void glTexturedBox(idVec3 &point, float size, const idMaterial *mat) {
90 qglTranslatef(point.x, point.y, point.z);
91 for (int i = 0; i < numQuads; i++) {
93 for (int j = 0; j < 4; j++) {
94 idVec3 v = cubeData[i * 4 + j].xyz;
96 qglTexCoord2fv(cubeData[i * 4 + j].st.ToFloatPtr());
97 qglVertex3fv(v.ToFloatPtr());
103 idGLWidget::idGLWidget()
109 idGLWidget::~idGLWidget()
114 BEGIN_MESSAGE_MAP(idGLWidget, CWnd)
115 //{{AFX_MSG_MAP(idGLWidget)
130 /////////////////////////////////////////////////////////////////////////////
131 // idGLWidget message handlers
133 BOOL idGLWidget::PreCreateWindow(CREATESTRUCT& cs)
135 // TODO: Add your specialized code here and/or call the base class
137 return CWnd::PreCreateWindow(cs);
140 BOOL idGLWidget::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
142 if (CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext) == -1) {
147 QEW_SetupPixelFormat(dc->m_hDC, false);
154 void idGLWidget::OnPaint()
159 QEW_SetupPixelFormat(dc->m_hDC, false);
163 CPaintDC dc(this); // device context for painting
168 if (!qwglMakeCurrent(dc.m_hDC, win32.hGLRC)) {
171 qglViewport(0, 0, rect.Width(), rect.Height());
172 qglScissor(0, 0, rect.Width(), rect.Height());
173 qglMatrixMode(GL_PROJECTION);
175 qglClearColor (0.4f, 0.4f, 0.4f, 0.7f);
176 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
179 qglDisable(GL_DEPTH_TEST);
180 qglDisable(GL_BLEND);
181 qglOrtho(0, rect.Width(), 0, rect.Height(), -256, 256);
184 drawable->draw(1, 1, rect.Width()-1, rect.Height()-1);
186 qglViewport(0, 0, rect.Width(), rect.Height());
187 qglScissor(0, 0, rect.Width(), rect.Height());
188 qglMatrixMode(GL_PROJECTION);
190 qglClearColor (0.4f, 0.4f, 0.4f, 0.7f);
191 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
196 qwglMakeCurrent(win32.hDC, win32.hGLRC);
200 extern bool Sys_KeyDown(int key);
202 void idGLDrawable::buttonDown(int _button, float x, float y) {
206 if (button == MK_RBUTTON) {
211 void idGLDrawable::buttonUp(int button, float x, float y) {
215 extern float fDiff(float f1, float f2);
216 void idGLDrawable::mouseMove(float x, float y) {
219 if (Sys_KeyDown(VK_MENU)) {
222 float *px2 = &pressX;
224 if (fDiff(y, pressY) > fDiff(x, pressX)) {
232 if ( scale > 10.0f ) {
235 } else if (*px < *px2) {
238 if ( scale <= 0.001f ) {
244 ::SetCursorPos(pressX, pressY);
246 } else if (Sys_KeyDown(VK_SHIFT)) {
251 xOffset += (x - pressX);
255 yOffset -= (y - pressY);
258 //::SetCursorPos(pressX, pressY);
263 void idGLDrawable::draw(int x, int y, int w, int h) {
264 GL_State( GLS_DEFAULT );
265 qglViewport(x, y, w, h);
266 qglScissor(x, y, w, h);
267 qglMatrixMode(GL_PROJECTION);
268 qglClearColor( 0.1f, 0.1f, 0.1f, 0.0f );
269 qglClear(GL_COLOR_BUFFER_BIT);
270 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
273 globalImages->BindNull();
274 qglBegin(GL_LINE_LOOP);
276 qglVertex2f(x + 3, y + 3);
278 qglVertex2f(x + 3, h - 3);
280 qglVertex2f(w - 3, h - 3);
282 qglVertex2f(w - 3, y + 3);
287 static int viewAngle = -98;
288 void idGLDrawableMaterial::buttonDown(int button, float x, float y) {
289 idGLDrawable::buttonDown(button, x, y);
290 //viewAngle += (button == MK_LBUTTON) ? 15 : -15;
294 void idGLDrawableMaterial::mouseMove(float x, float y) {
297 bool doScale = Sys_KeyDown(VK_MENU);
298 bool doLight = Sys_KeyDown(VK_SHIFT);
299 if (doScale || doLight) {
302 float *px2 = &pressX;
304 if (fDiff(y, pressY) > fDiff(x, pressX)) {
313 if ( scale > 10.0f ) {
318 if ( light > 2.0f ) {
322 } else if (*px < *px2) {
326 if ( scale <= 0.001f ) {
331 if ( light < 0.0f ) {
337 ::SetCursorPos(pressX, pressY);
341 xOffset += (x - pressX);
345 yOffset -= (y - pressY);
348 //::SetCursorPos(pressX, pressY);
354 void idGLDrawableMaterial::draw(int x, int y, int w, int h) {
355 const idMaterial *mat = material;
357 qglViewport(x, y, w, h);
358 qglScissor(x, y, w, h);
359 qglMatrixMode(GL_PROJECTION);
360 qglClearColor( 0.1f, 0.1f, 0.1f, 0.0f );
361 qglClear(GL_COLOR_BUFFER_BIT);
367 spawnArgs.Set("classname", "light");
368 spawnArgs.Set("name", "light_1");
369 spawnArgs.Set("origin", "0 0 0");
371 sprintf(str, "%f %f %f", light, light, light);
372 spawnArgs.Set("_color", str);
373 gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &parms );
374 lightDef = world->AddLightDef( &parms );
376 idImage *img = (mat->GetNumStages() > 0) ? mat->GetStage(0)->texture.image : mat->GetEditorImage();
379 common->Warning("Unable to load image for preview for %s", mat->GetName());
383 int width = img->uploadWidth;
384 int height = img->uploadHeight;
389 srfTriangles_t *tris = worldModel->AllocSurfaceTriangles( 4, 6 );
391 tris->numIndexes = 6;
393 tris->indexes[0] = 0;
394 tris->indexes[1] = 1;
395 tris->indexes[2] = 2;
396 tris->indexes[3] = 3;
397 tris->indexes[4] = 1;
398 tris->indexes[5] = 0;
400 tris->verts[0].xyz.x = 64;
401 tris->verts[0].xyz.y = -xOffset + 0 - width / 2;
402 tris->verts[0].xyz.z = yOffset + 0 - height / 2;
403 tris->verts[0].st.x = 1;
404 tris->verts[0].st.y = 1;
406 tris->verts[1].xyz.x = 64;
407 tris->verts[1].xyz.y = -xOffset + width / 2;
408 tris->verts[1].xyz.z = yOffset + height / 2;
409 tris->verts[1].st.x = 0;
410 tris->verts[1].st.y = 0;
412 tris->verts[2].xyz.x = 64;
413 tris->verts[2].xyz.y = -xOffset + 0 - width / 2;
414 tris->verts[2].xyz.z = yOffset + height / 2;
415 tris->verts[2].st.x = 1;
416 tris->verts[2].st.y = 0;
418 tris->verts[3].xyz.x = 64;
419 tris->verts[3].xyz.y = -xOffset + width / 2;
420 tris->verts[3].xyz.z = yOffset + 0 - height / 2;
421 tris->verts[3].st.x = 0;
422 tris->verts[3].st.y = 1;
424 tris->verts[0].normal = tris->verts[1].xyz.Cross(tris->verts[3].xyz);
425 tris->verts[1].normal = tris->verts[2].normal = tris->verts[3].normal = tris->verts[0].normal;
428 worldModel->FinishSurfaces();
430 renderEntity_t worldEntity;
432 memset( &worldEntity, 0, sizeof( worldEntity ) );
433 if ( mat->HasGui() ) {
434 worldEntity.gui[ 0 ] = mat->GlobalGui();
436 worldEntity.hModel = worldModel;
437 worldEntity.axis = mat3_default;
438 worldEntity.shaderParms[0] = 1;
439 worldEntity.shaderParms[1] = 1;
440 worldEntity.shaderParms[2] = 1;
441 worldEntity.shaderParms[3] = 1;
442 modelDef = world->AddEntityDef( &worldEntity );
449 renderSystem->BeginFrame(w, h);
450 memset( &refdef, 0, sizeof( refdef ) );
451 refdef.vieworg.Set(viewAngle, 0, 0);
453 refdef.viewaxis = idAngles(0,0,0).ToMat3();
454 refdef.shaderParms[0] = 1;
455 refdef.shaderParms[1] = 1;
456 refdef.shaderParms[2] = 1;
457 refdef.shaderParms[3] = 1;
459 refdef.width = SCREEN_WIDTH;
460 refdef.height = SCREEN_HEIGHT;
462 refdef.fov_y = 2 * atan((float)h / w) * idMath::M_RAD2DEG;
464 refdef.time = eventLoop->Milliseconds();
466 world->RenderScene( &refdef );
467 int frontEnd, backEnd;
468 renderSystem->EndFrame( &frontEnd, &backEnd );
470 qglMatrixMode( GL_MODELVIEW );
476 void idGLDrawableMaterial::setMedia(const char *name) {
479 material = declManager->FindMaterial(name);
481 const shaderStage_t *stage = (material->GetNumStages() > 0) ? material->GetStage(0) : NULL;
483 img = stage->texture.image;
485 img = material->GetEditorImage();
491 // set scale to get a good fit
493 if (material && img) {
495 float size = (img->uploadWidth > img->uploadHeight) ? img->uploadWidth : img->uploadHeight;
496 // use 128 as base scale of 1.0
497 scale = 128.0 / size;
506 idGLDrawableModel::idGLDrawableModel(const char *name) {
507 worldModel = renderModelManager->FindModel( name );
512 idGLDrawableModel::idGLDrawableModel() {
513 worldModel = renderModelManager->DefaultModel();
517 void idGLDrawableModel::setMedia(const char *name) {
518 worldModel = renderModelManager->FindModel(name);
523 rotation.Set( 0.0f, 0.0f, 0.0f, 1.0f );
528 void idGLDrawableModel::SetSkin( const char *skin ) {
533 void idGLDrawableModel::buttonDown(int _button, float x, float y) {
537 lastPress.y = -( float )( 2 * x - rect.z ) / rect.z;
538 lastPress.x = -( float )( 2 * y - rect.w ) / rect.w;
541 if (button == MK_RBUTTON || button == MK_LBUTTON) {
546 void idGLDrawableModel::mouseMove(float x, float y) {
549 if (button == MK_LBUTTON) {
550 float cury = ( float )( 2 * x - rect.z ) / rect.z;
551 float curx = ( float )( 2 * y - rect.w ) / rect.w;
552 idVec3 to( -curx, -cury, 0.0f );
553 to.ProjectSelfOntoSphere( radius );
554 lastPress.ProjectSelfOntoSphere( radius );
556 axis.Cross( to, lastPress );
557 float len = ( lastPress - to ).Length() / ( 2.0f * radius );
558 len = idMath::ClampFloat( -1.0f, 1.0f, len );
559 float phi = 2.0f * asin ( len ) ;
562 axis *= sin( phi / 2.0f );
563 idQuat rot( axis.z, axis.y, axis.x, cos( phi / 2.0f ) );
567 rotation.Normalize();
572 bool doScale = Sys_KeyDown(VK_MENU);
573 bool doLight = Sys_KeyDown(VK_SHIFT);
577 float *px2 = &pressX;
579 if (fDiff(y, pressY) > fDiff(x, pressX)) {
586 if ( light > 2.0f ) {
589 } else if (*px < *px2) {
591 if ( light < 0.0f ) {
596 ::SetCursorPos(pressX, pressY);
601 zOffset += (x - pressX);
603 xOffset += (x - pressX);
609 zOffset -= (y - pressY);
611 yOffset -= (y - pressY);
615 //::SetCursorPos(pressX, pressY);
622 void idGLDrawableModel::draw(int x, int y, int w, int h) {
626 if ( worldModel->IsDynamicModel() != DM_STATIC ) {
630 rect.Set( x, y, w, h );
632 qglViewport(x, y, w, h);
633 qglScissor(x, y, w, h);
634 qglMatrixMode(GL_PROJECTION);
635 qglClearColor( 0.1f, 0.1f, 0.1f, 0.0f );
636 qglClear(GL_COLOR_BUFFER_BIT);
640 world->InitFromMap( NULL );
643 spawnArgs.Set("classname", "light");
644 spawnArgs.Set("name", "light_1");
645 spawnArgs.Set("origin", "-128 0 0");
647 sprintf(str, "%f %f %f", light, light, light);
648 spawnArgs.Set("_color", str);
649 gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &parms );
650 lightDef = world->AddLightDef( &parms );
652 renderEntity_t worldEntity;
653 memset( &worldEntity, 0, sizeof( worldEntity ) );
655 spawnArgs.Set("classname", "func_static");
656 spawnArgs.Set("name", spawnArgs.GetString("model"));
657 spawnArgs.Set("origin", "0 0 0");
658 if ( skinStr.Length() ) {
659 spawnArgs.Set( "skin", skinStr );
661 gameEdit->ParseSpawnArgsToRenderEntity(&spawnArgs, &worldEntity);
662 worldEntity.hModel = worldModel;
664 worldEntity.axis = rotation.ToMat3();
666 worldEntity.shaderParms[0] = 1;
667 worldEntity.shaderParms[1] = 1;
668 worldEntity.shaderParms[2] = 1;
669 worldEntity.shaderParms[3] = 1;
670 modelDef = world->AddEntityDef( &worldEntity );
677 renderSystem->BeginFrame(w, h);
678 memset( &refdef, 0, sizeof( refdef ) );
679 refdef.vieworg.Set(zOffset, xOffset, -yOffset);
681 refdef.viewaxis = idAngles(0,0,0).ToMat3();
682 refdef.shaderParms[0] = 1;
683 refdef.shaderParms[1] = 1;
684 refdef.shaderParms[2] = 1;
685 refdef.shaderParms[3] = 1;
687 refdef.width = SCREEN_WIDTH;
688 refdef.height = SCREEN_HEIGHT;
690 refdef.fov_y = 2 * atan((float)h / w) * idMath::M_RAD2DEG;
692 refdef.time = eventLoop->Milliseconds();
694 world->RenderScene( &refdef );
695 int frontEnd, backEnd;
696 renderSystem->EndFrame( &frontEnd, &backEnd );
698 qglMatrixMode( GL_MODELVIEW );
704 void idGLWidget::OnLButtonDown(UINT nFlags, CPoint point)
708 if ( drawable->ScreenCoords() ) {
709 ClientToScreen(&point);
711 drawable->buttonDown(MK_LBUTTON, point.x, point.y);
715 void idGLWidget::OnLButtonUp(UINT nFlags, CPoint point)
718 if ( drawable->ScreenCoords() ) {
719 ClientToScreen(&point);
721 drawable->buttonUp(MK_LBUTTON, point.x, point.y);
726 void idGLWidget::OnMButtonDown(UINT nFlags, CPoint point)
730 if ( drawable->ScreenCoords() ) {
731 ClientToScreen(&point);
733 drawable->buttonDown(MK_MBUTTON, point.x, point.y);
737 void idGLWidget::OnMButtonUp(UINT nFlags, CPoint point)
740 if ( drawable->ScreenCoords() ) {
741 ClientToScreen(&point);
743 drawable->buttonUp(MK_MBUTTON, point.x, point.y);
748 void idGLWidget::OnMouseMove(UINT nFlags, CPoint point)
751 if ( drawable->ScreenCoords() ) {
752 ClientToScreen(&point);
754 drawable->mouseMove(point.x, point.y);
759 BOOL idGLWidget::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
762 float f = drawable->getScale();
763 if ( zDelta > 0.0f ) {
774 drawable->setScale(f);
779 void idGLWidget::OnRButtonDown(UINT nFlags, CPoint point)
783 if ( drawable->ScreenCoords() ) {
784 ClientToScreen(&point);
786 drawable->buttonDown(MK_RBUTTON, point.x, point.y);
790 void idGLWidget::OnRButtonUp(UINT nFlags, CPoint point)
793 if ( drawable->ScreenCoords() ) {
794 ClientToScreen(&point);
796 drawable->buttonUp(MK_RBUTTON, point.x, point.y);
801 void idGLWidget::setDrawable(idGLDrawable *d) {
803 if (d->getRealTime()) {
804 SetTimer(1, d->getRealTime(), NULL);
809 void idGLWidget::OnTimer(UINT nIDEvent) {
810 if (drawable && drawable->getRealTime()) {
818 idGLDrawable::idGLDrawable() {
827 void idGLDrawableConsole::draw(int x, int y, int w, int h) {
828 qglPushAttrib( GL_ALL_ATTRIB_BITS );
829 qglClearColor( 0.1f, 0.1f, 0.1f, 0.0f );
830 qglScissor( 0, 0, w, h );
831 qglClear( GL_COLOR_BUFFER_BIT );
832 renderSystem->BeginFrame( w, h );
834 console->Draw( true );
836 renderSystem->EndFrame( NULL, NULL );
840 void idGLConsoleWidget::init() {
841 setDrawable(&console);
844 void idGLConsoleWidget::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
848 memset( &ev, 0, sizeof( ev ) );
853 ::console->ProcessEvent( &ev, true );
856 BEGIN_MESSAGE_MAP(idGLConsoleWidget, idGLWidget)
857 //{{AFX_MSG_MAP(idGLConsoleWidget)
868 void idGLConsoleWidget::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
872 memset( &ev, 0, sizeof( ev ) );
877 ::console->ProcessEvent( &ev, true );
880 void idGLConsoleWidget::OnPaint() {
881 idGLWidget::OnPaint();
884 void idGLConsoleWidget::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
888 memset( &ev, 0, sizeof( ev ) );
892 ::console->ProcessEvent( &ev, true );
895 void idGLConsoleWidget::OnLButtonDown(UINT nFlags, CPoint point) {
899 BOOL idGLWidget::OnEraseBkgnd(CDC* pDC)
903 //return CWnd::OnEraseBkgnd(pDC);
907 idGLDrawableWorld::idGLDrawableWorld() {
913 idGLDrawableWorld::~idGLDrawableWorld() {
917 void idGLDrawableWorld::AddTris(srfTriangles_t *tris, const idMaterial *mat) {
919 surf.geometry = tris;
921 worldModel->AddSurface( surf );
924 void idGLDrawableWorld::draw(int x, int y, int w, int h) {
928 void idGLDrawableWorld::InitWorld() {
929 if ( world == NULL ) {
930 world = renderSystem->AllocRenderWorld();
932 if ( worldModel == NULL ) {
933 worldModel = renderModelManager->AllocModel();
935 world->InitFromMap( NULL );
936 worldModel->InitEmpty( va( "GLWorldModel_%i", Sys_Milliseconds() ) );