if (APPLE)
add_definitions(-DGL_SILENCE_DEPRECATION=1)
- endif()
+ endif ()
set(CMAKE_POSITION_INDEPENDENT_CODE 1)
endif ()
endif ()
if (APPLE)
+ set(UNSUPPORTED_GL_SHARED_CONTEXT ON CACHE INTERNAL "...")
+
if (GTK_TARGET EQUAL 2)
add_definitions(-DWORKAROUND_MACOS_GTK2_DESTROY=1)
add_definitions(-DWORKAROUND_MACOS_GTK2_GLWIDGET=1)
add_definitions(-DWORKAROUND_MACOS_GTK2_LAGGYPOINTER=1)
endif ()
endif ()
+
+ if (UNSUPPORTED_GL_SHARED_CONTEXT)
+ set(DEFAULT_GL_SHARED_CONTEXT ON)
+ else ()
+ set(DEFAULT_GL_SHARED_CONTEXT OFF)
+ endif ()
+
+ option(USE_GL_UNSHARED_CONTEXT "Do not share GL Contexts" ${DEFAULT_GL_SHARED_CONTEXT})
+
+ if (USE_GL_UNSHARED_CONTEXT)
+ add_definitions(-DGL_UNSHARED_CONTEXT=1)
+ endif ()
endif ()
#-----------------------------------------------------------------------
// If a texture doesn't have a shader script, a default shader object is used.
// The IShader object was leaking also
// collect texture info: sizes, etc
- IShader* i = GlobalShaderSystem().getShaderForName( texture );
+ IShader* i = QERApp_Shader_ForName( texture );
+
pqtTexInfo = i->getTexture(); // shader width/height doesn't come out properly
if ( pqtTexInfo ) {
#define INCLUDED_IGLRENDER_H
#include "igl.h"
+#include "itextures.h"
#include "generic/vector.h"
class AABB;
class Matrix4;
unsigned int m_state;
std::size_t m_sort;
-GLint m_texture;
-GLint m_texture1;
-GLint m_texture2;
-GLint m_texture3;
-GLint m_texture4;
-GLint m_texture5;
-GLint m_texture6;
-GLint m_texture7;
+
+qtexture_t *m_qtexture;
+qtexture_t *m_qtexture1;
+qtexture_t *m_qtexture2;
+qtexture_t *m_qtexture3;
+qtexture_t *m_qtexture4;
+qtexture_t *m_qtexture5;
+qtexture_t *m_qtexture6;
+qtexture_t *m_qtexture7;
+
+GLuint m_texture;
+GLuint m_texture1;
+GLuint m_texture2;
+GLuint m_texture3;
+GLuint m_texture4;
+GLuint m_texture5;
+GLuint m_texture6;
+GLuint m_texture7;
+
Vector4 m_colour;
+
GLenum m_blend_src, m_blend_dst;
GLenum m_depthfunc;
GLenum m_alphafunc;
+
GLfloat m_alpharef;
GLfloat m_linewidth;
GLfloat m_pointsize;
+
GLint m_linestipple_factor;
GLushort m_linestipple_pattern;
+
OpenGLFogState m_fog;
GLProgram* m_program;
#include "generic/constant.h"
#include "generic/callback.h"
+#include "viewport/viewport.h"
// Rendering states to sort by.
// Higher bits have the most effect - slowest state changes should be highest.
virtual Shader* capture( const char* name ) = 0;
virtual void release( const char* name ) = 0;
/*! Render all Shader objects. */
-virtual void render( RenderStateFlags globalstate, const Matrix4& modelview, const Matrix4& projection, const Vector3& viewer = Vector3( 0, 0, 0 ) ) = 0;
+virtual void render( const enum ViewportId, RenderStateFlags globalstate, const Matrix4& modelview, const Matrix4& projection, const Vector3& viewer = Vector3( 0, 0, 0 ) ) = 0;
virtual void realise() = 0;
virtual void unrealise() = 0;
virtual void realise() = 0;
virtual void unrealise() = 0;
virtual void refresh() = 0;
+virtual bool refreshed() = 0;
+virtual void triggerRefresh() = 0;
+virtual bool triggeredRefresh() = 0;
// activate the shader for a given name and return it
// will return the default shader if name is not found
virtual IShader* getShaderForName( const char* name ) = 0;
#define INCLUDED_ITEXTURES_H
#include "iimage.h"
+#include "igl.h"
#include "generic/constant.h"
+#include "viewport/viewport.h"
+
struct qtexture_t;
+void LoadTextureRGBA( const enum ViewportId v, qtexture_t* q, Image* image );
+GLuint GetBindTextureNumber( const enum ViewportId v, const qtexture_t* q );
+GLuint RequestBindTextureNumber( const enum ViewportId v, qtexture_t* q );
+
class LoadImageCallback
{
typedef Image* ( *LoadFunc )( void* environment, const char* name );
if (BUILD_RADIANT)
add_subdirectory(gtkutil)
add_subdirectory(uilib)
+ add_subdirectory(viewport)
endif ()
add_subdirectory(l_net)
GdkGLConfig *glconfig = zbuffer ? glconfig_new_with_depth() : glconfig_new();
ASSERT_MESSAGE(glconfig, "failed to create OpenGL config");
+#if defined(GL_UNSHARED_CONTEXT)
+ const auto share_list = nullptr;
+#else // !GL_UNSHARED_CONTEXT
const auto share_list = g_shared ? gtk_widget_get_gl_context(g_shared) : nullptr;
+#endif // !GL_UNSHARED_CONTEXT
+
gtk_widget_set_gl_capability(self, glconfig, share_list, true, GDK_GL_RGBA_TYPE);
gtk_widget_realize(self);
else
{
globalOutputStream() << "Module Dependencies Failed: '" << typename Type::Name() << "' '" << APIConstructor::getName() << "'\n";
+ ASSERT_MESSAGE( m_dependencyCheck, "module dependencies failed" );
}
m_cycleCheck = true;
}
#if !defined ( INCLUDED_TEXTURELIB_H )
#define INCLUDED_TEXTURELIB_H
+#include "iimage.h"
+
#include "generic/vector.h"
+
+#include "viewport/viewport.h"
+
typedef Vector3 Colour3;
typedef unsigned int GLuint;
class LoadImageCallback;
const LoadImageCallback& load;
const char* name;
std::size_t width, height;
- GLuint texture_number; // gl bind number
+ GLuint texture_number[ VP_MAX ]; // GL texture bind number
Colour3 color; // for flat shade mode
int surfaceFlags, contentFlags, value;
+ bool loaded; // shader plugin has no knowledge about viewport and can't rely on texture_number
};
#endif
--- /dev/null
+add_library(viewport STATIC
+ viewport.cpp viewport.h
+ )
--- /dev/null
+#include "viewport.h"
+
+ViewportId g_viewport_id = VP_NONE;
--- /dev/null
+#if !defined ( INCLUDED_VIEWPORT_H )
+#define INCLUDED_VIEWPORT_H
+
+enum ViewportId {
+ VP_NONE,
+#if defined(GL_UNSHARED_CONTEXT)
+ VP_CAMWINDOW,
+ VP_TEXWINDOW,
+ VP_XYWINDOW,
+#else // !GL_UNSHARED_CONTEXT
+ VP_SHARED,
+ VP_CAMWINDOW = VP_SHARED,
+ VP_TEXWINDOW = VP_SHARED,
+ VP_XYWINDOW = VP_SHARED,
+#endif // !GL_UNSHARED_CONTEXT
+ VP_MAX
+};
+
+#endif // INCLUDED_VIEWPORT_H
void realise(){
m_pTexture = evaluateTexture( m_template.m_textureName, m_template.m_params, m_args );
- if ( m_pTexture->texture_number == 0 ) {
+ if ( !m_pTexture->loaded ) {
m_notfound = m_pTexture;
{
class Quake3ShaderSystem : public ShaderSystem, public ModuleObserver
{
+bool m_toBeRefreshed = false;
+bool m_refreshed = false;
+
public:
void realise(){
Shaders_Realise();
}
void refresh(){
- Shaders_Refresh();
+ if ( m_toBeRefreshed )
+ {
+ Shaders_Refresh();
+ m_toBeRefreshed = false;
+ m_refreshed = true;
+ }
+}
+
+bool refreshed(){
+ return m_refreshed;
+}
+
+void triggerRefresh(){
+ m_toBeRefreshed = true;
+ m_refreshed = false;
+}
+
+bool triggeredRefresh(){
+ return m_toBeRefreshed;
}
IShader* getShaderForName( const char* name ){
// Based on MD3Model source code by SPoG
//
+// This code looks to be dead and unused.
+// It is not ported to RequestBindTextureNumber().
+
#include "spritemodel.h"
void LoadSpriteModel( entity_interfaces_t *interfaces, const char *name ){
// texturing tools for Radiant
//
+// This code looks to be dead and unused.
+// It calls unknown symbols like m_pfnGetTextureNumber().
+// It is not ported to RequestBindTextureNumber().
+
#include "StdAfx.h"
static void dialog_button_callback( GtkWidget *widget, gpointer data ){
stream
string
uilib
+ viewport
xmllib
)
//
#include "camwindow.h"
+#include "texwindow.h" // TextureBrowser_ShowStartupShaders
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "debugging/debugging.h"
#include "iscenegraph.h"
+#include "ishaders.h"
#include "irender.h"
#include "igl.h"
#include "icamera.h"
+#include "textures.h"
#include "cullable.h"
#include "renderable.h"
#include "preferencesystem.h"
}
private:
+void Cam_Clear();
+void Cam_Init_World();
void Cam_Draw();
};
camwnd.queue_draw();
}
-
-
camwindow_globals_t g_camwindow_globals;
const Vector3& Camera_getOrigin( CamWnd& camwnd ){
}
void render( const Matrix4& modelview, const Matrix4& projection ){
- GlobalShaderCache().render( m_globalstate, modelview, projection, m_viewer );
+ if( GlobalShaderSystem().refreshed() )
+ {
+ GlobalShaderCache().render( VP_CAMWINDOW, m_globalstate, modelview, projection, m_viewer );
+ }
}
};
Callback<void(const Callback<void(bool)> &)> g_show_stats_callback( g_show_stats_caller );
ToggleItem g_show_stats( g_show_stats_callback );
+void CamWnd::Cam_Clear(){
+ Vector3 clearColour( 0, 0, 0 );
+ if ( m_Camera.draw_mode != cd_lighting ) {
+ clearColour = g_camwindow_globals.color_cameraback;
+ }
+
+ glClearColor( clearColour[0], clearColour[1], clearColour[2], 0 );
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+}
+
+// g_deferredStartupMap is set in main.cpp
+extern const char* g_deferredStartupMap;
+
+// g_loadedMap and g_deferredStartupShaders are set in map.cpp
+extern bool g_deferredStartupShaders;
+
+void CamWnd::Cam_Init_World(){
+ // Only run and run once when Textures_TriggerRealise() is called before.
+ if ( Textures_TriggeredRealise() )
+ {
+ Textures_Realise();
+ }
+
+ // Only run and run once when GlobalShaderSystem().TriggerRefresh() is called before.
+
+ if ( GlobalShaderSystem().triggeredRefresh() )
+ {
+ GlobalShaderSystem().refresh();
+ }
+
+ if ( g_deferredStartupShaders )
+ {
+ TextureBrowser_ShowStartupShaders( GlobalTextureBrowser() );
+ g_deferredStartupShaders = false;
+ }
+
+ // Load the “to be loaded at startup” map when GL viewport
+ // is cleared and builtin shaders are realised.
+ if ( g_deferredStartupMap != nullptr )
+ {
+ Map_Free();
+ Map_LoadFile( g_deferredStartupMap );
+ g_deferredStartupMap = nullptr;
+ }
+}
+
void CamWnd::Cam_Draw(){
glViewport( 0, 0, m_Camera.width, m_Camera.height );
#if 0
glDepthMask( GL_TRUE );
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
- Vector3 clearColour( 0, 0, 0 );
- if ( m_Camera.draw_mode != cd_lighting ) {
- clearColour = g_camwindow_globals.color_cameraback;
- }
-
- glClearColor( clearColour[0], clearColour[1], clearColour[2], 0 );
- glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+ Cam_Clear();
extern void Renderer_ResetStats();
Renderer_ResetStats();
void CamWnd::draw(){
m_drawing = true;
+ if ( Textures_TriggeredRealise() || GlobalShaderSystem().triggeredRefresh() || g_deferredStartupShaders )
+ {
+ // Draw something to not display garbage while iterating textures.
+ if ( glwidget_make_current( m_gl_widget ) != FALSE ) {
+ if ( ScreenUpdates_Enabled() ) {
+ GlobalOpenGL_debugAssertNoErrors();
+ glViewport( 0, 0, m_Camera.width, m_Camera.height );
+ Cam_Clear();
+ GlobalOpenGL_debugAssertNoErrors();
+ }
+
+ Cam_Init_World();
+
+ glwidget_swap_buffers( m_gl_widget );
+ }
+ }
+
//globalOutputStream() << "draw...\n";
if ( glwidget_make_current( m_gl_widget ) != FALSE ) {
if ( Map_Valid( g_map ) && ScreenUpdates_Enabled() ) {
CamWnd_Update( camwnd );
}
+void GlobalCamera_SetVisible(){
+ g_camera_shown.set( true );
+}
+
camera_draw_mode CamWnd_GetMode(){
return camera_t::draw_mode;
}
void CamWnd_registerShortcuts();
void GlobalCamera_Benchmark();
+void GlobalCamera_SetVisible();
const Vector3& Camera_getOrigin( CamWnd& camwnd );
void Camera_setOrigin( CamWnd& camwnd, const Vector3& origin );
SaveCommandMap( path.c_str() );
}
+const char *g_deferredStartupMap = nullptr;
+
/* HACK: If ui::main is not called yet,
gtk_main_quit will not quit, so tell main
to not call ui::main. This happens when a
g_GamesDialog.m_bForceLogConsole = false;
}
-
Radiant_Initialise();
user_shortcuts_init();
hide_splash();
+ // Always load an empty map at startup.
+ Map_New();
+
+ // Defer the map loading to the time GL viewports are cleared,
+ // prevent garbage to be rendered while loading map and related assets.
+ // The deferred map is now loaded by the camwindow istelf and map related
+ // textures and GL states are now loaded and set by camwindow, so the
+ // camwindow must always be visible at map loading time.
if ( mapname != NULL ) {
- Map_LoadFile( mapname );
+ g_deferredStartupMap = mapname;
}
else if ( g_bLoadLastMap && !g_strLastMap.empty() ) {
- Map_LoadFile( g_strLastMap.c_str() );
+ g_deferredStartupMap = g_strLastMap.c_str();
}
- else
- {
- Map_New();
- }
-
- // load up shaders now that we have the map loaded
- // eviltypeguy
- TextureBrowser_ShowStartupShaders( GlobalTextureBrowser() );
-
remove_local_pid();
void VFS_Refresh(){
if ( !g_vfsInitialized ) return;
+ // Always set camwindow visible when reloading VFS
+ // especially when loading maps, because GL states loaded
+ // by the camwindow are also used by the xywindow.
+ // Loading map at startup (not deferred) may also requires this
+ // to make sure GL states are ready at map loading time
+ // since camwindow is now the place to initialize GL stuff.
+ GlobalCamera_SetVisible();
GlobalFileSystem().clear();
QE_InitVFS();
GlobalFileSystem().refresh();
}
void UpdateAllWindows(){
- GlobalCamera_UpdateWindow();
XY_UpdateAllWindows();
+ GlobalCamera_UpdateWindow();
}
}
void ClipperChangeNotify(){
- GlobalCamera_UpdateWindow();
XY_UpdateAllWindows();
+ GlobalCamera_UpdateWindow();
}
ShaderCache_extensionsInitialised();
GlobalShaderCache().realise();
- Textures_Realise();
+ Textures_TriggerRealise();
#if GDEF_OS_WINDOWS
/* win32 is dodgy here, just use courier new then */
#include "brush.h"
bool g_writeMapComments = true;
+bool g_deferredStartupShaders = false;
class NameObserver
{
g_currentMap = &g_map;
+ // Load up shaders now that we have the map loaded.
+ g_deferredStartupShaders = true;
+
Brush_switchFormat( switch_format );
}
// restart VFS to apply new pak filtering based on mapname
// needed for daemon DPK VFS
VFS_Restart();
+
+ // Load up shaders now that we have the map loaded.
+ g_deferredStartupShaders = true;
}
extern void ConstructRegionBrushes( scene::Node * brushes[6], const Vector3 ®ion_mins, const Vector3 ®ion_maxs );
#include "xywindow.h"
-
#define DEBUG_RENDER 0
inline void debug_string( const char* string ){
qtexture_t* g_attenuation_xy = 0;
qtexture_t* g_attenuation_z = 0;
-void createVertexProgram(){
+void createVertexProgram( const enum ViewportId v ){
{
glGenProgramsNV( 1, &m_vertex_program );
glBindProgramNV( GL_VERTEX_PROGRAM_NV, m_vertex_program );
g_attenuation_xy = GlobalTexturesCache().capture( "lights/squarelight1" );
glActiveTexture( GL_TEXTURE0 );
- glBindTexture( GL_TEXTURE_2D, g_attenuation_xy->texture_number );
+ glBindTexture( GL_TEXTURE_2D, requestTextureBind( v, g_attenuation_xy ) );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
g_attenuation_z = GlobalTexturesCache().capture( "lights/squarelight1a" );
glActiveTexture( GL_TEXTURE0 );
- glBindTexture( GL_TEXTURE_2D, g_attenuation_z->texture_number );
+ glBindTexture( GL_TEXTURE_2D, requestTextureBind( v, g_attenuation_z ) );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
bool g_texcoordArray_enabled = false;
bool g_colorArray_enabled = false;
+GLuint requestTextureBind( const enum ViewportId v, qtexture_t *q ){
+ if ( q != nullptr )
+ {
+ return RequestBindTextureNumber( v, q );
+ }
+
+ return 0;
+}
+
inline bool OpenGLState_less( const OpenGLState& self, const OpenGLState& other ){
//! Sort by sort-order override.
if ( self.m_sort != other.m_sort ) {
return self.m_sort < other.m_sort;
}
+
//! Sort by texture handle.
+ // HACK: The same data it reused whatever the viewport,
+ // but it is expected to produce the same result anyway.
if ( self.m_texture != other.m_texture ) {
return self.m_texture < other.m_texture;
}
if ( self.m_texture7 != other.m_texture7 ) {
return self.m_texture7 < other.m_texture7;
}
+
//! Sort by state bit-vector.
if ( self.m_state != other.m_state ) {
return self.m_state < other.m_state;
}
+
//! Comparing address makes sure states are never equal.
return &self < &other;
}
void OpenGLState_constructDefault( OpenGLState& state ){
state.m_state = RENDER_DEFAULT;
+ state.m_qtexture = nullptr;
+ state.m_qtexture1 = nullptr;
+ state.m_qtexture2 = nullptr;
+ state.m_qtexture3 = nullptr;
+ state.m_qtexture4 = nullptr;
+ state.m_qtexture5 = nullptr;
+ state.m_qtexture6 = nullptr;
+ state.m_qtexture7 = nullptr;
+
state.m_texture = 0;
state.m_texture1 = 0;
state.m_texture2 = 0;
return m_state;
}
-void render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer );
+void render( const enum ViewportId, OpenGLState& current, unsigned int globalstate, const Vector3& viewer );
};
#define LIGHT_SHADER_DEBUG 0
|| *name == '<'
|| *name == '('
|| strchr( name, '\\' ) == 0, "shader name contains invalid characters: \"" << name << "\"" );
+
#if DEBUG_SHADERS
globalOutputStream() << "shaders capture: " << makeQuoted( name ) << '\n';
#endif
+
return m_shaders.capture( name ).get();
}
#endif
m_shaders.release( name );
}
-void render( RenderStateFlags globalstate, const Matrix4& modelview, const Matrix4& projection, const Vector3& viewer ){
+void render( const enum ViewportId v, RenderStateFlags globalstate, const Matrix4& modelview, const Matrix4& projection, const Vector3& viewer ){
glMatrixMode( GL_PROJECTION );
glLoadMatrixf( reinterpret_cast<const float*>( &projection ) );
#if 0
debug_string( "begin rendering" );
for ( OpenGLStates::iterator i = g_state_sorted.begin(); i != g_state_sorted.end(); ++i )
{
- ( *i ).second->render( current, globalstate, viewer );
+ ( *i ).second->render( v, current, globalstate, viewer );
}
debug_string( "end rendering" );
}
return g_ShaderCache;
}
-inline void setTextureState( GLint& current, const GLint& texture, GLenum textureUnit ){
+inline void setTextureState( GLuint& current, const GLuint& texture, GLenum textureUnit ){
if ( texture != current ) {
glActiveTexture( textureUnit );
glClientActiveTexture( textureUnit );
}
}
-inline void setTextureState( GLint& current, const GLint& texture ){
+inline void setTextureState( GLuint& current, const GLuint& texture ){
if ( texture != current ) {
glBindTexture( GL_TEXTURE_2D, texture );
GlobalOpenGL_debugAssertNoErrors();
}
}
-void OpenGLState_apply( const OpenGLState& self, OpenGLState& current, unsigned int globalstate ){
- debug_int( "sort", int(self.m_sort) );
+void OpenGLState_apply( const enum ViewportId v, OpenGLState& self, OpenGLState& current, unsigned int globalstate ){
+ self.m_texture = requestTextureBind( v, self.m_qtexture );
debug_int( "texture", self.m_texture );
+ debug_int( "sort", int(self.m_sort) );
debug_int( "state", self.m_state );
debug_int( "address", int(std::size_t( &self ) ) );
current.m_alpharef = self.m_alpharef;
}
+ // Request texture binds.
+ current.m_texture = requestTextureBind( v, current.m_qtexture );
+ current.m_texture1 = requestTextureBind( v, current.m_qtexture1 );
+ current.m_texture2 = requestTextureBind( v, current.m_qtexture2 );
+ current.m_texture3 = requestTextureBind( v, current.m_qtexture3 );
+ current.m_texture4 = requestTextureBind( v, current.m_qtexture4 );
+ current.m_texture5 = requestTextureBind( v, current.m_qtexture5 );
+ current.m_texture6 = requestTextureBind( v, current.m_qtexture6 );
+ current.m_texture7 = requestTextureBind( v, current.m_qtexture7 );
+
+ // Request texture binds.
+ self.m_texture = requestTextureBind( v, self.m_qtexture );
+ self.m_texture1 = requestTextureBind( v, self.m_qtexture1 );
+ self.m_texture2 = requestTextureBind( v, self.m_qtexture2 );
+ self.m_texture3 = requestTextureBind( v, self.m_qtexture3 );
+ self.m_texture4 = requestTextureBind( v, self.m_qtexture4 );
+ self.m_texture5 = requestTextureBind( v, self.m_qtexture5 );
+ self.m_texture6 = requestTextureBind( v, self.m_qtexture6 );
+ self.m_texture7 = requestTextureBind( v, self.m_qtexture7 );
+
{
- GLint texture0 = 0;
- GLint texture1 = 0;
- GLint texture2 = 0;
- GLint texture3 = 0;
- GLint texture4 = 0;
- GLint texture5 = 0;
- GLint texture6 = 0;
- GLint texture7 = 0;
- //if(state & RENDER_TEXTURE) != 0)
- {
- texture0 = self.m_texture;
- texture1 = self.m_texture1;
- texture2 = self.m_texture2;
- texture3 = self.m_texture3;
- texture4 = self.m_texture4;
- texture5 = self.m_texture5;
- texture6 = self.m_texture6;
- texture7 = self.m_texture7;
- }
+ GLuint texture0 = self.m_texture;
+ GLuint texture1 = self.m_texture1;
+ GLuint texture2 = self.m_texture2;
+ GLuint texture3 = self.m_texture3;
+ GLuint texture4 = self.m_texture4;
+ GLuint texture5 = self.m_texture5;
+ GLuint texture6 = self.m_texture6;
+ GLuint texture7 = self.m_texture7;
if ( GlobalOpenGL().GL_1_3() ) {
setTextureState( current.m_texture, texture0, GL_TEXTURE0 );
}
}
-
if ( state & RENDER_TEXTURE && self.m_colour[3] != current.m_colour[3] ) {
debug_colour( "setting alpha" );
glColor4f( 1,1,1,self.m_colour[3] );
GlobalOpenGL_debugAssertNoErrors();
}
-void Renderables_flush( OpenGLStateBucket::Renderables& renderables, OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
+void Renderables_flush( const enum ViewportId v, OpenGLStateBucket::Renderables& renderables, OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
const Matrix4* transform = 0;
+
glPushMatrix();
for ( OpenGLStateBucket::Renderables::const_iterator i = renderables.begin(); i != renderables.end(); ++i )
{
if ( current.m_program != 0 && ( *i ).m_light != 0 ) {
const IShader& lightShader = static_cast<OpenGLShader*>( ( *i ).m_light->getShader() )->getShader();
if ( lightShader.firstLayer() != 0 ) {
- GLuint attenuation_xy = lightShader.firstLayer()->texture()->texture_number;
+ GLuint attenuation_xy = requestTextureBind( v, lightShader.firstLayer()->texture() );
GLuint attenuation_z = lightShader.lightFalloffImage() != 0
- ? lightShader.lightFalloffImage()->texture_number
- : static_cast<OpenGLShader*>( g_defaultPointLight )->getShader().lightFalloffImage()->texture_number;
+ ? requestTextureBind( v, lightShader.lightFalloffImage() )
+ : requestTextureBind( v, static_cast<OpenGLShader*>( g_defaultPointLight )->getShader().lightFalloffImage() );
+
+ current.m_texture3 = requestTextureBind( v, current.m_qtexture3 );
setTextureState( current.m_texture3, attenuation_xy, GL_TEXTURE3 );
glActiveTexture( GL_TEXTURE3 );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
+ current.m_texture4 = requestTextureBind( v, current.m_qtexture4 );
+
setTextureState( current.m_texture4, attenuation_z, GL_TEXTURE4 );
glActiveTexture( GL_TEXTURE4 );
glBindTexture( GL_TEXTURE_2D, attenuation_z );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
-
AABB lightBounds( ( *i ).m_light->aabb() );
Matrix4 world2light( g_matrix4_identity );
renderables.clear();
}
-void OpenGLStateBucket::render( OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
+void OpenGLStateBucket::render( const enum ViewportId v, OpenGLState& current, unsigned int globalstate, const Vector3& viewer ){
if ( ( globalstate & m_state.m_state & RENDER_SCREEN ) != 0 ) {
- OpenGLState_apply( m_state, current, globalstate );
+ OpenGLState_apply( v, m_state, current, globalstate );
debug_colour( "screen fill" );
glMatrixMode( GL_PROJECTION );
glPopMatrix();
}
else if ( !m_renderables.empty() ) {
- OpenGLState_apply( m_state, current, globalstate );
- Renderables_flush( m_renderables, current, globalstate, viewer );
+ OpenGLState_apply( v, m_state, current, globalstate );
+ Renderables_flush( v, m_renderables, current, globalstate, viewer );
}
}
/// \todo Define special-case shaders in a data file.
void OpenGLShader::construct( const char* name ){
OpenGLState& state = appendDefaultPass();
+
+ // HACK: It is currently assumed this is only called by camwindow
+ // and that there is only one camwindow.
+ ViewportId v = VP_CAMWINDOW;
+
switch ( name[0] )
{
case '(':
// construction from IShader
m_shader = QERApp_Shader_ForName( name );
- if ( g_ShaderCache->lightingSupported() && g_ShaderCache->lightingEnabled() && m_shader->getBump() != 0 && m_shader->getBump()->texture_number != 0 ) { // is a bump shader
+ // FIXME: what if the image loading or upload fail?
+ if ( g_ShaderCache->lightingSupported() && g_ShaderCache->lightingEnabled() && m_shader->getBump() != 0 && requestTextureBind( v, m_shader->getBump() ) != 0 ) { // is a bump shader
state.m_state = RENDER_FILL | RENDER_CULLFACE | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_DEPTHWRITE | RENDER_COLOURWRITE | RENDER_PROGRAM;
state.m_colour[0] = 0;
state.m_colour[1] = 0;
}
OpenGLState& bumpPass = appendDefaultPass();
- bumpPass.m_texture = m_shader->getDiffuse()->texture_number;
- bumpPass.m_texture1 = m_shader->getBump()->texture_number;
- bumpPass.m_texture2 = m_shader->getSpecular()->texture_number;
+ bumpPass.m_qtexture = m_shader->getDiffuse();
+ bumpPass.m_texture = requestTextureBind( v, bumpPass.m_qtexture );
+ bumpPass.m_qtexture1 = m_shader->getBump();
+ bumpPass.m_texture1 = requestTextureBind( v, bumpPass.m_qtexture1 );
+ bumpPass.m_qtexture2 = m_shader->getSpecular();
+ bumpPass.m_texture2 = requestTextureBind( v, bumpPass.m_qtexture2 );
bumpPass.m_state = RENDER_BLEND | RENDER_FILL | RENDER_CULLFACE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_SMOOTH | RENDER_BUMP | RENDER_PROGRAM;
}
else
{
- state.m_texture = m_shader->getTexture()->texture_number;
+ state.m_qtexture = m_shader->getTexture();
+ state.m_texture = requestTextureBind( v, state.m_qtexture );
state.m_state = RENDER_FILL | RENDER_TEXTURE | RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_LIGHTING | RENDER_SMOOTH;
if ( ( m_shader->getFlags() & QER_CULL ) != 0 ) {
}
Face & face = g_SelectedFaceInstances.last().getFace();
- textureNum = face.getShader().m_state->getTexture().texture_number;
+ // FIXME: is it called by CamWindow thread?
+ textureNum = RequestBindTextureNumber( face.getShader().m_state->getTexture(), VP_CAMWINDOW );
textureSize.x() = face.getShader().m_state->getTexture().width;
textureSize.y() = face.getShader().m_state->getTexture().height;
//globalOutputStream() << "--> Texture #" << textureNum << ": " << textureSize.x() << " x " << textureSize.y() << "...\n";
#include "itextures.h"
#include "igl.h"
+
#include "preferencesystem.h"
#include "qgl.h"
#include "texmanip.h"
#include "preferences.h"
-
-
enum ETexturesMode
{
eTextures_NEAREST = 0,
/// \brief This function does the actual processing of raw RGBA data into a GL texture.
/// It will also resample to power-of-two dimensions, generate the mipmaps and adjust gamma.
-void LoadTextureRGBA( qtexture_t* q, unsigned char* pPixels, int nWidth, int nHeight ){
+void LoadTextureRGBA( const enum ViewportId v, qtexture_t* q, Image* image ){
static float fGamma = -1;
float total[3];
byte *outpixels = 0;
+
+ unsigned char* pPixels = image->getRGBAPixels();
+ int nWidth = image->getWidth();
+ int nHeight = image->getHeight();
int nCount = nWidth * nHeight;
if ( fGamma != g_texture_globals.fGamma ) {
q->color[1] = total[1] / ( nCount * 255 );
q->color[2] = total[2] / ( nCount * 255 );
- glGenTextures( 1, &q->texture_number );
+ glGenTextures( 1, &q->texture_number[ v ] );
+
+ ASSERT_MESSAGE( q->name != nullptr, "Undefined texture name" );
+
+#ifdef DEBUG_TEXTURES
+ // It may produce an infinite loop (never reproduced though):
+ // Log → Redraw → Log → Redraw…
+ globalOutputStream() << "LoadTextureRGBA: " << v << ", " << q->name << ", " << q->texture_number[ v ] << "\n";
+#endif
- glBindTexture( GL_TEXTURE_2D, q->texture_number );
+ glBindTexture( GL_TEXTURE_2D, q->texture_number[ v ] );
SetTexParameters( g_texture_mode );
}
}
+GLuint GetBindTextureNumber( const enum ViewportId v, const qtexture_t* q ){
+ ASSERT_MESSAGE( v >= VP_NONE && v < VP_MAX, "Unknown GL Viewport" );
+ ASSERT_MESSAGE( v != VP_NONE, "Unset GL Viewport" );
+
+ return q->texture_number[ v ];
+}
+
+GLuint RequestBindTextureNumber( const enum ViewportId v, qtexture_t* q ){
+ if ( GetBindTextureNumber( v, q ) == 0 )
+ {
+ ASSERT_MESSAGE( q->name != nullptr, "Undefined texture name" );
+
+ // It is common to set "" as unknown texture,
+ // expecting NetRadiant to display the notex fallback.
+ if ( q->name[0] == '\0' )
+ {
+ q->loaded = false;
+ return 0;
+ }
+
+ Image* image = GlobalTexturesCache().loadImage( q->name );
+
+ if ( image != nullptr )
+ {
+ LoadTextureRGBA( v, q, image );
+ q->surfaceFlags = image->getSurfaceFlags();
+ q->contentFlags = image->getContentFlags();
+ q->value = image->getValue();
+ GlobalOpenGL_debugAssertNoErrors();
+ globalOutputStream() << "Loaded Texture: \"" << q->name << "\"\n";
+ q->loaded = true;
+ image->release();
+ }
+ else
+ {
+ globalErrorStream() << "Texture load failed: \"" << q->name << "\"\n";
+ q->texture_number[ v ] = 0;
+ q->loaded = false;
+ }
+ }
+
+ return q->texture_number[ v ];
+}
+
#if 0
/*
==============
typedef std::pair<LoadImageCallback, CopiedString> TextureKey;
void qtexture_realise( qtexture_t& texture, const TextureKey& key ){
- texture.texture_number = 0;
if ( !string_empty( key.second.c_str() ) ) {
- Image* image = key.first.loadImage( key.second.c_str() );
- if ( image != 0 ) {
- LoadTextureRGBA( &texture, image->getRGBAPixels(), image->getWidth(), image->getHeight() );
- texture.surfaceFlags = image->getSurfaceFlags();
- texture.contentFlags = image->getContentFlags();
- texture.value = image->getValue();
+ for ( int v = VP_NONE; v < VP_MAX; v++ )
+ {
+ texture.texture_number[ v ] = 0;
+ }
+
+ texture.name = key.second.c_str();
+
+ ASSERT_MESSAGE( texture.name != nullptr, "Undefined texture name" );
+
+ // It is common to set "" as unknown texture,
+ // expecting NetRadiant to display the notex fallback.
+ if ( texture.name[0] == '\0' )
+ {
+ texture.loaded = false;
+ return;
+ }
+
+#if defined(GL_UNSHARED_CONTEXT)
+ Image* image = GlobalTexturesCache().loadImage( texture.name );
+ if ( image != nullptr )
+ {
+ texture.loaded = true;
image->release();
- globalOutputStream() << "Loaded Texture: \"" << key.second.c_str() << "\"\n";
- GlobalOpenGL_debugAssertNoErrors();
}
else
{
- globalErrorStream() << "Texture load failed: \"" << key.second.c_str() << "\"\n";
+ globalErrorStream() << "Texture load failed: \"" << texture.name << "\"\n";
+ // Can't reuse texture_number because shader plugin has no knowledge about viewport.
+ texture.loaded = false;
}
+#else // !GL_UNSHARED_CONTEXT
+ RequestBindTextureNumber( VP_SHARED, &texture );
+#endif // !GL_UNSHARED_CONTEXT
}
}
void qtexture_unrealise( qtexture_t& texture ){
- if ( GlobalOpenGL().contextValid && texture.texture_number != 0 ) {
- glDeleteTextures( 1, &texture.texture_number );
- GlobalOpenGL_debugAssertNoErrors();
+ for ( int v = VP_NONE; v < VP_MAX; v++ )
+ {
+ if ( GlobalOpenGL().contextValid && texture.texture_number[ v ] != 0 ) {
+ glDeleteTextures( 1, &texture.texture_number[ v ] );
+ GlobalOpenGL_debugAssertNoErrors();
+ }
}
}
break;
}
-
glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_tex_size );
if ( max_tex_size == 0 ) {
max_tex_size = 1024;
return *g_texturesmap;
}
+bool texturesToBeRealised = false;
void Textures_Realise(){
g_texturesmap->realise();
+ texturesToBeRealised = false;
+}
+
+void Textures_TriggerRealise(){
+ texturesToBeRealised = true;
+}
+
+bool Textures_TriggeredRealise(){
+ return texturesToBeRealised;
}
void Textures_Unrealise(){
}
void Textures_ModeChanged(){
+ // FIXME: not called by CamWindow thread
if ( g_texturesmap->realised() ) {
SetTexParameters( g_texture_mode );
for ( TexturesMap::iterator i = g_texturesmap->begin(); i != g_texturesmap->end(); ++i )
{
- glBindTexture( GL_TEXTURE_2D, ( *i ).value->texture_number );
+ glBindTexture( GL_TEXTURE_2D, ( *i ).value->texture_number[ VP_CAMWINDOW ] );
SetTexParameters( g_texture_mode );
}
if ( g_texture_globals.texture_components != texture_components ) {
Textures_Unrealise();
g_texture_globals.texture_components = texture_components;
- Textures_Realise();
+ Textures_TriggerRealise();
}
}
if (value != self) {
Textures_Unrealise();
self = value;
- Textures_Realise();
+ Textures_TriggerRealise();
}
}
};
#include "generic/callback.h"
void Textures_Realise();
+void Textures_TriggerRealise();
+bool Textures_TriggeredRealise();
void Textures_Unrealise();
void Textures_sharedContextDestroyed();
#include "defaults.h"
#include "ifilesystem.h"
+#include "itextures.h"
#include "iundo.h"
#include "igl.h"
#include "iarchive.h"
if ( textureBrowser.m_startupShaders == STARTUPSHADERS_COMMON ) {
TextureBrowser_ShowDirectory( textureBrowser, TextureBrowser_getCommonShadersDir() );
}
+ else
+ {
+ TextureBrowser_showAll();
+ }
}
break;
}
+ ViewportId v = VP_TEXWINDOW;
+
+ GLuint texture_number = RequestBindTextureNumber( v, q );
int nWidth = textureBrowser.getTextureWidth( q );
int nHeight = textureBrowser.getTextureHeight( q );
}
// Draw the texture
- glBindTexture( GL_TEXTURE_2D, q->texture_number );
+
+#ifdef DEBUG_TEXTURES
+ // It is known to produces an infinite loop on macOS with default layout:
+ // Log → Redraw → Log → Redraw…
+ globalOutputStream() << "Texture_Draw: " << v << ", " << q->name << ", " << texture_number << "\n";
+#endif
+
+ glBindTexture( GL_TEXTURE_2D, texture_number );
GlobalOpenGL_debugAssertNoErrors();
glColor3f( 1,1,1 );
glBegin( GL_QUADS );
//int totalHeight = abs(y) + last_height + TextureBrowser_fontHeight(textureBrowser) + 4;
}
-
// reset the current texture
glBindTexture( GL_TEXTURE_2D, 0 );
//qglFinish();
void TextureBrowser_RefreshShaders(){
TextureBrowser &textureBrowser = GlobalTextureBrowser();
ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Loading Shaders" );
- GlobalShaderSystem().refresh();
+ // GlobalShaderSystem is refreshed by camwindow
+ GlobalShaderSystem().triggerRefresh();
UpdateAllWindows();
auto selection = gtk_tree_view_get_selection(GlobalTextureBrowser().m_treeViewTree);
GtkTreeModel* model = NULL;
void TextureBrowser_ShowDirectory( TextureBrowser& textureBrowser, const char* name );
void TextureBrowser_ShowStartupShaders( TextureBrowser& textureBrowser );
+void TextureBrowser_showAll();
+
const char* TextureBrowser_GetSelectedShader( TextureBrowser& textureBrower );
void TextureBrowser_Construct();
#include "ibrush.h"
#include "iundo.h"
#include "iimage.h"
+#include "ishaders.h"
+#include "itextures.h"
#include "ifilesystem.h"
#include "os/path.h"
#include "image.h"
#include "brushmanip.h"
#include "selection.h"
#include "entity.h"
+#include "textures.h"
#include "camwindow.h"
#include "texwindow.h"
#include "mainframe.h"
#include "grid.h"
#include "windowobservers.h"
-void LoadTextureRGBA( qtexture_t* q, unsigned char* pPixels, int nWidth, int nHeight );
-
// d1223m
extern bool g_brush_always_caulk;
+const char *g_xywindow_background_filename = nullptr;
+
//!\todo Rewrite.
class ClipPoint
{
}
void XYWnd::Redraw() {
+ if ( Textures_TriggeredRealise() || GlobalShaderSystem().triggeredRefresh() ) {
+ if ( glwidget_make_current( m_gl_widget ) != FALSE ) {
+ // Draw something to not display garbage while camwindow
+ // is iterating textures.
+ if ( ScreenUpdates_Enabled() ) {
+ GlobalOpenGL_debugAssertNoErrors();
+ glViewport( 0, 0, m_nWidth, m_nHeight );
+ XY_Clear();
+ GlobalOpenGL_debugAssertNoErrors();
+ }
+ }
+
+ glwidget_swap_buffers( m_gl_widget );
+ return;
+ }
+
if ( glwidget_make_current( m_gl_widget ) != FALSE ) {
if ( Map_Valid( g_map ) && ScreenUpdates_Enabled() ) {
GlobalOpenGL_debugAssertNoErrors();
m_XORRectangle.set( rectangle_t() );
}
+
glwidget_swap_buffers( m_gl_widget );
}
}
}
}
-void XYWnd::XY_LoadBackgroundImage( const char *name ){
+void XYWnd::XY_LoadBackgroundImage(){
+ if (g_pParentWnd->ActiveXY()->m_backgroundActivated ){
+ return;
+ }
+
+ const char* name = g_xywindow_background_filename;
+
+ if ( name == nullptr )
+ {
+ return;
+ }
+
const char* relative = path_make_relative( name, GlobalFileSystem().findRoot( name ) );
if ( relative == name ) {
globalOutputStream() << "WARNING: could not extract the relative path, using full path instead\n";
fileNameWithoutExt[512 - 1] = '\0';
fileNameWithoutExt[strlen( fileNameWithoutExt ) - 4] = '\0';
- Image *image = QERApp_LoadImage( 0, fileNameWithoutExt );
+ Image* image = QERApp_LoadImage( 0, fileNameWithoutExt );
+
if ( !image ) {
globalOutputStream() << "Could not load texture " << fileNameWithoutExt << "\n";
+ g_xywindow_background_filename = nullptr;
return;
}
+
g_pParentWnd->ActiveXY()->m_tex = (qtexture_t*)malloc( sizeof( qtexture_t ) );
- LoadTextureRGBA( g_pParentWnd->ActiveXY()->XYWnd::m_tex, image->getRGBAPixels(), image->getWidth(), image->getHeight() );
+ g_pParentWnd->ActiveXY()->XYWnd::m_tex->name = fileNameWithoutExt;
+
+ // It can be loaded from outside the VFS, don't use RequestBindTextureNumber
+ LoadTextureRGBA( VP_XYWINDOW, g_pParentWnd->ActiveXY()->XYWnd::m_tex, image );
+
globalOutputStream() << "Loaded background texture " << relative << "\n";
g_pParentWnd->ActiveXY()->m_backgroundActivated = true;
void XYWnd::XY_DisableBackground( void ){
g_pParentWnd->ActiveXY()->m_backgroundActivated = false;
+ g_xywindow_background_filename = nullptr;
if ( g_pParentWnd->ActiveXY()->m_tex ) {
free( g_pParentWnd->ActiveXY()->m_tex );
}
return;
}
- const char *filename = main_window.file_dialog( TRUE, "Background Image", NULL, NULL );
-
g_pParentWnd->ActiveXY()->XY_DisableBackground();
- if ( filename ) {
- g_pParentWnd->ActiveXY()->XY_LoadBackgroundImage( filename );
+ g_xywindow_background_filename = main_window.file_dialog( TRUE, "Background Image", NULL, NULL );
+
+ if ( g_xywindow_background_filename != nullptr )
+ {
+ globalOutputStream() << "Selected background texture path: " << g_xywindow_background_filename << "\n";
}
+ // Request draw immediately, that will also request image loading.
+ // If something bad happens at image loading time, it will be known
+ // immediately.
+
// Draw the background image immediately (do not wait for user input).
g_pParentWnd->ActiveXY()->Redraw();
}
}
void XYWnd::XY_DrawBackground( void ){
+ if ( g_xywindow_background_filename == nullptr )
+ {
+ return;
+ }
+
+ if ( m_tex == nullptr )
+ {
+ XY_LoadBackgroundImage();
+ }
+
+ // TODO: activated?
+ if ( m_tex == nullptr )
+ {
+ return;
+ }
+
glPushAttrib( GL_ALL_ATTRIB_BITS );
glEnable( GL_TEXTURE_2D );
glPolygonMode( GL_FRONT, GL_FILL );
- glBindTexture( GL_TEXTURE_2D, m_tex->texture_number );
+ // It can be loaded from outside the VFS, don't use RequestBindTextureNumber
+ glBindTexture( GL_TEXTURE_2D, GetBindTextureNumber( VP_XYWINDOW, m_tex ) );
glBegin( GL_QUADS );
glColor4f( 1.0, 1.0, 1.0, m_alpha );
}
void render( const Matrix4& modelview, const Matrix4& projection ){
- GlobalShaderCache().render( m_globalstate, modelview, projection );
+ // GlobalShaderSystem is refreshed by camwindow
+ if ( GlobalShaderSystem().refreshed() )
+ {
+ GlobalShaderCache().render( VP_XYWINDOW, m_globalstate, modelview, projection );
+ }
}
private:
std::vector<state_type> m_state_stack;
//#define DBG_SCENEDUMP
-void XYWnd::XY_Draw(){
- //
- // clear
- //
- glViewport( 0, 0, m_nWidth, m_nHeight );
+void XYWnd::XY_Clear(){
glClearColor( g_xywindow_globals.color_gridback[0],
g_xywindow_globals.color_gridback[1],
g_xywindow_globals.color_gridback[2],0 );
glClear( GL_COLOR_BUFFER_BIT );
+}
+void XYWnd::XY_Draw(){
+ //
+ // clear
+ //
+ glViewport( 0, 0, m_nWidth, m_nHeight );
+ XY_Clear();
//
// set up viewpoint
//
glDisable( GL_COLOR_MATERIAL );
glDisable( GL_DEPTH_TEST );
- if ( m_backgroundActivated ) {
- XY_DrawBackground();
- }
+ XY_DrawBackground();
XY_DrawGrid();
if ( g_xywindow_globals_private.show_blocks ) {
DeferredDraw m_deferredDraw;
DeferredMotion m_deferred_motion;
+
+void XY_Clear();
public:
ui::Window m_parent;
XYWnd();
void XY_DrawAxis();
void XY_DrawGrid();
void XY_DrawBackground();
-void XY_LoadBackgroundImage( const char *name );
+void XY_LoadBackgroundImage();
void XY_DisableBackground();
void XY_MouseUp( int x, int y, unsigned int buttons );