Fix crash on launch on OS X. Also describe installing deps with homebrew.
Hi,
I applied this patch to fix the crash after the initial game selection dialog: https://github.com/TTimo/GtkRadiant/issues/289
Also made a small update to COMPILING describing how you can build using dependencies installed with Homebrew.
See merge request !1
.settings
games
install
+games
tools/quake3/q3map2/vis.o \
tools/quake3/q3map2/writebsp.o \
libddslib.$(A) \
+ libetclib.$(A) \
libfilematch.$(A) \
libl_net.$(A) \
libmathlib.$(A) \
libddslib.$(A): \
libs/ddslib/ddslib.o \
+libetclib.$(A): CPPFLAGS_EXTRA := -Ilibs
+libetclib.$(A): \
+ libs/etclib.o \
+
$(INSTALLDIR)/q3data.$(EXE): LIBS_EXTRA := $(LIBS_XML) $(LIBS_GLIB) $(LIBS_ZLIB)
$(INSTALLDIR)/q3data.$(EXE): CPPFLAGS_EXTRA := $(CPPFLAGS_XML) $(CPPFLAGS_GLIB) $(CPPFLAGS_ZLIB) -Itools/quake3/common -Ilibs -Iinclude
$(INSTALLDIR)/q3data.$(EXE): \
tools/quake3/q3data/stripper.o \
tools/quake3/q3data/video.o \
libfilematch.$(A) \
+ libetclib.$(A) \
libl_net.$(A) \
libmathlib.$(A) \
$(if $(findstring $(OS),Win32),icons/q3data.o,) \
plugins/image/dds.o \
plugins/image/image.o \
plugins/image/jpeg.o \
+ plugins/image/ktx.o \
plugins/image/pcx.o \
plugins/image/tga.o \
libddslib.$(A) \
+ libetclib.$(A) \
$(INSTALLDIR)/modules/imageq2.$(DLL): CPPFLAGS_EXTRA := -Ilibs -Iinclude
$(INSTALLDIR)/modules/imageq2.$(DLL): \
struct toolbar_button_info_s toolbar_buttons[NUM_TOOLBAR_BUTTONS] =
{
{
- "bkgrnd2d_xy_toggle.bmp",
+ "bkgrnd2d_xy_toggle.png",
"xy background",
"Toggle xy background image",
DoBkgrndToggleXY,
IToolbarButton::eToggleButton
},
{
- "bkgrnd2d_xz_toggle.bmp",
+ "bkgrnd2d_xz_toggle.png",
"xz background",
"Toggle xz background image",
DoBkgrndToggleXZ,
IToolbarButton::eToggleButton
},
{
- "bkgrnd2d_yz_toggle.bmp",
+ "bkgrnd2d_yz_toggle.png",
"yz background",
"Toggle yz background image",
DoBkgrndToggleYZ,
IToolbarButton::eToggleButton
},
{
- "bkgrnd2d_conf.bmp",
+ "bkgrnd2d_conf.png",
"Configure",
"Configure background images",
ShowBackgroundDialog,
--- /dev/null
+bobtoolz bitmaps are in setup/data/tools/plugins/bitmaps
public:
virtual const char* getImage() const {
switch ( mIndex ) {
- case 0: return "bobtoolz_cleanup.bmp";
- case 1: return "bobtoolz_poly.bmp";
- case 2: return "bobtoolz_caulk.bmp";
+ case 0: return "bobtoolz_cleanup.png";
+ case 1: return "bobtoolz_poly.png";
+ case 2: return "bobtoolz_caulk.png";
case 3: return "";
- case 4: return "bobtoolz_treeplanter.bmp";
- case 5: return "bobtoolz_trainpathplot.bmp";
- case 6: return "bobtoolz_dropent.bmp";
+ case 4: return "bobtoolz_treeplanter.png";
+ case 5: return "bobtoolz_trainpathplot.png";
+ case 6: return "bobtoolz_dropent.png";
case 7: return "";
- case 8: return "bobtoolz_merge.bmp";
- case 9: return "bobtoolz_split.bmp";
- case 10: return "bobtoolz_splitrow.bmp";
- case 11: return "bobtoolz_splitcol.bmp";
+ case 8: return "bobtoolz_merge.png";
+ case 9: return "bobtoolz_split.png";
+ case 10: return "bobtoolz_splitrow.png";
+ case 11: return "bobtoolz_splitcol.png";
case 12: return "";
- case 13: return "bobtoolz_turnedge.bmp";
+ case 13: return "bobtoolz_turnedge.png";
}
return NULL;
}
{
public:
virtual const char* getImage() const {
- return "camera_insp.bmp";
+ return "camera_insp.jpg";
}
virtual const char* getText() const {
return "Inspector";
--- /dev/null
+ufoaiplug bitmaps are in setup/data/tools/plugins/bitmaps
virtual const char* getImage() const {
switch ( mIndex )
{
- case 0: return "ufoai_level1.bmp";
- case 1: return "ufoai_level2.bmp";
- case 2: return "ufoai_level3.bmp";
- case 3: return "ufoai_level4.bmp";
- case 4: return "ufoai_level5.bmp";
- case 5: return "ufoai_level6.bmp";
- case 6: return "ufoai_level7.bmp";
- case 7: return "ufoai_level8.bmp";
- case 8: return "ufoai_stepon.bmp";
- case 9: return "ufoai_actorclip.bmp";
- case 10: return "ufoai_weaponclip.bmp";
- case 11: return "ufoai_nodraw.bmp";
+ case 0: return "ufoai_level1.png";
+ case 1: return "ufoai_level2.png";
+ case 2: return "ufoai_level3.png";
+ case 3: return "ufoai_level4.png";
+ case 4: return "ufoai_level5.png";
+ case 5: return "ufoai_level6.png";
+ case 6: return "ufoai_level7.png";
+ case 7: return "ufoai_level8.png";
+ case 8: return "ufoai_stepon.png";
+ case 9: return "ufoai_actorclip.png";
+ case 10: return "ufoai_weaponclip.png";
+ case 11: return "ufoai_nodraw.png";
}
return NULL;
}
pack OsirionPack GPL zip1 http://ingar.satgnu.net/files/gtkradiant/gamepacks/OsirionPack.zip
pack Q3Pack proprietary svn svn://svn.icculus.org/gtkradiant-gamepacks/Q3Pack/trunk/ -r29
pack Quake2Pack proprietary zip1 http://ingar.satgnu.net/files/gtkradiant/gamepacks/Quake2Pack.zip
-pack Quake2WorldPack GPL svn svn://svn.icculus.org/gtkradiant-gamepacks/Q2WPack/branches/1.5/
pack QuakePack GPL zip1 http://ingar.satgnu.net/files/gtkradiant/gamepacks/Quake1Pack.zip
+pack QuetooPack GPL svn svn://svn.icculus.org/gtkradiant-gamepacks/QuetooPack/branches/1.5/
pack TremulousPack proprietary zip1 http://ingar.satgnu.net/files/gtkradiant/gamepacks/TremulousPack.zip
pack UFOAIPack proprietary svn svn://svn.icculus.org/gtkradiant-gamepacks/UFOAIPack/branches/1.5/
#pack WarsowPack GPL svn https://svn.bountysource.com/wswpack/trunk/netradiant/games/WarsowPack/
-pack WarsowPack GPL zip1 http://ingar.satgnu.net/files/gtkradiant/gamepacks/WarsowPack.zip
+#pack WarsowPack GPL zip1 http://ingar.satgnu.net/files/gtkradiant/gamepacks/WarsowPack.zip
+pack WarsowPack GPL git https://github.com/Warsow/NetRadiantPack.git
pack XonoticPack GPL git http://git.xonotic.org/xonotic/netradiant-xonoticpack.git
return value;
}
+template<typename InputStreamType>
+inline int16_t istream_read_int16_be( InputStreamType& istream ){
+ int16_t value;
+ istream_read_big_endian( istream, value );
+ return value;
+}
+
template<typename InputStreamType>
inline uint16_t istream_read_uint16_le( InputStreamType& istream ){
uint16_t value;
return value;
}
+template<typename InputStreamType>
+inline uint16_t istream_read_uint16_be( InputStreamType& istream ){
+ uint16_t value;
+ istream_read_big_endian( istream, value );
+ return value;
+}
+
template<typename InputStreamType>
inline int32_t istream_read_int32_le( InputStreamType& istream ){
int32_t value;
return value;
}
+template<typename InputStreamType>
+inline int32_t istream_read_int32_be( InputStreamType& istream ){
+ int32_t value;
+ istream_read_big_endian( istream, value );
+ return value;
+}
+
template<typename InputStreamType>
inline uint32_t istream_read_uint32_le( InputStreamType& istream ){
uint32_t value;
return value;
}
+template<typename InputStreamType>
+inline uint32_t istream_read_uint32_be( InputStreamType& istream ){
+ uint32_t value;
+ istream_read_big_endian( istream, value );
+ return value;
+}
+
template<typename InputStreamType>
inline float istream_read_float32_le( InputStreamType& istream ){
float value;
return value;
}
+template<typename InputStreamType>
+inline float istream_read_float32_be( InputStreamType& istream ){
+ float value;
+ istream_read_big_endian( istream, value );
+ return value;
+}
+
template<typename InputStreamType>
inline typename InputStreamType::byte_type istream_read_byte( InputStreamType& istream ){
typename InputStreamType::byte_type b;
--- /dev/null
+// Copyright 2009 Google Inc.
+//
+// Based on the code from Android ETC1Util.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "etclib.h"
+
+static void ETC_DecodeETC1SubBlock( byte *out, qboolean outRGBA, int r, int g, int b, int tableIndex, unsigned int low, qboolean second, qboolean flipped ){
+ int baseX = 0, baseY = 0;
+ const int modifierTable[] = {
+ 2, 8, -2, -8,
+ 5, 17, -5, -17,
+ 9, 29, -9, -29,
+ 13, 42, -13, -42,
+ 18, 60, -18, -60,
+ 24, 80, -24, -80,
+ 33, 106, -33, -106,
+ 47, 183, -47, -183
+ };
+ const int *table = modifierTable + tableIndex * 4;
+ int i;
+
+ if ( second ) {
+ if ( flipped ) {
+ baseY = 2;
+ }
+ else {
+ baseX = 2;
+ }
+ }
+
+ for ( i = 0; i < 8; i++ )
+ {
+ int x, y, k, delta;
+ int qr, qg, qb;
+ byte *q;
+
+ if ( flipped ) {
+ x = baseX + ( i >> 1 );
+ y = baseY + ( i & 1 );
+ }
+ else {
+ x = baseX + ( i >> 2 );
+ y = baseY + ( i & 3 );
+ }
+ k = y + ( x * 4 );
+ delta = table[( ( low >> k ) & 1 ) | ( ( low >> ( k + 15 ) ) & 2 )];
+
+ qr = r + delta;
+ qg = g + delta;
+ qb = b + delta;
+ if ( outRGBA ) {
+ q = out + 4 * ( x + 4 * y );
+ }
+ else {
+ q = out + 3 * ( x + 4 * y );
+ }
+ *( q++ ) = ( ( qr > 0 ) ? ( ( qr < 255 ) ? qr : 255 ) : 0 );
+ *( q++ ) = ( ( qg > 0 ) ? ( ( qg < 255 ) ? qg : 255 ) : 0 );
+ *( q++ ) = ( ( qb > 0 ) ? ( ( qb < 255 ) ? qb : 255 ) : 0 );
+ if ( outRGBA ) {
+ *( q++ ) = 255;
+ }
+ }
+}
+
+void ETC_DecodeETC1Block( const byte* in, byte* out, qboolean outRGBA ){
+ unsigned int high = ( in[0] << 24 ) | ( in[1] << 16 ) | ( in[2] << 8 ) | in[3];
+ unsigned int low = ( in[4] << 24 ) | ( in[5] << 16 ) | ( in[6] << 8 ) | in[7];
+ int r1, r2, g1, g2, b1, b2;
+ qboolean flipped = ( ( high & 1 ) != 0 );
+
+ if ( high & 2 ) {
+ int rBase, gBase, bBase;
+ const int lookup[] = { 0, 1, 2, 3, -4, -3, -2, -1 };
+
+ rBase = ( high >> 27 ) & 31;
+ r1 = ( rBase << 3 ) | ( rBase >> 2 );
+ rBase = ( rBase + ( lookup[( high >> 24 ) & 7] ) ) & 31;
+ r2 = ( rBase << 3 ) | ( rBase >> 2 );
+
+ gBase = ( high >> 19 ) & 31;
+ g1 = ( gBase << 3 ) | ( gBase >> 2 );
+ gBase = ( gBase + ( lookup[( high >> 16 ) & 7] ) ) & 31;
+ g2 = ( gBase << 3 ) | ( gBase >> 2 );
+
+ bBase = ( high >> 11 ) & 31;
+ b1 = ( bBase << 3 ) | ( bBase >> 2 );
+ bBase = ( bBase + ( lookup[( high >> 8 ) & 7] ) ) & 31;
+ b2 = ( bBase << 3 ) | ( bBase >> 2 );
+ }
+ else {
+ r1 = ( ( high >> 24 ) & 0xf0 ) | ( ( high >> 28 ) & 0xf );
+ r2 = ( ( high >> 20 ) & 0xf0 ) | ( ( high >> 24 ) & 0xf );
+ g1 = ( ( high >> 16 ) & 0xf0 ) | ( ( high >> 20 ) & 0xf );
+ g2 = ( ( high >> 12 ) & 0xf0 ) | ( ( high >> 16 ) & 0xf );
+ b1 = ( ( high >> 8 ) & 0xf0 ) | ( ( high >> 12 ) & 0xf );
+ b2 = ( ( high >> 4 ) & 0xf0 ) | ( ( high >> 8 ) & 0xf );
+ }
+
+ ETC_DecodeETC1SubBlock( out, outRGBA, r1, g1, b1, ( high >> 5 ) & 7, low, qfalse, flipped );
+ ETC_DecodeETC1SubBlock( out, outRGBA, r2, g2, b2, ( high >> 2 ) & 7, low, qtrue, flipped );
+}
--- /dev/null
+// Copyright 2009 Google Inc.
+//
+// Based on the code from Android ETC1Util.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef INCLUDED_ETCLIB_H
+#define INCLUDED_ETCLIB_H
+
+#include "bytebool.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+void ETC_DecodeETC1Block( const byte* in, byte* out, qboolean outRGBA );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
}
else
{
- GdkPixbuf* rgba = gdk_pixbuf_add_alpha( rgb, TRUE, 255, 0, 255 );
+ GdkPixbuf* rgba = gdk_pixbuf_add_alpha( rgb, FALSE, 255, 0, 255 );
gdk_pixbuf_unref( rgb );
return rgba;
}
};
static inline bool shader_is_diffuse( const char *shader ){
- return !string_equal_suffix( shader, "_bump" )
- && !string_equal_suffix( shader, "_glow" )
- && !string_equal_suffix( shader, "_h" )
- && !string_equal_suffix( shader, "_local" )
- && !string_equal_suffix( shader, "_luma" )
- && !string_equal_suffix( shader, "_nm" )
- && !string_equal_suffix( shader, "_s" );
+ return
+ /* Quetoo */
+ !string_equal_suffix( shader, "_h" )
+ && !string_equal_suffix( shader, "_local" )
+ && !string_equal_suffix( shader, "_nm" )
+ && !string_equal_suffix( shader, "_s" )
+ /* DarkPlaces */
+ && !string_equal_suffix( shader, "_bump" )
+ && !string_equal_suffix( shader, "_glow" )
+ && !string_equal_suffix( shader, "_gloss" )
+ && !string_equal_suffix( shader, "_luma" )
+ && !string_equal_suffix( shader, "_norm" )
+ && !string_equal_suffix( shader, "_pants" )
+ && !string_equal_suffix( shader, "_shirt" )
+ && !string_equal_suffix( shader, "_reflect" )
+ ;
}
inline bool shader_valid( const char* shader ){
#include "bmp.h"
#include "pcx.h"
#include "dds.h"
+#include "ktx.h"
#include "modulesystem/singletonmodule.h"
ImageDDSModule g_ImageDDSModule;
+class ImageKTXAPI
+{
+_QERPlugImageTable m_imagektx;
+public:
+typedef _QERPlugImageTable Type;
+STRING_CONSTANT( Name, "ktx" );
+
+ImageKTXAPI(){
+ m_imagektx.loadImage = LoadKTX;
+}
+_QERPlugImageTable* getTable(){
+ return &m_imagektx;
+}
+};
+
+typedef SingletonModule<ImageKTXAPI, ImageDependencies> ImageKTXModule;
+
+ImageKTXModule g_ImageKTXModule;
+
+
extern "C" void RADIANT_DLLEXPORT Radiant_RegisterModules( ModuleServer& server ){
initialiseModule( server );
g_ImageBMPModule.selfRegister();
g_ImagePCXModule.selfRegister();
g_ImageDDSModule.selfRegister();
+ g_ImageKTXModule.selfRegister();
}
--- /dev/null
+/*
+ Copyright (C) 2015, SiPlus, Chasseur de bots.
+ All Rights Reserved.
+
+ This file is part of GtkRadiant.
+
+ GtkRadiant is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ GtkRadiant is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GtkRadiant; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ktx.h"
+
+#include <string.h>
+
+#include "bytestreamutils.h"
+#include "etclib.h"
+#include "ifilesystem.h"
+#include "imagelib.h"
+
+
+#define KTX_TYPE_UNSIGNED_BYTE 0x1401
+#define KTX_TYPE_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define KTX_TYPE_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define KTX_TYPE_UNSIGNED_SHORT_5_6_5 0x8363
+
+#define KTX_FORMAT_ALPHA 0x1906
+#define KTX_FORMAT_RGB 0x1907
+#define KTX_FORMAT_RGBA 0x1908
+#define KTX_FORMAT_LUMINANCE 0x1909
+#define KTX_FORMAT_LUMINANCE_ALPHA 0x190A
+#define KTX_FORMAT_BGR 0x80E0
+#define KTX_FORMAT_BGRA 0x80E1
+
+#define KTX_FORMAT_ETC1_RGB8 0x8D64
+
+class KTX_Decoder
+{
+public:
+ virtual void Decode( PointerInputStream& istream, byte* out ) = 0;
+ virtual unsigned int GetPixelSize() = 0;
+};
+
+class KTX_Decoder_A8 : public KTX_Decoder
+{
+public:
+ virtual void Decode( PointerInputStream& istream, byte* out ){
+ out[0] = out[1] = out[2] = 0;
+ out[3] = istream_read_byte( istream );
+ }
+ virtual unsigned int GetPixelSize(){
+ return 1;
+ }
+};
+
+class KTX_Decoder_RGB8 : public KTX_Decoder
+{
+public:
+ virtual void Decode( PointerInputStream& istream, byte* out ){
+ istream.read( out, 3 );
+ out[3] = 255;
+ }
+ virtual unsigned int GetPixelSize(){
+ return 3;
+ }
+};
+
+class KTX_Decoder_RGBA8 : public KTX_Decoder
+{
+public:
+ virtual void Decode( PointerInputStream& istream, byte* out ){
+ istream.read( out, 4 );
+ }
+ virtual unsigned int GetPixelSize(){
+ return 4;
+ }
+};
+
+class KTX_Decoder_L8 : public KTX_Decoder
+{
+public:
+ virtual void Decode( PointerInputStream& istream, byte* out ){
+ byte l = istream_read_byte( istream );
+ out[0] = out[1] = out[2] = l;
+ out[3] = 255;
+ }
+ virtual unsigned int GetPixelSize(){
+ return 1;
+ }
+};
+
+class KTX_Decoder_LA8 : public KTX_Decoder
+{
+public:
+ virtual void Decode( PointerInputStream& istream, byte* out ){
+ byte la[2];
+ istream.read( la, 2 );
+ out[0] = out[1] = out[2] = la[0];
+ out[3] = la[1];
+ }
+ virtual unsigned int GetPixelSize(){
+ return 2;
+ }
+};
+
+class KTX_Decoder_BGR8 : public KTX_Decoder
+{
+public:
+ virtual void Decode( PointerInputStream& istream, byte* out ){
+ byte bgr[3];
+ istream.read( bgr, 3 );
+ out[0] = bgr[2];
+ out[1] = bgr[1];
+ out[2] = bgr[0];
+ out[3] = 255;
+ }
+ virtual unsigned int GetPixelSize(){
+ return 3;
+ }
+};
+
+class KTX_Decoder_BGRA8 : public KTX_Decoder
+{
+public:
+ virtual void Decode( PointerInputStream& istream, byte* out ){
+ byte bgra[4];
+ istream.read( bgra, 4 );
+ out[0] = bgra[2];
+ out[1] = bgra[1];
+ out[2] = bgra[0];
+ out[3] = bgra[3];
+ }
+ virtual unsigned int GetPixelSize(){
+ return 4;
+ }
+};
+
+class KTX_Decoder_RGBA4 : public KTX_Decoder
+{
+protected:
+ bool m_bigEndian;
+public:
+ KTX_Decoder_RGBA4( bool bigEndian ) : m_bigEndian( bigEndian ){}
+ virtual void Decode( PointerInputStream& istream, byte* out ){
+ uint16_t rgba;
+ if ( m_bigEndian ) {
+ rgba = istream_read_uint16_be( istream );
+ }
+ else {
+ rgba = istream_read_uint16_le( istream );
+ }
+ int r = ( rgba >> 12 ) & 0xf;
+ int g = ( rgba >> 8 ) & 0xf;
+ int b = ( rgba >> 4 ) & 0xf;
+ int a = rgba & 0xf;
+ out[0] = ( r << 4 ) | r;
+ out[1] = ( g << 4 ) | g;
+ out[2] = ( b << 4 ) | b;
+ out[3] = ( a << 4 ) | a;
+ }
+ virtual unsigned int GetPixelSize(){
+ return 2;
+ }
+};
+
+class KTX_Decoder_RGBA5 : public KTX_Decoder
+{
+protected:
+ bool m_bigEndian;
+public:
+ KTX_Decoder_RGBA5( bool bigEndian ) : m_bigEndian( bigEndian ){}
+ virtual void Decode( PointerInputStream& istream, byte* out ){
+ uint16_t rgba;
+ if ( m_bigEndian ) {
+ rgba = istream_read_uint16_be( istream );
+ }
+ else {
+ rgba = istream_read_uint16_le( istream );
+ }
+ int r = ( rgba >> 11 ) & 0x1f;
+ int g = ( rgba >> 6 ) & 0x1f;
+ int b = ( rgba >> 1 ) & 0x1f;
+ out[0] = ( r << 3 ) | ( r >> 2 );
+ out[1] = ( g << 3 ) | ( g >> 2 );
+ out[2] = ( b << 3 ) | ( b >> 2 );
+ out[3] = ( rgba & 1 ) * 255;
+ }
+ virtual unsigned int GetPixelSize(){
+ return 2;
+ }
+};
+
+class KTX_Decoder_RGB5 : public KTX_Decoder
+{
+protected:
+ bool m_bigEndian;
+public:
+ KTX_Decoder_RGB5( bool bigEndian ) : m_bigEndian( bigEndian ){}
+ virtual void Decode( PointerInputStream& istream, byte* out ){
+ uint16_t rgb;
+ if ( m_bigEndian ) {
+ rgb = istream_read_uint16_be( istream );
+ }
+ else {
+ rgb = istream_read_uint16_le( istream );
+ }
+ int r = ( rgb >> 11 ) & 0x1f;
+ int g = ( rgb >> 5 ) & 0x3f;
+ int b = rgb & 0x1f;
+ out[0] = ( r << 3 ) | ( r >> 2 );
+ out[1] = ( g << 2 ) | ( g >> 4 );
+ out[2] = ( b << 3 ) | ( b >> 2 );
+ out[3] = 255;
+ }
+ virtual unsigned int GetPixelSize(){
+ return 2;
+ }
+};
+
+static void KTX_DecodeETC1( PointerInputStream& istream, Image& image ){
+ unsigned int width = image.getWidth(), height = image.getHeight();
+ unsigned int stride = width * 4;
+ byte* pixbuf = image.getRGBAPixels();
+ byte etc[8], rgba[64];
+
+ for ( unsigned int y = 0; y < height; y += 4, pixbuf += stride * 4 )
+ {
+ unsigned int blockrows = height - y;
+ if ( blockrows > 4 ) {
+ blockrows = 4;
+ }
+
+ byte* p = pixbuf;
+ for ( unsigned int x = 0; x < width; x += 4, p += 16 )
+ {
+ istream.read( etc, 8 );
+ ETC_DecodeETC1Block( etc, rgba, qtrue );
+
+ unsigned int blockrowsize = width - x;
+ if ( blockrowsize > 4 ) {
+ blockrowsize = 4;
+ }
+ blockrowsize *= 4;
+ for ( unsigned int blockrow = 0; blockrow < blockrows; blockrow++ )
+ {
+ memcpy( p + blockrow * stride, rgba + blockrow * 16, blockrowsize );
+ }
+ }
+ }
+}
+
+Image* LoadKTXBuff( PointerInputStream& istream ){
+ byte identifier[12];
+ istream.read( identifier, 12 );
+ if ( memcmp( identifier, "\xABKTX 11\xBB\r\n\x1A\n", 12 ) ) {
+ globalErrorStream() << "LoadKTX: Image has the wrong identifier\n";
+ return 0;
+ }
+
+ bool bigEndian = ( istream_read_uint32_le( istream ) == 0x01020304 );
+
+ unsigned int type;
+ if ( bigEndian ) {
+ type = istream_read_uint32_be( istream );
+ }
+ else {
+ type = istream_read_uint32_le( istream );
+ }
+
+ // For compressed textures, the format is in glInternalFormat.
+ // For uncompressed textures, it's in glBaseInternalFormat.
+ istream.seek( ( type ? 3 : 2 ) * sizeof( uint32_t ) );
+ unsigned int format;
+ if ( bigEndian ) {
+ format = istream_read_uint32_be( istream );
+ }
+ else {
+ format = istream_read_uint32_le( istream );
+ }
+ if ( !type ) {
+ istream.seek( sizeof( uint32_t ) );
+ }
+
+ unsigned int width, height;
+ if ( bigEndian ) {
+ width = istream_read_uint32_be( istream );
+ height = istream_read_uint32_be( istream );
+ }
+ else {
+ width = istream_read_uint32_le( istream );
+ height = istream_read_uint32_le( istream );
+ }
+ if ( !width ) {
+ globalErrorStream() << "LoadKTX: Image has zero width\n";
+ return 0;
+ }
+ if ( !height ) {
+ height = 1;
+ }
+
+ // Skip the key/values and load the first 2D image in the texture.
+ // Since KTXorientation is only a hint and has no effect on the texture data and coordinates, it must be ignored.
+ istream.seek( 4 * sizeof( uint32_t ) );
+ unsigned int bytesOfKeyValueData;
+ if ( bigEndian ) {
+ bytesOfKeyValueData = istream_read_uint32_be( istream );
+ }
+ else {
+ bytesOfKeyValueData = istream_read_uint32_le( istream );
+ }
+ istream.seek( bytesOfKeyValueData + sizeof( uint32_t ) );
+
+ RGBAImage* image = new RGBAImage( width, height );
+
+ if ( type ) {
+ KTX_Decoder* decoder = NULL;
+ switch ( type )
+ {
+ case KTX_TYPE_UNSIGNED_BYTE:
+ switch ( format )
+ {
+ case KTX_FORMAT_ALPHA:
+ decoder = new KTX_Decoder_A8();
+ break;
+ case KTX_FORMAT_RGB:
+ decoder = new KTX_Decoder_RGB8();
+ break;
+ case KTX_FORMAT_RGBA:
+ decoder = new KTX_Decoder_RGBA8();
+ break;
+ case KTX_FORMAT_LUMINANCE:
+ decoder = new KTX_Decoder_L8();
+ break;
+ case KTX_FORMAT_LUMINANCE_ALPHA:
+ decoder = new KTX_Decoder_LA8();
+ break;
+ case KTX_FORMAT_BGR:
+ decoder = new KTX_Decoder_BGR8();
+ break;
+ case KTX_FORMAT_BGRA:
+ decoder = new KTX_Decoder_BGRA8();
+ break;
+ }
+ break;
+ case KTX_TYPE_UNSIGNED_SHORT_4_4_4_4:
+ if ( format == KTX_FORMAT_RGBA ) {
+ decoder = new KTX_Decoder_RGBA4( bigEndian );
+ }
+ break;
+ case KTX_TYPE_UNSIGNED_SHORT_5_5_5_1:
+ if ( format == KTX_FORMAT_RGBA ) {
+ decoder = new KTX_Decoder_RGBA5( bigEndian );
+ }
+ break;
+ case KTX_TYPE_UNSIGNED_SHORT_5_6_5:
+ if ( format == KTX_FORMAT_RGB ) {
+ decoder = new KTX_Decoder_RGB5( bigEndian );
+ }
+ break;
+ }
+
+ if ( !decoder ) {
+ globalErrorStream() << "LoadKTX: Image has an unsupported pixel type " << type << " or format " << format << "\n";
+ image->release();
+ return 0;
+ }
+
+ unsigned int inRowLength = width * decoder->GetPixelSize();
+ unsigned int inPadding = ( ( inRowLength + 3 ) & ~3 ) - inRowLength;
+ byte* out = image->getRGBAPixels();
+ for ( unsigned int y = 0; y < height; y++ )
+ {
+ for ( unsigned int x = 0; x < width; x++, out += 4 )
+ {
+ decoder->Decode( istream, out );
+ }
+
+ if ( inPadding ) {
+ istream.seek( inPadding );
+ }
+ }
+
+ delete decoder;
+ }
+ else {
+ switch ( format )
+ {
+ case KTX_FORMAT_ETC1_RGB8:
+ KTX_DecodeETC1( istream, *image );
+ break;
+ default:
+ globalErrorStream() << "LoadKTX: Image has an unsupported compressed format " << format << "\n";
+ image->release();
+ return 0;
+ }
+ }
+
+ return image;
+}
+
+Image* LoadKTX( ArchiveFile& file ){
+ ScopedArchiveBuffer buffer( file );
+ PointerInputStream istream( buffer.buffer );
+ return LoadKTXBuff( istream );
+}
--- /dev/null
+/*
+ Copyright (C) 2015, SiPlus, Chasseur de bots.
+ All Rights Reserved.
+
+ This file is part of GtkRadiant.
+
+ GtkRadiant is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ GtkRadiant is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GtkRadiant; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if !defined( INCLUDED_KTX_H )
+#define INCLUDED_KTX_H
+
+class Image;
+class ArchiveFile;
+
+Image* LoadKTX( ArchiveFile& file );
+
+#endif
}
+class TargaDecodeGrayPixelRLE
+{
+TargaPacketSize m_packetSize;
+RGBAPixel m_pixel;
+TargaPacket m_packet;
+public:
+TargaDecodeGrayPixelRLE() : m_packetSize( 0 ){
+}
+void operator()( PointerInputStream& istream, RGBAPixel& pixel ){
+ if ( m_packetSize == 0 ) {
+ targa_packet_read_istream( m_packet, istream );
+ m_packetSize = targa_packet_size( m_packet );
+
+ if ( targa_packet_is_rle( m_packet ) ) {
+ istream_read_gray( istream, m_pixel );
+ }
+ }
+
+ if ( targa_packet_is_rle( m_packet ) ) {
+ pixel = m_pixel;
+ }
+ else
+ {
+ istream_read_gray( istream, pixel );
+ }
+
+ --m_packetSize;
+}
+};
+
+template<typename Flip>
+void targa_decode_rle_grayscale( PointerInputStream& istream, RGBAImage& image, const Flip& flip ){
+ TargaDecodeGrayPixelRLE decode;
+ image_decode( istream, decode, image, flip );
+}
+
class TargaDecodeRGBPixelRLE
{
TargaPacketSize m_packetSize;
return 0;
}
}
- else if ( targa_header.image_type == 10 ) {
+ else if ( targa_header.image_type == 10 || targa_header.image_type == 11 ) {
switch ( targa_header.pixel_size )
{
+ case 8:
+ targa_decode_rle_grayscale( istream, *image, flip );
+ break;
case 24:
targa_decode_rle_rgb( istream, *image, flip );
break;
targa_header_read_istream( targa_header, istream );
- if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) {
+ if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 && targa_header.image_type != 11 ) {
globalErrorStream() << "LoadTGA: TGA type " << targa_header.image_type << " not supported\n";
- globalErrorStream() << "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n";
+ globalErrorStream() << "LoadTGA: Only type 2 (RGB), 3 (gray), 10 (RGB), and 11 (gray) TGA images supported\n";
return 0;
}
return 0;
}
- if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 )
- && targa_header.image_type != 3 ) {
- globalErrorStream() << "LoadTGA: Only 32 or 24 bit images supported\n";
+ if ( ( ( targa_header.image_type == 2 || targa_header.image_type == 10 ) && targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) ||
+ ( ( targa_header.image_type == 3 || targa_header.image_type == 11 ) && targa_header.pixel_size != 8 ) ) {
+ globalErrorStream() << "LoadTGA: Only 32, 24 or 8 bit images supported\n";
return 0;
}
ImageModuleRef m_bitmapModule;
public:
ShadersDependencies() :
- m_bitmapModule( "bmp" ){
+ m_bitmapModule( "png" ){
}
ImageModuleRef& getBitmapModule(){
return m_bitmapModule;
Image* loadSpecial( void* environment, const char* name ){
if ( *name == '_' ) { // special image
StringOutputStream bitmapName( 256 );
- bitmapName << GlobalRadiant().getAppPath() << "bitmaps/" << name + 1 << ".bmp";
+ bitmapName << GlobalRadiant().getAppPath() << "bitmaps/" << name + 1 << ".png";
Image* image = loadBitmap( environment, bitmapName.c_str() );
if ( image != 0 ) {
return image;
{
StringOutputStream name( 256 );
- name << GlobalRadiant().getAppPath() << "bitmaps/" << ( IsDefault() ? "notex.bmp" : "shadernotex.bmp" );
+ name << GlobalRadiant().getAppPath() << "bitmaps/" << ( IsDefault() ? "notex.png" : "shadernotex.png" );
m_pTexture = GlobalTexturesCache().capture( LoadImageCallback( 0, loadBitmap ), name.c_str() );
}
}
void CamWnd_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_toggle_button( toolbar, "Cubic clip the camera view (\\)", "view_cubicclipping.bmp", "ToggleCubicClip" );
+ toolbar_append_toggle_button( toolbar, "Cubic clip the camera view (\\)", "view_cubicclipping.png", "ToggleCubicClip" );
}
void CamWnd_registerShortcuts(){
else
{
CopiedString tmp( key );
- ASSERT_MESSAGE( !string_equal_n( key, "editor_", 7 ), "unsupported editor key: " << makeQuoted( key ) );
+ if ( string_equal_n( key, "editor_", 7 ) ) {
+ globalErrorStream() << "unsupported editor key " << makeQuoted( key ) ;
+ }
EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, key ).second;
attribute.m_type = "string";
const char* value;
#endif
{ return; }
- // try to detect Q2World installs
- if ( gamedetect_check_game( "q2w.game", "default/quake2world.version", NULL, buf, p - buf ) ) {
+ // try to detect Quetoo installs
+ if ( gamedetect_check_game( "quetoo.game", "default/icons/quetoo.png", NULL, buf, p - buf ) ) {
return;
}
GtkFrame* frame = create_dialog_frame( 0, GTK_SHADOW_IN );
gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( frame ), FALSE, FALSE, 0 );
{
- GtkImage* image = new_local_image( "logo.bmp" );
+ GtkImage* image = new_local_image( "logo.png" );
gtk_widget_show( GTK_WIDGET( image ) );
gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( image ) );
}
void Patch_registerShortcuts(){
command_connect_accelerator( "InvertCurveTextureX" );
command_connect_accelerator( "InvertCurveTextureY" );
- command_connect_accelerator( "IncPatchColumn" );
- command_connect_accelerator( "IncPatchRow" );
- command_connect_accelerator( "DecPatchColumn" );
- command_connect_accelerator( "DecPatchRow" );
+ command_connect_accelerator( "PatchInsertInsertColumn" );
+ command_connect_accelerator( "PatchInsertInsertRow" );
+ command_connect_accelerator( "PatchDeleteLastColumn" );
+ command_connect_accelerator( "PatchDeleteLastRow" );
command_connect_accelerator( "NaturalizePatch" );
//command_connect_accelerator("CapCurrentCurve");
}
}
void File_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_button( toolbar, "Open an existing map (CTRL + O)", "file_open.bmp", "OpenMap" );
- toolbar_append_button( toolbar, "Save the active map (CTRL + S)", "file_save.bmp", "SaveMap" );
+ toolbar_append_button( toolbar, "Open an existing map (CTRL + O)", "file_open.png", "OpenMap" );
+ toolbar_append_button( toolbar, "Save the active map (CTRL + S)", "file_save.png", "SaveMap" );
}
void UndoRedo_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_button( toolbar, "Undo (CTRL + Z)", "undo.bmp", "Undo" );
- toolbar_append_button( toolbar, "Redo (CTRL + Y)", "redo.bmp", "Redo" );
+ toolbar_append_button( toolbar, "Undo (CTRL + Z)", "undo.png", "Undo" );
+ toolbar_append_button( toolbar, "Redo (CTRL + Y)", "redo.png", "Redo" );
}
void RotateFlip_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_button( toolbar, "x-axis Flip", "brush_flipx.bmp", "MirrorSelectionX" );
- toolbar_append_button( toolbar, "x-axis Rotate", "brush_rotatex.bmp", "RotateSelectionX" );
- toolbar_append_button( toolbar, "y-axis Flip", "brush_flipy.bmp", "MirrorSelectionY" );
- toolbar_append_button( toolbar, "y-axis Rotate", "brush_rotatey.bmp", "RotateSelectionY" );
- toolbar_append_button( toolbar, "z-axis Flip", "brush_flipz.bmp", "MirrorSelectionZ" );
- toolbar_append_button( toolbar, "z-axis Rotate", "brush_rotatez.bmp", "RotateSelectionZ" );
+ toolbar_append_button( toolbar, "x-axis Flip", "brush_flipx.png", "MirrorSelectionX" );
+ toolbar_append_button( toolbar, "x-axis Rotate", "brush_rotatex.png", "RotateSelectionX" );
+ toolbar_append_button( toolbar, "y-axis Flip", "brush_flipy.png", "MirrorSelectionY" );
+ toolbar_append_button( toolbar, "y-axis Rotate", "brush_rotatey.png", "RotateSelectionY" );
+ toolbar_append_button( toolbar, "z-axis Flip", "brush_flipz.png", "MirrorSelectionZ" );
+ toolbar_append_button( toolbar, "z-axis Rotate", "brush_rotatez.png", "RotateSelectionZ" );
}
void Select_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_button( toolbar, "Select touching", "selection_selecttouching.bmp", "SelectTouching" );
- toolbar_append_button( toolbar, "Select inside", "selection_selectinside.bmp", "SelectInside" );
+ toolbar_append_button( toolbar, "Select touching", "selection_selecttouching.png", "SelectTouching" );
+ toolbar_append_button( toolbar, "Select inside", "selection_selectinside.png", "SelectInside" );
}
void CSG_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_button( toolbar, "CSG Subtract (SHIFT + U)", "selection_csgsubtract.bmp", "CSGSubtract" );
- toolbar_append_button( toolbar, "CSG Merge (CTRL + U)", "selection_csgmerge.bmp", "CSGMerge" );
- toolbar_append_button( toolbar, "Hollow", "selection_makehollow.bmp", "CSGHollow" );
+ toolbar_append_button( toolbar, "CSG Subtract (SHIFT + U)", "selection_csgsubtract.png", "CSGSubtract" );
+ toolbar_append_button( toolbar, "CSG Merge (CTRL + U)", "selection_csgmerge.png", "CSGMerge" );
+ toolbar_append_button( toolbar, "Hollow", "selection_makehollow.png", "CSGHollow" );
}
void ComponentModes_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_toggle_button( toolbar, "Select Vertices (V)", "modify_vertices.bmp", "DragVertices" );
- toolbar_append_toggle_button( toolbar, "Select Edges (E)", "modify_edges.bmp", "DragEdges" );
- toolbar_append_toggle_button( toolbar, "Select Faces (F)", "modify_faces.bmp", "DragFaces" );
+ toolbar_append_toggle_button( toolbar, "Select Vertices (V)", "modify_vertices.png", "DragVertices" );
+ toolbar_append_toggle_button( toolbar, "Select Edges (E)", "modify_edges.png", "DragEdges" );
+ toolbar_append_toggle_button( toolbar, "Select Faces (F)", "modify_faces.png", "DragFaces" );
}
void Clipper_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_toggle_button( toolbar, "Clipper (X)", "view_clipper.bmp", "ToggleClipper" );
+ toolbar_append_toggle_button( toolbar, "Clipper (X)", "view_clipper.png", "ToggleClipper" );
}
void XYWnd_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_button( toolbar, "Change views", "view_change.bmp", "NextView" );
+ toolbar_append_button( toolbar, "Change views", "view_change.png", "NextView" );
}
void Manipulators_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_toggle_button( toolbar, "Translate (W)", "select_mousetranslate.bmp", "MouseTranslate" );
- toolbar_append_toggle_button( toolbar, "Rotate (R)", "select_mouserotate.bmp", "MouseRotate" );
- toolbar_append_toggle_button( toolbar, "Scale", "select_mousescale.bmp", "MouseScale" );
- toolbar_append_toggle_button( toolbar, "Resize (Q)", "select_mouseresize.bmp", "MouseDrag" );
+ toolbar_append_toggle_button( toolbar, "Translate (W)", "select_mousetranslate.png", "MouseTranslate" );
+ toolbar_append_toggle_button( toolbar, "Rotate (R)", "select_mouserotate.png", "MouseRotate" );
+ toolbar_append_toggle_button( toolbar, "Scale", "select_mousescale.png", "MouseScale" );
+ toolbar_append_toggle_button( toolbar, "Resize (Q)", "select_mouseresize.png", "MouseDrag" );
Clipper_constructToolbar( toolbar );
}
gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
- toolbar_append_toggle_button( toolbar, "Texture Lock (SHIFT +T)", "texture_lock.bmp", "TogTexLock" );
+ toolbar_append_toggle_button( toolbar, "Texture Lock (SHIFT +T)", "texture_lock.png", "TogTexLock" );
gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
- GtkButton* g_view_entities_button = toolbar_append_button( toolbar, "Entities (N)", "entities.bmp", "ToggleEntityInspector" );
- GtkButton* g_view_console_button = toolbar_append_button( toolbar, "Console (O)", "console.bmp", "ToggleConsole" );
- GtkButton* g_view_textures_button = toolbar_append_button( toolbar, "Texture Browser (T)", "texture_browser.bmp", "ToggleTextures" );
+ GtkButton* g_view_entities_button = toolbar_append_button( toolbar, "Entities (N)", "entities.png", "ToggleEntityInspector" );
+ GtkButton* g_view_console_button = toolbar_append_button( toolbar, "Console (O)", "console.png", "ToggleConsole" );
+ GtkButton* g_view_textures_button = toolbar_append_button( toolbar, "Texture Browser (T)", "texture_browser.png", "ToggleTextures" );
// TODO: call light inspector
- //GtkButton* g_view_lightinspector_button = toolbar_append_button(toolbar, "Light Inspector", "lightinspector.bmp", "ToggleLightInspector");
+ //GtkButton* g_view_lightinspector_button = toolbar_append_button(toolbar, "Light Inspector", "lightinspector.png", "ToggleLightInspector");
gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
- GtkButton* g_refresh_models_button = toolbar_append_button( toolbar, "Refresh Models", "refresh_models.bmp", "RefreshReferences" );
+ GtkButton* g_refresh_models_button = toolbar_append_button( toolbar, "Refresh Models", "refresh_models.png", "RefreshReferences" );
// disable the console and texture button in the regular layouts
gtk_window_set_position( window, GTK_WIN_POS_CENTER );
gtk_container_set_border_width( GTK_CONTAINER( window ), 0 );
- GtkImage* image = new_local_image( "splash.bmp" );
+ GtkImage* image = new_local_image( "splash.png" );
gtk_widget_show( GTK_WIDGET( image ) );
gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( image ) );
#if !defined( WIN32 )
{
- GdkPixbuf* pixbuf = pixbuf_new_from_file_with_mask( "bitmaps/icon.bmp" );
+ GdkPixbuf* pixbuf = pixbuf_new_from_file_with_mask( "bitmaps/icon.png" );
if ( pixbuf != 0 ) {
gtk_window_set_icon( window, pixbuf );
gdk_pixbuf_unref( pixbuf );
void Layout_constructPreferences( PreferencesPage& page ){
{
- const char* layouts[] = { "window1.bmp", "window2.bmp", "window3.bmp", "window4.bmp" };
+ const char* layouts[] = { "window1.png", "window2.png", "window3.png", "window4.png" };
page.appendRadioIcons(
"Window Layout",
STRING_ARRAY_RANGE( layouts ),
}
static void OnBtnPatchdetails( GtkWidget *widget, gpointer data ){
- UndoableCommand command( "patchCapTexture" );
-
- Scene_PatchCapTexture_Selected( GlobalSceneGraph() );
+ Patch_CapTexture();
}
static void OnBtnPatchfit( GtkWidget *widget, gpointer data ){
- UndoableCommand command( "patchFitTexture" );
-
- Scene_PatchTileTexture_Selected( GlobalSceneGraph(), 1, 1 );
+ Patch_FitTexture();
}
static void OnBtnPatchnatural( GtkWidget *widget, gpointer data ){
- UndoableCommand command( "patchNaturalTexture" );
-
- Scene_PatchNaturalTexture_Selected( GlobalSceneGraph() );
+ Patch_NaturalTexture();
}
static void OnBtnPatchreset( GtkWidget *widget, gpointer data ){
- float fx, fy;
- if ( DoTextureLayout( &fx, &fy ) == eIDOK ) {
- UndoableCommand command( "patchTileTexture" );
- Scene_PatchTileTexture_Selected( GlobalSceneGraph(), fx, fy );
- }
+ Patch_ResetTexture();
+}
+
+static void OnBtnPatchFlipX( GtkWidget *widget, gpointer data ){
+ Patch_FlipTextureX();
+}
+
+static void OnBtnPatchFlipY( GtkWidget *widget, gpointer data ){
+ Patch_FlipTextureY();
}
struct PatchRotateTexture
Scene_forEachVisibleSelectedPatch( PatchTranslateTexture( s, t ) );
}
+static void OnBtnPatchAutoCap( GtkWidget *widget, gpointer data ){
+ Patch_AutoCapTexture();
+}
+
static void OnSpinChanged( GtkAdjustment *adj, gpointer data ){
texdef_t td;
g_signal_connect( G_OBJECT( entry ), "key_press_event", G_CALLBACK( OnDialogKey ), 0 );
}
{
- GtkTable* table = GTK_TABLE( gtk_table_new( 5, 3, FALSE ) );
+ GtkTable* table = GTK_TABLE( gtk_table_new( 5, 4, FALSE ) );
gtk_widget_show( GTK_WIDGET( table ) );
gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( table ), TRUE, TRUE, 0 );
gtk_table_set_row_spacings( table, 5 );
{
GtkLabel* label = GTK_LABEL( gtk_label_new( "Horizontal Shift Step" ) );
gtk_widget_show( GTK_WIDGET( label ) );
- gtk_table_attach( table, GTK_WIDGET( label ), 2, 3, 0, 1,
- (GtkAttachOptions)( GTK_FILL ),
+ gtk_table_attach( table, GTK_WIDGET( label ), 2, 4, 0, 1,
+ (GtkAttachOptions)( GTK_FILL|GTK_EXPAND ),
(GtkAttachOptions)( 0 ), 0, 0 );
gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
}
{
GtkLabel* label = GTK_LABEL( gtk_label_new( "Vertical Shift Step" ) );
gtk_widget_show( GTK_WIDGET( label ) );
- gtk_table_attach( table, GTK_WIDGET( label ), 2, 3, 1, 2,
- (GtkAttachOptions)( GTK_FILL ),
+ gtk_table_attach( table, GTK_WIDGET( label ), 2, 4, 1, 2,
+ (GtkAttachOptions)( GTK_FILL|GTK_EXPAND ),
(GtkAttachOptions)( 0 ), 0, 0 );
gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
}
GtkLabel* label = GTK_LABEL( gtk_label_new( "Horizontal Stretch Step" ) );
gtk_widget_show( GTK_WIDGET( label ) );
gtk_table_attach( table, GTK_WIDGET( label ), 2, 3, 2, 3,
- (GtkAttachOptions)( GTK_FILL ),
+ (GtkAttachOptions)( GTK_FILL|GTK_EXPAND ),
(GtkAttachOptions)( 0 ), 0, 0 );
gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
}
+ {
+ GtkButton* button = GTK_BUTTON( gtk_button_new_with_label( "Flip" ) );
+ gtk_widget_show( GTK_WIDGET( button ) );
+ gtk_table_attach( table, GTK_WIDGET( button ), 3, 4, 2, 3,
+ (GtkAttachOptions)( GTK_FILL ),
+ (GtkAttachOptions)( 0 ), 0, 0 );
+ g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( OnBtnPatchFlipX ), 0 );
+ gtk_widget_set_usize( GTK_WIDGET( button ), 60, -1 );
+ }
{
GtkLabel* label = GTK_LABEL( gtk_label_new( "Vertical Stretch Step" ) );
gtk_widget_show( GTK_WIDGET( label ) );
gtk_table_attach( table, GTK_WIDGET( label ), 2, 3, 3, 4,
- (GtkAttachOptions)( GTK_FILL ),
+ (GtkAttachOptions)( GTK_FILL|GTK_EXPAND ),
(GtkAttachOptions)( 0 ), 0, 0 );
gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
}
+ {
+ GtkButton* button = GTK_BUTTON( gtk_button_new_with_label( "Flip" ) );
+ gtk_widget_show( GTK_WIDGET( button ) );
+ gtk_table_attach( table, GTK_WIDGET( button ), 3, 4, 3, 4,
+ (GtkAttachOptions)( GTK_FILL ),
+ (GtkAttachOptions)( 0 ), 0, 0 );
+ g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( OnBtnPatchFlipY ), 0 );
+ gtk_widget_set_usize( GTK_WIDGET( button ), 60, -1 );
+ }
{
GtkLabel* label = GTK_LABEL( gtk_label_new( "Rotate Step" ) );
gtk_widget_show( GTK_WIDGET( label ) );
- gtk_table_attach( table, GTK_WIDGET( label ), 2, 3, 4, 5,
- (GtkAttachOptions)( GTK_FILL ),
+ gtk_table_attach( table, GTK_WIDGET( label ), 2, 4, 4, 5,
+ (GtkAttachOptions)( GTK_FILL|GTK_EXPAND ),
(GtkAttachOptions)( 0 ), 0, 0 );
gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
}
GtkHBox* hbox2 = GTK_HBOX( gtk_hbox_new( TRUE, 5 ) );
gtk_widget_show( GTK_WIDGET( hbox2 ) );
gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( hbox2 ), TRUE, FALSE, 0 );
+ {
+ GtkButton* button = GTK_BUTTON( gtk_button_new_with_label( "Auto Cap" ) );
+ gtk_widget_show( GTK_WIDGET( button ) );
+ gtk_box_pack_end( GTK_BOX( hbox2 ), GTK_WIDGET( button ), TRUE, FALSE, 0 );
+ g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( OnBtnPatchAutoCap ), 0 );
+ gtk_widget_set_usize( GTK_WIDGET( button ), 60, -1 );
+ }
{
GtkButton* button = GTK_BUTTON( gtk_button_new_with_label( "CAP" ) );
gtk_widget_show( GTK_WIDGET( button ) );
}
}
+void PatchAutoCapTexture( Patch& patch ) {
+
+ AABB box = patch.localAABB();
+ float x = box.extents.x();
+ float y = box.extents.y();
+ float z = box.extents.z();
+
+ int cap_direction = -1;
+ if ( x < y && x < z )
+ cap_direction = 0;
+ else if ( y < x && y < z )
+ cap_direction = 1;
+ else if ( z < x && z < x )
+ cap_direction = 2;
+
+ if ( cap_direction >= 0 )
+ patch.ProjectTexture(cap_direction);
+ else
+ patch.NaturalTexture();
+}
+
+void Patch_AutoCapTexture(){
+ UndoableCommand command( "patchAutoCapTexture" );
+ Scene_forEachVisibleSelectedPatch( &PatchAutoCapTexture );
+ SceneChangeNotify();
+}
void Patch_makeCaps( Patch& patch, scene::Instance& instance, EPatchCap type, const char* shader ){
if ( ( type == eCapEndCap || type == eCapIEndCap )
NodeSmartReference cap( g_patchCreator->createPatch() );
Node_getTraversable( instance.path().parent() )->insert( cap );
- patch.MakeCap( Node_getPatch( cap ), type, ROW, true );
- Node_getPatch( cap )->SetShader( shader );
+ Patch* cap_patch = Node_getPatch( cap );
+ patch.MakeCap( cap_patch, type, ROW, true );
+ cap_patch->SetShader( shader );
+ PatchAutoCapTexture(*cap_patch);
scene::Path path( instance.path() );
path.pop();
NodeSmartReference cap( g_patchCreator->createPatch() );
Node_getTraversable( instance.path().parent() )->insert( cap );
- patch.MakeCap( Node_getPatch( cap ), type, ROW, false );
- Node_getPatch( cap )->SetShader( shader );
+ Patch* cap_patch = Node_getPatch( cap );
+ patch.MakeCap( cap_patch, type, ROW, false );
+ cap_patch->SetShader( shader );
+ PatchAutoCapTexture(*cap_patch);
scene::Path path( instance.path() );
path.pop();
Scene_PatchNaturalTexture_Selected( GlobalSceneGraph() );
}
+void Patch_CapTexture(){
+ UndoableCommand command( "patchCapTexture" );
+ Scene_PatchCapTexture_Selected( GlobalSceneGraph() );
+}
+void Patch_ResetTexture(){
+ float fx, fy;
+ if ( DoTextureLayout( &fx, &fy ) == eIDOK ) {
+ UndoableCommand command( "patchTileTexture" );
+ Scene_PatchTileTexture_Selected( GlobalSceneGraph(), fx, fy );
+ }
+}
+
+void Patch_FitTexture(){
+ UndoableCommand command( "patchFitTexture" );
+
+ Scene_PatchTileTexture_Selected( GlobalSceneGraph(), 1, 1 );
+}
#include "ifilter.h"
void Patch_registerCommands(){
GlobalCommands_insert( "InvertCurveTextureX", FreeCaller<Patch_FlipTextureX>(), Accelerator( 'I', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
GlobalCommands_insert( "InvertCurveTextureY", FreeCaller<Patch_FlipTextureY>(), Accelerator( 'I', (GdkModifierType)GDK_SHIFT_MASK ) );
- GlobalCommands_insert( "IncPatchColumn", FreeCaller<Patch_InsertInsertColumn>(), Accelerator( GDK_KP_Add, (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
- GlobalCommands_insert( "IncPatchRow", FreeCaller<Patch_InsertInsertRow>(), Accelerator( GDK_KP_Add, (GdkModifierType)GDK_CONTROL_MASK ) );
- GlobalCommands_insert( "DecPatchColumn", FreeCaller<Patch_DeleteLastColumn>(), Accelerator( GDK_KP_Subtract, (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
- GlobalCommands_insert( "DecPatchRow", FreeCaller<Patch_DeleteLastRow>(), Accelerator( GDK_KP_Subtract, (GdkModifierType)GDK_CONTROL_MASK ) );
GlobalCommands_insert( "NaturalizePatch", FreeCaller<Patch_NaturalTexture>(), Accelerator( 'N', (GdkModifierType)GDK_CONTROL_MASK ) );
GlobalCommands_insert( "PatchCylinder", FreeCaller<Patch_Cylinder>() );
GlobalCommands_insert( "PatchDenseCylinder", FreeCaller<Patch_DenseCylinder>() );
GlobalCommands_insert( "PatchCone", FreeCaller<Patch_Cone>() );
GlobalCommands_insert( "PatchSphere", FreeCaller<Patch_Sphere>() );
GlobalCommands_insert( "SimplePatchMesh", FreeCaller<Patch_Plane>(), Accelerator( 'P', (GdkModifierType)GDK_SHIFT_MASK ) );
- GlobalCommands_insert( "PatchInsertInsertColumn", FreeCaller<Patch_InsertInsertColumn>() );
+ GlobalCommands_insert( "PatchInsertInsertColumn", FreeCaller<Patch_InsertInsertColumn>(), Accelerator( GDK_KP_Add, (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
GlobalCommands_insert( "PatchInsertAddColumn", FreeCaller<Patch_InsertAddColumn>() );
- GlobalCommands_insert( "PatchInsertInsertRow", FreeCaller<Patch_InsertInsertRow>() );
+ GlobalCommands_insert( "PatchInsertInsertRow", FreeCaller<Patch_InsertInsertRow>(), Accelerator( GDK_KP_Add, (GdkModifierType)GDK_CONTROL_MASK ) );
GlobalCommands_insert( "PatchInsertAddRow", FreeCaller<Patch_InsertAddRow>() );
GlobalCommands_insert( "PatchDeleteFirstColumn", FreeCaller<Patch_DeleteFirstColumn>() );
- GlobalCommands_insert( "PatchDeleteLastColumn", FreeCaller<Patch_DeleteLastColumn>() );
- GlobalCommands_insert( "PatchDeleteFirstRow", FreeCaller<Patch_DeleteFirstRow>() );
+ GlobalCommands_insert( "PatchDeleteLastColumn", FreeCaller<Patch_DeleteLastColumn>(), Accelerator( GDK_KP_Subtract, (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
+ GlobalCommands_insert( "PatchDeleteFirstRow", FreeCaller<Patch_DeleteFirstRow>(), Accelerator( GDK_KP_Subtract, (GdkModifierType)GDK_CONTROL_MASK ) );
GlobalCommands_insert( "PatchDeleteLastRow", FreeCaller<Patch_DeleteLastRow>() );
GlobalCommands_insert( "InvertCurve", FreeCaller<Patch_Invert>(), Accelerator( 'I', (GdkModifierType)GDK_CONTROL_MASK ) );
GlobalCommands_insert( "RedisperseRows", FreeCaller<Patch_RedisperseRows>(), Accelerator( 'E', (GdkModifierType)GDK_CONTROL_MASK ) );
}
void Patch_constructToolbar( GtkToolbar* toolbar ){
- toolbar_append_button( toolbar, "Put caps on the current patch (SHIFT + C)", "curve_cap.bmp", "CapCurrentCurve" );
+ toolbar_append_button( toolbar, "Put caps on the current patch (SHIFT + C)", "cap_curve.png", "CapCurrentCurve" );
}
void Patch_constructMenu( GtkMenu* menu ){
gtk_table_set_col_spacings( table, 5 );
{
- GtkImage* image = new_local_image( "cap_bevel.bmp" );
+ GtkImage* image = new_local_image( "cap_bevel.png" );
gtk_widget_show( GTK_WIDGET( image ) );
gtk_table_attach( table, GTK_WIDGET( image ), 0, 1, 0, 1,
(GtkAttachOptions) ( GTK_FILL ),
(GtkAttachOptions) ( 0 ), 0, 0 );
}
{
- GtkImage* image = new_local_image( "cap_endcap.bmp" );
+ GtkImage* image = new_local_image( "cap_endcap.png" );
gtk_widget_show( GTK_WIDGET( image ) );
gtk_table_attach( table, GTK_WIDGET( image ), 0, 1, 1, 2,
(GtkAttachOptions) ( GTK_FILL ),
(GtkAttachOptions) ( 0 ), 0, 0 );
}
{
- GtkImage* image = new_local_image( "cap_ibevel.bmp" );
+ GtkImage* image = new_local_image( "cap_ibevel.png" );
gtk_widget_show( GTK_WIDGET( image ) );
gtk_table_attach( table, GTK_WIDGET( image ), 0, 1, 2, 3,
(GtkAttachOptions) ( GTK_FILL ),
(GtkAttachOptions) ( 0 ), 0, 0 );
}
{
- GtkImage* image = new_local_image( "cap_iendcap.bmp" );
+ GtkImage* image = new_local_image( "cap_iendcap.png" );
gtk_widget_show( GTK_WIDGET( image ) );
gtk_table_attach( table, GTK_WIDGET( image ), 0, 1, 3, 4,
(GtkAttachOptions) ( GTK_FILL ),
(GtkAttachOptions) ( 0 ), 0, 0 );
}
{
- GtkImage* image = new_local_image( "cap_cylinder.bmp" );
+ GtkImage* image = new_local_image( "cap_cylinder.png" );
gtk_widget_show( GTK_WIDGET( image ) );
gtk_table_attach( table, GTK_WIDGET( image ), 0, 1, 4, 5,
(GtkAttachOptions) ( GTK_FILL ),
void Patch_registerPreferencesPage();
+void Patch_NaturalTexture();
+void Patch_CapTexture();
+void Patch_ResetTexture();
+void Patch_FitTexture();
+void Patch_FlipTextureX();
+void Patch_FlipTextureY();
+void Patch_AutoCapTexture();
+
class PatchCreator;
extern PatchCreator* g_patchCreator;
static gboolean rotatedlg_ok( GtkWidget *widget, RotateDialog* rotateDialog ){
rotatedlg_apply( widget, rotateDialog );
- rotatedlg_cancel( widget, rotateDialog );
+ gtk_widget_hide( GTK_WIDGET( rotateDialog->window ) );
return TRUE;
}
static gboolean scaledlg_ok( GtkWidget *widget, ScaleDialog* scaleDialog ){
scaledlg_apply( widget, scaleDialog );
- scaledlg_cancel( widget, scaleDialog );
+ gtk_widget_hide( GTK_WIDGET( scaleDialog->window ) );
return TRUE;
}
}
static void OnBtnPatchdetails( GtkWidget *widget, gpointer data ){
- Scene_PatchCapTexture_Selected( GlobalSceneGraph() );
+ Patch_CapTexture();
}
static void OnBtnPatchnatural( GtkWidget *widget, gpointer data ){
- Scene_PatchNaturalTexture_Selected( GlobalSceneGraph() );
+ Patch_NaturalTexture();
}
static void OnBtnPatchreset( GtkWidget *widget, gpointer data ){
- float fx, fy;
-
- if ( DoTextureLayout( &fx, &fy ) == eIDOK ) {
- Scene_PatchTileTexture_Selected( GlobalSceneGraph(), fx, fy );
- }
+ Patch_ResetTexture();
}
static void OnBtnPatchFit( GtkWidget *widget, gpointer data ){
- Scene_PatchTileTexture_Selected( GlobalSceneGraph(), 1, 1 );
+ Patch_FitTexture();
}
static void OnBtnAxial( GtkWidget *widget, gpointer data ){
namespace
{
bool g_TextureBrowser_shaderlistOnly = false;
-bool g_TextureBrowser_fixedSize = false;
+bool g_TextureBrowser_fixedSize = true;
bool g_TextureBrowser_filterNotex = false;
+bool g_TextureBrowser_enableAlpha = true;
}
class DeferredAdjustment
void TextureBrowser_filterNotex( const BoolImportCallback& importer );
typedef FreeCaller1<const BoolImportCallback&, TextureBrowser_filterNotex> TextureBrowserFilterNotexExport;
+void TextureBrowser_enableAlpha( const BoolImportCallback& importer );
+typedef FreeCaller1<const BoolImportCallback&, TextureBrowser_enableAlpha> TextureBrowserEnableAlphaExport;
+
class TextureBrowser
{
public:
ToggleItem m_showshaderlistonly_item;
ToggleItem m_fixedsize_item;
ToggleItem m_filternotex_item;
+ToggleItem m_enablealpha_item;
guint m_sizeHandler;
guint m_exposeHandler;
m_showshaderlistonly_item( TextureBrowserShowShaderlistOnlyExport() ),
m_fixedsize_item( TextureBrowserFixedSizeExport() ),
m_filternotex_item( TextureBrowserFilterNotexExport() ),
+ m_enablealpha_item( TextureBrowserEnableAlphaExport() ),
m_heightChanged( true ),
m_originInvalid( true ),
m_scrollAdjustment( TextureBrowser_scrollChanged, this ),
m_rmbSelected( false ),
m_searchedTags( false ),
m_tags( false ),
- m_uniformTextureSize( 128 ){
+ m_uniformTextureSize( 96 ){
}
};
}
typedef FreeCaller1<const BoolImportCallback&, TextureBrowser_filterNotex> TextureBrowser_filterNotexExport;
+void TextureBrowser_enableAlpha( const BoolImportCallback& importer ){
+ importer( g_TextureBrowser_enableAlpha );
+}
+typedef FreeCaller1<const BoolImportCallback&, TextureBrowser_enableAlpha> TextureBrowser_enableAlphaExport;
+
void TextureBrowser_SetHideUnused( TextureBrowser& textureBrowser, bool hideUnused ){
if ( hideUnused ) {
textureBrowser.m_hideUnused = true;
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glDisable( GL_DEPTH_TEST );
- glDisable( GL_BLEND );
+ if ( g_TextureBrowser_enableAlpha ) {
+ glEnable( GL_BLEND );
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ else {
+ glDisable( GL_BLEND );
+ }
glOrtho( 0, textureBrowser.width, originy - textureBrowser.height, originy, -100, 100 );
glEnable( GL_TEXTURE_2D );
}
}
+ // draw checkerboard for transparent textures
+ if ( g_TextureBrowser_enableAlpha )
+ {
+ glDisable( GL_TEXTURE_2D );
+ glBegin( GL_QUADS );
+ int font_height = TextureBrowser_fontHeight( textureBrowser );
+ for ( int i = 0; i < nHeight; i += 8 )
+ for ( int j = 0; j < nWidth; j += 8 )
+ {
+ unsigned char color = (i + j) / 8 % 2 ? 0x66 : 0x99;
+ glColor3ub( color, color, color );
+ int left = j;
+ int right = std::min(j+8, nWidth);
+ int top = i;
+ int bottom = std::min(i+8, nHeight);
+ glVertex2i(x + right, y - nHeight - font_height + top);
+ glVertex2i(x + left, y - nHeight - font_height + top);
+ glVertex2i(x + left, y - nHeight - font_height + bottom);
+ glVertex2i(x + right, y - nHeight - font_height + bottom);
+ }
+ glEnd();
+ glEnable( GL_TEXTURE_2D );
+ }
+
// Draw the texture
glBindTexture( GL_TEXTURE_2D, q->texture_number );
GlobalOpenGL_debugAssertNoErrors();
TextureBrowser_queueDraw( textureBrowser );
}
+void TextureBrowser_setUniformSize( TextureBrowser& textureBrowser, std::size_t scale ){
+ textureBrowser.m_uniformTextureSize = scale;
+
+ TextureBrowser_queueDraw( textureBrowser );
+}
+
void TextureBrowser_MouseWheel( TextureBrowser& textureBrowser, bool bUp ){
int originy = TextureBrowser_getOriginY( textureBrowser );
create_menu_item_with_mnemonic( menu, "Show Untagged", "ShowUntagged" );
}
+ menu_separator( menu );
create_check_menu_item_with_mnemonic( menu, "Fixed Size", "FixedSize" );
+ create_check_menu_item_with_mnemonic( menu, "Transparency", "EnableAlpha" );
if ( string_empty( g_pGameDescription->getKeyValue( "show_wads" ) ) ) {
menu_separator( menu );
gtk_widget_set_sensitive( g_TextureBrowser.m_shader_info_item, FALSE );
}
+
return textures_menu_item;
}
void TextureBrowser_SetNotex(){
StringOutputStream name( 256 );
- name << GlobalRadiant().getAppPath() << "bitmaps/notex.bmp";
+ name << GlobalRadiant().getAppPath() << "bitmaps/notex.png";
g_notex = name.c_str();
name = NULL;
- name << GlobalRadiant().getAppPath() << "bitmaps/shadernotex.bmp";
+ name << GlobalRadiant().getAppPath() << "bitmaps/shadernotex.png";
g_shadernotex = name.c_str();
}
ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Loading Shaders" );
GlobalShaderSystem().refresh();
UpdateAllWindows();
+ GtkTreeSelection* selection = gtk_tree_view_get_selection((GtkTreeView*)GlobalTextureBrowser().m_treeViewTree);
+ GtkTreeModel* model = NULL;
+ GtkTreeIter iter;
+ if ( gtk_tree_selection_get_selected (selection, &model, &iter) )
+ {
+ gchar dirName[1024];
+
+ gchar* buffer;
+ gtk_tree_model_get( model, &iter, 0, &buffer, -1 );
+ strcpy( dirName, buffer );
+ g_free( buffer );
+ if ( !TextureBrowser_showWads() ) {
+ strcat( dirName, "/" );
+ }
+ TextureBrowser_ShowDirectory( GlobalTextureBrowser(), dirName );
+ TextureBrowser_queueDraw( GlobalTextureBrowser() );
+ }
}
void TextureBrowser_ToggleShowShaders(){
TextureBrowser_activeShadersChanged( GlobalTextureBrowser() );
}
+void TextureBrowser_EnableAlpha(){
+ g_TextureBrowser_enableAlpha ^= 1;
+ GlobalTextureBrowser().m_enablealpha_item.update();
+ TextureBrowser_activeShadersChanged( GlobalTextureBrowser() );
+}
+
void TextureBrowser_exportTitle( const StringImportCallback& importer ){
StringOutputStream buffer( 64 );
buffer << "Textures: ";
}
typedef ReferenceCaller1<TextureBrowser, const IntImportCallback&, TextureScaleExport> TextureScaleExportCaller;
+
+void UniformTextureSizeImport( TextureBrowser& textureBrowser, int value ){
+
+ if ( value > 16 )
+ TextureBrowser_setUniformSize( textureBrowser, value );
+}
+typedef ReferenceCaller1<TextureBrowser, int, UniformTextureSizeImport> UniformTextureSizeImportCaller;
+
void TextureBrowser_constructPreferences( PreferencesPage& page ){
page.appendCheckBox(
"", "Texture scrollbar",
IntExportCallback( TextureScaleExportCaller( GlobalTextureBrowser() ) )
);
}
+ page.appendSpinner(
+ "Texture Thumbnail Size",
+ GlobalTextureBrowser().m_uniformTextureSize,
+ GlobalTextureBrowser().m_uniformTextureSize,
+ 16, 8192
+ );
page.appendEntry( "Mousewheel Increment", GlobalTextureBrowser().m_mouseWheelScrollIncrement );
{
const char* startup_shaders[] = { "None", TextureBrowser_getComonShadersName() };
GlobalToggles_insert( "ToggleShowShaderlistOnly", FreeCaller<TextureBrowser_ToggleShowShaderListOnly>(), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_showshaderlistonly_item ) );
GlobalToggles_insert( "FixedSize", FreeCaller<TextureBrowser_FixedSize>(), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_fixedsize_item ) );
GlobalToggles_insert( "FilterNotex", FreeCaller<TextureBrowser_FilterNotex>(), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_filternotex_item ) );
+ GlobalToggles_insert( "EnableAlpha", FreeCaller<TextureBrowser_EnableAlpha>(), ToggleItem::AddCallbackCaller( g_TextureBrowser.m_enablealpha_item ) );
GlobalPreferenceSystem().registerPreference( "TextureScale",
makeSizeStringImportCallback( TextureBrowserSetScaleCaller( g_TextureBrowser ) ),
SizeExportStringCaller( g_TextureBrowser.m_textureScale )
);
+ GlobalPreferenceSystem().registerPreference( "UniformTextureSize",
+ makeIntStringImportCallback(UniformTextureSizeImportCaller(g_TextureBrowser)),
+ IntExportStringCaller(g_TextureBrowser.m_uniformTextureSize) );
GlobalPreferenceSystem().registerPreference( "TextureScrollbar",
makeBoolStringImportCallback( TextureBrowserImportShowScrollbarCaller( g_TextureBrowser ) ),
BoolExportStringCaller( GlobalTextureBrowser().m_showTextureScrollbar )
GlobalPreferenceSystem().registerPreference( "ShowShaderlistOnly", BoolImportStringCaller( g_TextureBrowser_shaderlistOnly ), BoolExportStringCaller( g_TextureBrowser_shaderlistOnly ) );
GlobalPreferenceSystem().registerPreference( "FixedSize", BoolImportStringCaller( g_TextureBrowser_fixedSize ), BoolExportStringCaller( g_TextureBrowser_fixedSize ) );
GlobalPreferenceSystem().registerPreference( "FilterNotex", BoolImportStringCaller( g_TextureBrowser_filterNotex ), BoolExportStringCaller( g_TextureBrowser_filterNotex ) );
+ GlobalPreferenceSystem().registerPreference( "EnableAlpha", BoolImportStringCaller( g_TextureBrowser_enableAlpha ), BoolExportStringCaller( g_TextureBrowser_enableAlpha ) );
GlobalPreferenceSystem().registerPreference( "LoadShaders", IntImportStringCaller( reinterpret_cast<int&>( GlobalTextureBrowser().m_startupShaders ) ), IntExportStringCaller( reinterpret_cast<int&>( GlobalTextureBrowser().m_startupShaders ) ) );
GlobalPreferenceSystem().registerPreference( "WheelMouseInc", SizeImportStringCaller( GlobalTextureBrowser().m_mouseWheelScrollIncrement ), SizeExportStringCaller( GlobalTextureBrowser().m_mouseWheelScrollIncrement ) );
GlobalPreferenceSystem().registerPreference( "SI_Colors0", Vector3ImportStringCaller( GlobalTextureBrowser().color_textureback ), Vector3ExportStringCaller( GlobalTextureBrowser().color_textureback ) );
#include "inout.h"
#include "cmdlib.h"
+#include "etclib.h"
#include "imagelib.h"
#include "vfs.h"
}
}
}
+
+
+/*
+ ============================================================================
+
+ KHRONOS TEXTURE
+
+ ============================================================================
+ */
+
+
+#define KTX_UINT32_LE( buf ) ( ( unsigned int )( (buf)[0] | ( (buf)[1] << 8 ) | ( (buf)[2] << 16 ) | ( (buf)[3] << 24 ) ) )
+#define KTX_UINT32_BE( buf ) ( ( unsigned int )( (buf)[3] | ( (buf)[2] << 8 ) | ( (buf)[1] << 16 ) | ( (buf)[0] << 24 ) ) )
+
+#define KTX_TYPE_UNSIGNED_BYTE 0x1401
+#define KTX_TYPE_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define KTX_TYPE_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define KTX_TYPE_UNSIGNED_SHORT_5_6_5 0x8363
+
+#define KTX_FORMAT_ALPHA 0x1906
+#define KTX_FORMAT_RGB 0x1907
+#define KTX_FORMAT_RGBA 0x1908
+#define KTX_FORMAT_LUMINANCE 0x1909
+#define KTX_FORMAT_LUMINANCE_ALPHA 0x190A
+#define KTX_FORMAT_BGR 0x80E0
+#define KTX_FORMAT_BGRA 0x80E1
+
+#define KTX_FORMAT_ETC1_RGB8 0x8D64
+
+static void KTX_DecodeA8( const byte *in, qboolean bigEndian, byte *out ){
+ out[0] = out[1] = out[2] = 0;
+ out[3] = in[0];
+}
+
+static void KTX_DecodeRGB8( const byte *in, qboolean bigEndian, byte *out ){
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = 255;
+}
+
+static void KTX_DecodeRGBA8( const byte *in, qboolean bigEndian, byte *out ){
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+static void KTX_DecodeL8( const byte *in, qboolean bigEndian, byte *out ){
+ out[0] = out[1] = out[2] = in[0];
+ out[3] = 255;
+}
+
+static void KTX_DecodeLA8( const byte *in, qboolean bigEndian, byte *out ){
+ out[0] = out[1] = out[2] = in[0];
+ out[3] = in[1];
+}
+
+static void KTX_DecodeBGR8( const byte *in, qboolean bigEndian, byte *out ){
+ out[0] = in[2];
+ out[1] = in[1];
+ out[2] = in[0];
+ out[3] = 255;
+}
+
+static void KTX_DecodeBGRA8( const byte *in, qboolean bigEndian, byte *out ){
+ out[0] = in[2];
+ out[1] = in[1];
+ out[2] = in[0];
+ out[3] = in[3];
+}
+
+static void KTX_DecodeRGBA4( const byte *in, qboolean bigEndian, byte *out ){
+ unsigned short rgba;
+ int r, g, b, a;
+
+ if ( bigEndian ) {
+ rgba = ( in[0] << 8 ) | in[1];
+ }
+ else {
+ rgba = ( in[1] << 8 ) | in[0];
+ }
+
+ r = ( rgba >> 12 ) & 0xf;
+ g = ( rgba >> 8 ) & 0xf;
+ b = ( rgba >> 4 ) & 0xf;
+ a = rgba & 0xf;
+ out[0] = ( r << 4 ) | r;
+ out[1] = ( g << 4 ) | g;
+ out[2] = ( b << 4 ) | b;
+ out[3] = ( a << 4 ) | a;
+}
+
+static void KTX_DecodeRGBA5( const byte *in, qboolean bigEndian, byte *out ){
+ unsigned short rgba;
+ int r, g, b;
+
+ if ( bigEndian ) {
+ rgba = ( in[0] << 8 ) | in[1];
+ }
+ else {
+ rgba = ( in[1] << 8 ) | in[0];
+ }
+
+ r = ( rgba >> 11 ) & 0x1f;
+ g = ( rgba >> 6 ) & 0x1f;
+ b = ( rgba >> 1 ) & 0x1f;
+ out[0] = ( r << 3 ) | ( r >> 2 );
+ out[1] = ( g << 3 ) | ( g >> 2 );
+ out[2] = ( b << 3 ) | ( b >> 2 );
+ out[3] = ( rgba & 1 ) * 255;
+}
+
+static void KTX_DecodeRGB5( const byte *in, qboolean bigEndian, byte *out ){
+ unsigned short rgba;
+ int r, g, b;
+
+ if ( bigEndian ) {
+ rgba = ( in[0] << 8 ) | in[1];
+ }
+ else {
+ rgba = ( in[1] << 8 ) | in[0];
+ }
+
+ r = ( rgba >> 11 ) & 0x1f;
+ g = ( rgba >> 5 ) & 0x3f;
+ b = rgba & 0x1f;
+ out[0] = ( r << 3 ) | ( r >> 2 );
+ out[1] = ( g << 2 ) | ( g >> 4 );
+ out[2] = ( b << 3 ) | ( b >> 2 );
+ out[3] = 255;
+}
+
+typedef struct
+{
+ unsigned int type;
+ unsigned int format;
+ unsigned int pixelSize;
+ void ( *decode )( const byte *in, qboolean bigEndian, byte *out );
+} KTX_UncompressedFormat_t;
+
+static const KTX_UncompressedFormat_t KTX_UncompressedFormats[] =
+{
+ { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_ALPHA, 1, KTX_DecodeA8 },
+ { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_RGB, 3, KTX_DecodeRGB8 },
+ { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_RGBA, 4, KTX_DecodeRGBA8 },
+ { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_LUMINANCE, 1, KTX_DecodeL8 },
+ { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_LUMINANCE_ALPHA, 2, KTX_DecodeLA8 },
+ { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_BGR, 3, KTX_DecodeBGR8 },
+ { KTX_TYPE_UNSIGNED_BYTE, KTX_FORMAT_BGRA, 4, KTX_DecodeBGRA8 },
+ { KTX_TYPE_UNSIGNED_SHORT_4_4_4_4, KTX_FORMAT_RGBA, 2, KTX_DecodeRGBA4 },
+ { KTX_TYPE_UNSIGNED_SHORT_5_5_5_1, KTX_FORMAT_RGBA, 2, KTX_DecodeRGBA5 },
+ { KTX_TYPE_UNSIGNED_SHORT_5_6_5, KTX_FORMAT_RGB, 2, KTX_DecodeRGB5 },
+ { 0, 0, 0, NULL }
+};
+
+static qboolean KTX_DecodeETC1( const byte* in, size_t inSize, unsigned int width, unsigned int height, byte* out ){
+ unsigned int y, stride = width * 4;
+ byte rgba[64];
+
+ if ( inSize < ( ( ( ( width + 3 ) & ~3 ) * ( ( height + 3 ) & ~3 ) ) >> 1 ) ) {
+ return qfalse;
+ }
+
+ for ( y = 0; y < height; y += 4, out += stride * 4 )
+ {
+ byte *p;
+ unsigned int x, blockrows;
+
+ blockrows = height - y;
+ if ( blockrows > 4 ) {
+ blockrows = 4;
+ }
+
+ p = out;
+ for ( x = 0; x < width; x += 4, p += 16 )
+ {
+ unsigned int blockrowsize, blockrow;
+
+ ETC_DecodeETC1Block( in, rgba, qtrue );
+ in += 8;
+
+ blockrowsize = width - x;
+ if ( blockrowsize > 4 ) {
+ blockrowsize = 4;
+ }
+ blockrowsize *= 4;
+ for ( blockrow = 0; blockrow < blockrows; blockrow++ )
+ {
+ memcpy( p + blockrow * stride, rgba + blockrow * 16, blockrowsize );
+ }
+ }
+ }
+
+ return qtrue;
+}
+
+#define KTX_HEADER_UINT32( buf ) ( bigEndian ? KTX_UINT32_BE( buf ) : KTX_UINT32_LE( buf ) )
+
+void LoadKTXBufferFirstImage( const byte *buffer, size_t bufSize, byte **pic, int *picWidth, int *picHeight ){
+ unsigned int type, format, width, height, imageOffset;
+ byte *pixels;
+
+ if ( bufSize < 64 ) {
+ Error( "LoadKTX: Image doesn't have a header" );
+ }
+
+ if ( memcmp( buffer, "\xABKTX 11\xBB\r\n\x1A\n", 12 ) ) {
+ Error( "LoadKTX: Image has the wrong identifier" );
+ }
+
+ qboolean bigEndian = ( buffer[4] == 4 );
+
+ type = KTX_HEADER_UINT32( buffer + 16 );
+ if ( type ) {
+ format = KTX_HEADER_UINT32( buffer + 32 );
+ }
+ else {
+ format = KTX_HEADER_UINT32( buffer + 28 );
+ }
+
+ width = KTX_HEADER_UINT32( buffer + 36 );
+ height = KTX_HEADER_UINT32( buffer + 40 );
+ if ( !width ) {
+ Error( "LoadKTX: Image has zero width" );
+ }
+ if ( !height ) {
+ height = 1;
+ }
+ if ( picWidth ) {
+ *picWidth = width;
+ }
+ if ( picHeight ) {
+ *picHeight = height;
+ }
+
+ imageOffset = 64 + KTX_HEADER_UINT32( buffer + 60 ) + 4;
+ if ( bufSize < imageOffset ) {
+ Error( "LoadKTX: No image in the file" );
+ }
+ buffer += imageOffset;
+ bufSize -= imageOffset;
+
+ pixels = safe_malloc( width * height * 4 );
+ *pic = pixels;
+
+ if ( type ) {
+ const KTX_UncompressedFormat_t *ktxFormat = KTX_UncompressedFormats;
+ unsigned int pixelSize;
+ unsigned int inRowLength, inPadding;
+ unsigned int y;
+
+ while ( ktxFormat->type )
+ {
+ if ( ktxFormat->type == type && ktxFormat->format == format ) {
+ break;
+ }
+ ktxFormat++;
+ }
+ if ( !ktxFormat->type ) {
+ Error( "LoadKTX: Image has an unsupported pixel type 0x%X or format 0x%X", type, format );
+ }
+
+ pixelSize = ktxFormat->pixelSize;
+ inRowLength = width * pixelSize;
+ inPadding = ( ( inRowLength + 3 ) & ~3 ) - inRowLength;
+
+ if ( bufSize < height * ( inRowLength + inPadding ) ) {
+ Error( "LoadKTX: Image is truncated" );
+ }
+
+ for ( y = 0; y < height; y++ )
+ {
+ unsigned int x;
+ for ( x = 0; x < width; x++, buffer += pixelSize, pixels += 4 )
+ {
+ ktxFormat->decode( buffer, bigEndian, pixels );
+ }
+ buffer += inPadding;
+ }
+ }
+ else {
+ qboolean decoded = qfalse;
+
+ switch ( format )
+ {
+ case KTX_FORMAT_ETC1_RGB8:
+ decoded = KTX_DecodeETC1( buffer, bufSize, width, height, pixels );
+ break;
+ default:
+ Error( "LoadKTX: Image has an unsupported compressed format format 0x%X", format );
+ break;
+ }
+
+ if ( !decoded ) {
+ Error( "LoadKTX: Image is truncated" );
+ }
+ }
+}
int LoadJPGBuff( void *src_buffer, int src_size, unsigned char **pic, int *width, int *height );
void Load32BitImage( const char *name, unsigned **pixels, int *width, int *height );
+
+void LoadKTXBufferFirstImage( const byte *buffer, size_t bufSize, byte **pic, int *picWidth, int *picHeight );
size_t stacksize;
int start, end;
- int i = 0, status = 0;
+ int i = 0;
start = I_FloatTime();
pacifier = showpacifier;
}
for ( i = 0 ; i < numthreads ; i++ )
{
- if ( pthread_join( work_threads[i], (void **)&status ) != 0 ) {
+ if ( pthread_join( work_threads[i], NULL ) != 0 ) {
Error( "pthread_join failed" );
}
}
}
#endif
}
+ else
+ {
+ /* attempt to load ktx */
+ StripExtension( name );
+ strcat( name, ".ktx" );
+ size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 );
+ if ( size > 0 ) {
+ LoadKTXBufferFirstImage( buffer, size, &image->pixels, &image->width, &image->height );
+ }
+ }
}
}
}
}
+struct HelpOption
+{
+ const char* name;
+ const char* description;
+};
+
+void HelpOptions(const char* group_name, int indentation, int width, struct HelpOption* options, int count)
+{
+ indentation *= 2;
+ char* indent = malloc(indentation+1);
+ memset(indent, ' ', indentation);
+ indent[indentation] = 0;
+ printf("%s%s:\n", indent, group_name);
+ indentation += 2;
+ indent = realloc(indent, indentation+1);
+ memset(indent, ' ', indentation);
+ indent[indentation] = 0;
+
+ int i;
+ for ( i = 0; i < count; i++ )
+ {
+ int printed = printf("%s%-24s ", indent, options[i].name);
+ int descsz = strlen(options[i].description);
+ int j = 0;
+ while ( j < descsz && descsz-j > width - printed )
+ {
+ if ( j != 0 )
+ printf("%s%26c",indent,' ');
+ int fragment = width - printed;
+ while ( fragment > 0 && options[i].description[j+fragment-1] != ' ')
+ fragment--;
+ j += fwrite(options[i].description+j, sizeof(char), fragment, stdout);
+ putchar('\n');
+ printed = indentation+26;
+ }
+ if ( j == 0 )
+ {
+ printf("%s\n",options[i].description+j);
+ }
+ else if ( j < descsz )
+ {
+ printf("%s%26c%s\n",indent,' ',options[i].description+j);
+ }
+ }
+
+ putchar('\n');
+
+ free(indent);
+}
+
+void HelpBsp()
+{
+ struct HelpOption bsp[] = {
+ {"-bsp <filename.map>", "Switch that enters this stage"},
+ {"-altsplit", "Alternate BSP tree splitting weights (should give more fps)"},
+ {"-celshader <shadername>", "Sets a global cel shader name"},
+ {"-custinfoparms", "Read scripts/custinfoparms.txt"},
+ {"-debuginset", "Push all triangle vertexes towards the triangle center"},
+ {"-debugportals", "Make BSP portals visible in the map"},
+ {"-debugsurfaces", "Color the vertexes according to the index of the surface"},
+ {"-deep", "Use detail brushes in the BSP tree, but at lowest priority (should give more fps)"},
+ {"-de <F>", "Distance epsilon for plane snapping etc."},
+ {"-fakemap", "Write fakemap.map containing all world brushes"},
+ {"-flares", "Turn on support for flares (TEST?)"},
+ {"-flat", "Enable flat shading (good for combining with -celshader)"},
+ {"-fulldetail", "Treat detail brushes as structural ones"},
+ {"-leaktest", "Abort if a leak was found"},
+ {"-meta", "Combine adjacent triangles of the same texture to surfaces (ALWAYS USE THIS)"},
+ {"-minsamplesize <N>", "Sets minimum lightmap resolution in luxels/qu"},
+ {"-mi <N>", "Sets the maximum number of indexes per surface"},
+ {"-mv <N>", "Sets the maximum number of vertices of a lightmapped surface"},
+ {"-ne <F>", "Normal epsilon for plane snapping etc."},
+ {"-nocurves", "Turn off support for patches"},
+ {"-nodetail", "Leave out detail brushes"},
+ {"-noflares", "Turn off support for flares"},
+ {"-nofog", "Turn off support for fog volumes"},
+ {"-nohint", "Turn off support for hint brushes"},
+ {"-nosubdivide", "Turn off support for `q3map_tessSize` (breaks water vertex deforms)"},
+ {"-notjunc", "Do not fix T-junctions (causes cracks between triangles, do not use)"},
+ {"-nowater", "Turn off support for water, slime or lava (Stef, this is for you)"},
+ {"-np <A>", "Force all surfaces to be nonplanar with a given shade angle"},
+ {"-onlyents", "Only update entities in the BSP"},
+ {"-patchmeta", "Turn patches into triangle meshes for display"},
+ {"-rename", "Append “bspâ€\9d suffix to miscmodel shaders (needed for SoF2)"},
+ {"-samplesize <N>", "Sets default lightmap resolution in luxels/qu"},
+ {"-skyfix", "Turn sky box into six surfaces to work around ATI problems"},
+ {"-snap <N>", "Snap brush bevel planes to the given number of units"},
+ {"-tempname <filename.map>", "Read the MAP file from the given file name"},
+ {"-texrange <N>", "Limit per-surface texture range to the given number of units, and subdivide surfaces like with `q3map_tessSize` if this is not met"},
+ {"-tmpout", "Write the BSP file to /tmp"},
+ {"-verboseentities", "Enable `-v` only for map entities, not for the world"},
+ };
+ HelpOptions("BSP Stage", 0, 80, bsp, sizeof(bsp)/sizeof(struct HelpOption));
+}
+void HelpVis()
+{
+ struct HelpOption vis[] = {
+ {"-vis <filename.map>", "Switch that enters this stage"},
+ {"-fast", "Very fast and crude vis calculation"},
+ {"-mergeportals", "The less crude half of `-merge`, makes vis sometimes much faster but doesn't hurt fps usually"},
+ {"-merge", "Faster but still okay vis calculation"},
+ {"-nopassage", "Just use PortalFlow vis (usually less fps)"},
+ {"-nosort", "Do not sort the portals before calculating vis (usually slower)"},
+ {"-passageOnly", "Just use PassageFlow vis (usually less fps)"},
+ {"-saveprt", "Keep the PRT file after running vis (so you can run vis again)"},
+ {"-tmpin", "Use /tmp folder for input"},
+ {"-tmpout", "Use /tmp folder for output"},
+ };
+ HelpOptions("VIS Stage", 0, 80, vis, sizeof(vis)/sizeof(struct HelpOption));
+}
+void HelpLight()
+{
+ struct HelpOption light[] = {
+ {"-light <filename.map>", "Switch that enters this stage"},
+ {"-vlight <filename.map>", "Deprecated alias for `-light -fast` ... filename.map"},
+ {"-approx <N>", "Vertex light approximation tolerance (never use in conjunction with deluxemapping)"},
+ {"-areascale <F, `-area` F>", "Scaling factor for area lights (surfacelight)"},
+ {"-border", "Add a red border to lightmaps for debugging"},
+ {"-bouncegrid", "Also compute radiosity on the light grid"},
+ {"-bounceonly", "Only compute radiosity"},
+ {"-bouncescale <F>", "Scaling factor for radiosity"},
+ {"-bounce <N>", "Number of bounces for radiosity"},
+ {"-cheapgrid", "Use `-cheap` style lighting for radiosity"},
+ {"-cheap", "Abort vertex light calculations when white is reached"},
+ {"-compensate <F>", "Lightmap compensate (darkening factor applied after everything else)"},
+ {"-cpma", "CPMA vertex lighting mode"},
+ {"-custinfoparms", "Read scripts/custinfoparms.txt"},
+ {"-dark", "Darken lightmap seams"},
+ {"-debugaxis", "Color the lightmaps according to the lightmap axis"},
+ {"-debugcluster", "Color the lightmaps according to the index of the cluster"},
+ {"-debugdeluxe", "Show deluxemaps on the lightmap"},
+ {"-debugnormals", "Color the lightmaps according to the direction of the surface normal"},
+ {"-debugorigin", "Color the lightmaps according to the origin of the luxels"},
+ {"-debugsurfaces, -debugsurface", "Color the lightmaps according to the index of the surface"},
+ {"-debugunused", "This option does nothing"},
+ {"-debug", "Mark the lightmaps according to the cluster: unmapped clusters get yellow, occluded ones get pink, flooded ones get blue overlay color, otherwise red"},
+ {"-deluxemode 0", "Use modelspace deluxemaps (DarkPlaces)"},
+ {"-deluxemode 1", "Use tangentspace deluxemaps"},
+ {"-deluxe, -deluxemap", "Enable deluxemapping (light direction maps)"},
+ {"-dirtdebug, -debugdirt", "Store the dirtmaps as lightmaps for debugging"},
+ {"-dirtdepth", "Dirtmapping depth"},
+ {"-dirtgain", "Dirtmapping exponent"},
+ {"-dirtmode 0", "Ordered direction dirtmapping"},
+ {"-dirtmode 1", "Randomized direction dirtmapping"},
+ {"-dirtscale", "Dirtmapping scaling factor"},
+ {"-dirty", "Enable dirtmapping"},
+ {"-dump", "Dump radiosity from `-bounce` into numbered MAP file prefabs"},
+ {"-export", "Export lightmaps when compile finished (like `-export` mode)"},
+ {"-exposure <F>", "Lightmap exposure to better support overbright spots"},
+ {"-external", "Force external lightmaps even if at size of internal lightmaps"},
+ {"-extravisnudge", "Broken feature to nudge the luxel origin to a better vis cluster"},
+ {"-extrawide", "Deprecated alias for `-super 2 -filter`"},
+ {"-extra", "Deprecated alias for `-super 2`"},
+ {"-fastbounce", "Use `-fast` style lighting for radiosity"},
+ {"-faster", "Use a faster falloff curve for lighting; also implies `-fast`"},
+ {"-fastgrid", "Use `-fast` style lighting for the light grid"},
+ {"-fast", "Ignore tiny light contributions"},
+ {"-filter", "Lightmap filtering"},
+ {"-floodlight", "Enable floodlight (zero-effort somewhat decent lighting)"},
+ {"-gamma <F>", "Lightmap gamma"},
+ {"-gridambientscale <F>", "Scaling factor for the light grid ambient components only"},
+ {"-gridscale <F>", "Scaling factor for the light grid only"},
+ {"-keeplights", "Keep light entities in the BSP file after compile"},
+ {"-lightmapdir <directory>", "Directory to store external lightmaps (default: same as map name without extension)"},
+ {"-lightmapsize <N>", "Size of lightmaps to generate (must be a power of two)"},
+ {"-lomem", "Low memory but slower lighting mode"},
+ {"-lowquality", "Low quality floodlight (appears to currently break floodlight)"},
+ {"-minsamplesize <N>", "Sets minimum lightmap resolution in luxels/qu"},
+ {"-nocollapse", "Do not collapse identical lightmaps"},
+ {"-nodeluxe, -nodeluxemap", "Disable deluxemapping"},
+ {"-nogrid", "Disable grid light calculation (makes all entities fullbright)"},
+ {"-nolightmapsearch", "Do not optimize lightmap packing for GPU memory usage (as doing so costs fps)"},
+ {"-normalmap", "Color the lightmaps according to the direction of the surface normal (TODO is this identical to `-debugnormals`?)"},
+ {"-nostyle, -nostyles", "Disable support for light styles"},
+ {"-nosurf", "Disable tracing against surfaces (only uses BSP nodes then)"},
+ {"-notrace", "Disable shadow occlusion"},
+ {"-novertex", "Disable vertex lighting"},
+ {"-patchshadows", "Cast shadows from patches"},
+ {"-pointscale <F, `-point` F>", "Scaling factor for point lights (light entities)"},
+ {"-q3", "Use nonlinear falloff curve by default (like Q3A)"},
+ {"-samplescale <F>", "Scales all lightmap resolutions"},
+ {"-samplesize <N>", "Sets default lightmap resolution in luxels/qu"},
+ {"-samples <N>", "Adaptive supersampling quality"},
+ {"-scale <F>", "Scaling factor for all light types"},
+ {"-shadeangle <A>", "Angle for phong shading"},
+ {"-shade", "Enable phong shading at default shade angle"},
+ {"-skyscale <F, `-sky` F>", "Scaling factor for sky and sun light"},
+ {"-smooth", "Deprecated alias for `-samples 2`"},
+ {"-style, -styles", "Enable support for light styles"},
+ {"-sunonly", "Only compute sun light"},
+ {"-super <N, `-supersample` N>", "Ordered grid supersampling quality"},
+ {"-thresh <F>", "Triangle subdivision threshold"},
+ {"-trianglecheck", "Broken check that should ensure luxels apply to the right triangle"},
+ {"-trisoup", "Convert brush faces to triangle soup"},
+ {"-wolf", "Use linear falloff curve by default (like W:ET)"},
+ };
+
+ HelpOptions("Light Stage", 0, 80, light, sizeof(light)/sizeof(struct HelpOption));
+}
+
+void HelpAnalize()
+{
+ struct HelpOption analize[] = {
+ {"-analyze <filename.bsp>", "Switch that enters this mode"},
+ {"-lumpswap", "Swap byte order in the lumps"},
+ };
+
+ HelpOptions("Analyzing BSP-like file structure", 0, 80, analize, sizeof(analize)/sizeof(struct HelpOption));
+}
+void HelpScale()
+{
+ struct HelpOption scale[] = {
+ {"-scale <S filename.bsp>", "Scale uniformly"},
+ {"-scale <SX SY SZ filename.bsp>", "Scale non-uniformly"},
+ {"-scale -tex <S filename.bsp>", "Scale uniformly without texture lock"},
+ {"-scale -tex <SX SY SZ filename.bsp>", "Scale non-uniformly without texture lock"},
+ };
+ HelpOptions("Scaling", 0, 80, scale, sizeof(scale)/sizeof(struct HelpOption));
+}
+void HelpConvert()
+{
+ struct HelpOption convert[] = {
+ {"-convert <filename.bsp>", "Switch that enters this mode"},
+ {"-de <number>", "Distance epsilon for the conversion"},
+ {"-format <converter>", "Select the converter (available: map, ase, or game names)"},
+ {"-ne <F>", "Normal epsilon for the conversion"},
+ {"-shadersasbitmap", "(only for ase) use the shader names as \\*BITMAP key so they work as prefabs"},
+ };
+
+ HelpOptions("Converting & Decompiling", 0, 80, convert, sizeof(convert)/sizeof(struct HelpOption));
+}
+
+void HelpExport()
+{
+ struct HelpOption exportl[] = {
+ {"-export <filename.bsp>", "Copies lightmaps from the BSP to `filename/lightmap_0000.tga` ff"}
+ };
+
+ HelpOptions("Exporting lightmaps", 0, 80, exportl, sizeof(exportl)/sizeof(struct HelpOption));
+}
+
+void HelpFixaas()
+{
+ struct HelpOption fixaas[] = {
+ {"-fixaas <filename.bsp>", "Switch that enters this mode"},
+ };
+
+ HelpOptions("Fixing AAS checksum", 0, 80, fixaas, sizeof(fixaas)/sizeof(struct HelpOption));
+}
+
+void HelpInfo()
+{
+ struct HelpOption info[] = {
+ {"-info <filename.bsp>", "Switch that enters this mode"},
+ };
+
+ HelpOptions("Get info about BSP file", 0, 80, info, sizeof(info)/sizeof(struct HelpOption));
+}
+
+void HelpImport()
+{
+ struct HelpOption import[] = {
+ {"-import <filename.bsp>", "Copies lightmaps from `filename/lightmap_0000.tga` ff into the BSP"},
+ };
+
+ HelpOptions("Importing lightmaps", 0, 80, import, sizeof(import)/sizeof(struct HelpOption));
+}
+
+void HelpMinimap()
+{
+ struct HelpOption minimap[] = {
+ {"-minimap <filename.bsp>", "Creates a minimap of the BSP, by default writes to `../gfx/filename_mini.tga`"},
+ {"-black", "Write the minimap as a black-on-transparency RGBA32 image"},
+ {"-boost <F>", "Sets the contrast boost value (higher values make a brighter image); contrast boost is somewhat similar to gamma, but continuous even at zero"},
+ {"-border <F>", "Sets the amount of border pixels relative to the total image size"},
+ {"-gray", "Write the minimap as a white-on-black GRAY8 image"},
+ {"-keepaspect", "Ensure the aspect ratio is kept (the minimap is then letterboxed to keep aspect)"},
+ {"-minmax <xmin ymin zmin xmax ymax zmax>", "Forces specific map dimensions (note: the minimap actually uses these dimensions, scaled to the target size while keeping aspect with centering, and 1/64 of border appended to all sides)"},
+ {"-nokeepaspect", "Do not ensure the aspect ratio is kept (makes it easier to use the image in your code, but looks bad together with sharpening)"},
+ {"-o <filename.tga>", "Sets the output file name"},
+ {"-random <N>", "Sets the randomized supersampling count (cannot be combined with `-samples`)"},
+ {"-samples <N>", "Sets the ordered supersampling count (cannot be combined with `-random`)"},
+ {"-sharpen <F>", "Sets the sharpening coefficient"},
+ {"-size <N>", "Sets the width and height of the output image"},
+ {"-white", "Write the minimap as a white-on-transparency RGBA32 image"},
+ };
+
+ HelpOptions("MiniMap", 0, 80, minimap, sizeof(minimap)/sizeof(struct HelpOption));
+}
+
+void HelpCommon()
+{
+ struct HelpOption common[] = {
+ {"-connect <address>", "Talk to a NetRadiant instance using a specific XML based protocol"},
+ {"-force", "Allow reading some broken/unsupported BSP files e.g. when decompiling, may also crash"},
+ {"-fs_basepath <path>", "Sets the given path as main directory of the game (can be used more than once to look in multiple paths)"},
+ {"-fs_game <gamename>", "Sets a different game directory name (default for Q3A: baseq3)"},
+ {"-fs_homebase <dir>", "Specifies where the user home directory name is on Linux (default for Q3A: .q3a)"},
+ {"-game <gamename>", "Load settings for the given game (default: quake3)"},
+ {"-subdivisions <F>", "multiplier for patch subdivisions quality"},
+ {"-threads <N>", "number of threads to use"},
+ {"-v", "Verbose mode"}
+ };
+
+ HelpOptions("Common Options", 0, 80, common, sizeof(common)/sizeof(struct HelpOption));
+
+}
+
+void Help(const char* arg)
+{
+ printf("Usage: q3map2 [stage] [common options...] [stage options...] [stage source file]\n");
+ printf(" q3map2 -help [stage]\n\n");
+
+ HelpCommon();
+
+ struct HelpOption stages[] = {
+ {"-bsp", "BSP Stage"},
+ {"-vis", "VIS Stage"},
+ {"-light", "Light Stage"},
+ {"-analize", "Analyzing BSP-like file structure"},
+ {"-scale", "Scaling"},
+ {"-convert", "Converting & Decompiling"},
+ {"-export", "Exporting lightmaps"},
+ {"-fixaas", "Fixing AAS checksum"},
+ {"-info", "Get info about BSP file"},
+ {"-import", "Importing lightmaps"},
+ {"-minimap", "MiniMap"},
+ };
+ void(*help_funcs[])() = {
+ HelpBsp,
+ HelpVis,
+ HelpLight,
+ HelpAnalize,
+ HelpScale,
+ HelpConvert,
+ HelpExport,
+ HelpFixaas,
+ HelpInfo,
+ HelpImport,
+ HelpMinimap
+ };
+
+ if ( arg && strlen(arg) > 0 )
+ {
+ if ( arg[0] == '-' )
+ arg++;
+
+ unsigned i;
+ for ( i = 0; i < sizeof(stages)/sizeof(struct HelpOption); i++ )
+ if ( strcmp(arg, stages[i].name+1) == 0 )
+ {
+ help_funcs[i]();
+ return;
+ }
+ }
+
+ HelpOptions("Stages", 0, 80, stages, sizeof(stages)/sizeof(struct HelpOption));
+}
/*
main()
/* read general options first */
for ( i = 1; i < argc; i++ )
{
+ /* -help */
+ if ( !strcmp( argv[ i ], "-h" ) || !strcmp( argv[ i ], "--help" )
+ || !strcmp( argv[ i ], "-help" ) ) {
+ Help(argv[i+1]);
+ return 0;
+ }
+
/* -connect */
if ( !strcmp( argv[ i ], "-connect" ) ) {
argv[ i ] = NULL;