Преглед изворни кода

Added PixelFormat.RGB32F, PixelFormat.RGBA32F and simple .hdr support.

Mark Sibly пре 7 година
родитељ
комит
844920ac12

+ 6 - 0
modules/bullet/bullet.monkey2

@@ -623,6 +623,12 @@ Class btHingeConstraint Extends btTypedConstraint="bbBullet::HingeConstraint"
 	Method getFrameOffsetA:btTransform()
 	Method getFrameOffsetA:btTransform()
 		
 		
 	Method getFrameOffsetB:btTransform()
 	Method getFrameOffsetB:btTransform()
+		
+	Method getLowerLimit:btScalar()
+		
+	Method getUpperLimit:btScalar()
+		
+	Method setLimit( low:btScalar,high:btScalar,_softness:btScalar=.9,_biasFactor:btScalar=.3,_relaxationFactor:btScalar=1.0 )
 End
 End
 
 
 Class btSliderConstraint Extends btTypedConstraint="bbBullet::SliderConstraint"
 Class btSliderConstraint Extends btTypedConstraint="bbBullet::SliderConstraint"

+ 22 - 66
modules/mojo/graphics/texture.monkey2

@@ -30,6 +30,7 @@ Function glInternalFormat:GLenum( format:PixelFormat )
 	Case PixelFormat.RGB8 Return GL_RGB
 	Case PixelFormat.RGB8 Return GL_RGB
 	Case PixelFormat.RGBA8 Return GL_RGBA
 	Case PixelFormat.RGBA8 Return GL_RGBA
 '	Case PixelFormat.RGBA16F Return GL_RGBA
 '	Case PixelFormat.RGBA16F Return GL_RGBA
+	Case PixelFormat.RGB32F Return BBGL_ES ? GL_RGB Else GL_RGB32F
 	Case PixelFormat.RGBA32F Return BBGL_ES ? GL_RGBA Else GL_RGBA32F
 	Case PixelFormat.RGBA32F Return BBGL_ES ? GL_RGBA Else GL_RGBA32F
 	Case PixelFormat.Depth32 Return GL_DEPTH_COMPONENT
 	Case PixelFormat.Depth32 Return GL_DEPTH_COMPONENT
 	End
 	End
@@ -45,6 +46,7 @@ Function glFormat:GLenum( format:PixelFormat )
 	Case PixelFormat.RGB8 Return GL_RGB
 	Case PixelFormat.RGB8 Return GL_RGB
 	Case PixelFormat.RGBA8 Return GL_RGBA
 	Case PixelFormat.RGBA8 Return GL_RGBA
 '	Case PixelFormat.RGBA16F Return GL_RGBA
 '	Case PixelFormat.RGBA16F Return GL_RGBA
+	Case PixelFormat.RGB32F Return GL_RGB
 	Case PixelFormat.RGBA32F Return GL_RGBA
 	Case PixelFormat.RGBA32F Return GL_RGBA
 	Case PixelFormat.Depth32 Return GL_DEPTH_COMPONENT
 	Case PixelFormat.Depth32 Return GL_DEPTH_COMPONENT
 	End
 	End
@@ -60,6 +62,7 @@ Function glType:GLenum( format:PixelFormat )
 	Case PixelFormat.RGB8 Return GL_UNSIGNED_BYTE
 	Case PixelFormat.RGB8 Return GL_UNSIGNED_BYTE
 	Case PixelFormat.RGBA8 Return GL_UNSIGNED_BYTE
 	Case PixelFormat.RGBA8 Return GL_UNSIGNED_BYTE
 '	Case PixelFormat.RGBA16F Return GL_HALF_FLOAT
 '	Case PixelFormat.RGBA16F Return GL_HALF_FLOAT
+	Case PixelFormat.RGB32F Return GL_FLOAT
 	Case PixelFormat.RGBA32F Return GL_FLOAT
 	Case PixelFormat.RGBA32F Return GL_FLOAT
 	Case PixelFormat.Depth32 Return GL_UNSIGNED_INT
 	Case PixelFormat.Depth32 Return GL_UNSIGNED_INT
 	End
 	End
@@ -93,60 +96,29 @@ Function ClearTexImage2D( glTarget:GLenum,width:Int,height:Int,format:PixelForma
 	glCheck()
 	glCheck()
 End
 End
 
 
-Function UploadTexImage2D( glTarget:GLenum,image:Pixmap,mipmap:Bool,envmap:Bool )
+Function UploadTexImage2D( glTarget:GLenum,image:Pixmap )
 	
 	
 	glCheck()
 	glCheck()
 	
 	
-	Local format:=image.Format
-	
-	If envmap Assert( format=PixelFormat.RGBA8 )
-	
+	Local width:=image.Width,height:=image.Height,format:=image.Format
+
 	Local gliformat:=glInternalFormat( format )
 	Local gliformat:=glInternalFormat( format )
 	Local glformat:=glFormat( format )
 	Local glformat:=glFormat( format )
 	Local gltype:=glType( format )
 	Local gltype:=glType( format )
-	
-	Local mip:=0
-	
-	Repeat
-		
-		Local width:=image.Width,height:=image.Height
 
 
-		If envmap
-			'write miplevel to alpha for envmaps
-			For Local y:=0 until height
-				Local p:=image.PixelPtr( 0,y )
-				For Local x:=0 Until width
-					p[x*4+3]=mip
-				Next
-			Next
-		Endif
-		
-		If image.Pitch=width * image.Depth
-			glTexImage2D( glTarget,mip,gliformat,width,height,0,glformat,gltype,image.Data )
-			glCheck()
-		Else
-			glTexImage2D( glTarget,mip,gliformat,width,height,0,glformat,gltype,Null )
+	If image.Pitch=width * image.Depth
+		glTexImage2D( glTarget,0,gliformat,width,height,0,glformat,gltype,image.Data )
+		glCheck()
+	Else
+		glTexImage2D( glTarget,0,gliformat,width,height,0,glformat,gltype,Null )
+		glCheck()
+		For Local y:=0 Until height
+			glTexSubImage2D( glTarget,0,0,y,width,1,glformat,gltype,image.PixelPtr( 0,y ) )
 			glCheck()
 			glCheck()
-			For Local y:=0 Until height
-				glTexSubImage2D( glTarget,mip,0,y,width,1,glformat,gltype,image.PixelPtr( 0,y ) )
-				glCheck()
-			Next
-		Endif
-		
-		glFlush() 'macos nvidia bug!
-		
-		If Not mipmap Or Not envmap Exit
-		
-		If width=1 And height=1 Exit
-		
-		image=image.MipHalve()
-		
-		mip+=1
-	Forever
-	
-	If mipmap And Not envmap glGenerateMipmap( glTarget )
+		Next
+	Endif
 	
 	
-	glCheck()
+	glFlush() 'macos nvidia bug!
 End
 End
 
 
 Public
 Public
@@ -173,11 +145,9 @@ Enum TextureFlags
 	
 	
 	Dynamic=		$0100
 	Dynamic=		$0100
 	Cubemap=		$0200
 	Cubemap=		$0200
-	Envmap=			$0400
 	
 	
 	WrapST=			WrapS|WrapT
 	WrapST=			WrapS|WrapT
 	FilterMipmap=	Filter|Mipmap
 	FilterMipmap=	Filter|Mipmap
-	CubeEnvmap=		Cubemap|Envmap
 End
 End
 
 
 #rem monketdoc @hidden
 #rem monketdoc @hidden
@@ -212,13 +182,6 @@ Class Texture Extends Resource
 		
 		
 		If flags & TextureFlags.Cubemap
 		If flags & TextureFlags.Cubemap
 
 
-			'Nasty: envmap mips need mip level in the alpha channel for env maps
-			'
-			'If flags & TextureFlags.Envmap And pixmap.Format<>PixelFormat.RGBA8
-			'	
-			'	pixmap=pixmap.Convert( PixelFormat.RGBA8 )
-			'Endif
-
 			Local size:=pixmap.Size
 			Local size:=pixmap.Size
 			
 			
 			If size.x=size.y			'1x1?
 			If size.x=size.y			'1x1?
@@ -336,8 +299,7 @@ Class Texture Extends Resource
 	Function Load:Texture( path:String,flags:TextureFlags=TextureFlags.FilterMipmap,flipNormalY:Bool=False )
 	Function Load:Texture( path:String,flags:TextureFlags=TextureFlags.FilterMipmap,flipNormalY:Bool=False )
 		
 		
 		Local format:=PixelFormat.Unknown
 		Local format:=PixelFormat.Unknown
-		If flags & TextureFlags.Envmap format=PixelFormat.RGBA8
-
+		
 		Local pixmap:=Pixmap.Load( path,format,True )
 		Local pixmap:=Pixmap.Load( path,format,True )
 		If Not pixmap Return Null
 		If Not pixmap Return Null
 		
 		
@@ -519,19 +481,13 @@ Class Texture Extends Resource
 		
 		
 		If _dirty & Dirty.TexImage
 		If _dirty & Dirty.TexImage
 			
 			
-			Local mipmap:=(_flags & TextureFlags.Mipmap)<>0
-				
-			Local envmap:=(_flags & TextureFlags.Envmap)<>0
-				
 			Select _glTarget
 			Select _glTarget
 			Case GL_TEXTURE_2D
 			Case GL_TEXTURE_2D
 				
 				
 				If _managed
 				If _managed
-					UploadTexImage2D( _glTarget,_managed,mipmap,envmap )
-					_dirty&=~Dirty.Mipmaps
+					UploadTexImage2D( _glTarget,_managed )
 				else
 				else
 					ClearTexImage2D( _glTarget,_size.x,_size.y,_format,Color.Black )
 					ClearTexImage2D( _glTarget,_size.x,_size.y,_format,Color.Black )
-					If mipmap _dirty|=Dirty.Mipmaps
 				Endif
 				Endif
 					
 					
 			Case GL_TEXTURE_CUBE_MAP
 			Case GL_TEXTURE_CUBE_MAP
@@ -539,18 +495,18 @@ Class Texture Extends Resource
 				If _cubeFaces[0]._managed
 				If _cubeFaces[0]._managed
 					For Local i:=0 Until 6
 					For Local i:=0 Until 6
 						Local face:=_cubeFaces[i]
 						Local face:=_cubeFaces[i]
-						UploadTexImage2D( face._glTarget,face._managed,mipmap,envmap )
+						UploadTexImage2D( face._glTarget,face._managed )
 					Next
 					Next
-					_dirty&=~Dirty.Mipmaps
 				Else
 				Else
 					For Local i:=0 Until 6
 					For Local i:=0 Until 6
 						Local face:=_cubeFaces[i]
 						Local face:=_cubeFaces[i]
 						ClearTexImage2D( face._glTarget,face._size.x,face._size.y,face._format,Color.Black )
 						ClearTexImage2D( face._glTarget,face._size.x,face._size.y,face._format,Color.Black )
 					Next
 					Next
-					If mipmap _dirty|=Dirty.Mipmaps
 				Endif
 				Endif
 			End
 			End
 			
 			
+			If _flags & TextureFlags.Mipmap _dirty|=Dirty.Mipmaps
+			
 		Endif
 		Endif
 		
 		
 		If _dirty & Dirty.Mipmaps
 		If _dirty & Dirty.Mipmaps

+ 8 - 0
modules/mojo3d/assets/shaders/imports/std.glsl

@@ -356,10 +356,14 @@ vec3 sampleEnv( vec3 viewVec,float roughness ){
 
 
 	if( r_EnvCube ){
 	if( r_EnvCube ){
 		
 		
+		return pow( textureCube( r_EnvTextureCube,tv,roughness*r_EnvTextureMaxLod ).rgb,vec3( 2.2 ) ) * r_EnvColor.rgb;
+		
+		/*
 		float lod=textureCube( r_EnvTextureCube,tv,r_EnvTextureMaxLod ).a * 255.0 - r_EnvTextureMaxLod;
 		float lod=textureCube( r_EnvTextureCube,tv,r_EnvTextureMaxLod ).a * 255.0 - r_EnvTextureMaxLod;
 		if( lod>0.0 ) lod=textureCube( r_EnvTextureCube,tv ).a * 255.0;
 		if( lod>0.0 ) lod=textureCube( r_EnvTextureCube,tv ).a * 255.0;
 	
 	
 		return pow( textureCube( r_EnvTextureCube,tv,max( roughness*r_EnvTextureMaxLod-lod,0.0 ) ).rgb,vec3( 2.2 ) ) * r_EnvColor.rgb;
 		return pow( textureCube( r_EnvTextureCube,tv,max( roughness*r_EnvTextureMaxLod-lod,0.0 ) ).rgb,vec3( 2.2 ) ) * r_EnvColor.rgb;
+		*/
 		
 		
 	}else{
 	}else{
 
 
@@ -368,10 +372,14 @@ vec3 sampleEnv( vec3 viewVec,float roughness ){
 		
 		
 		vec2 tc=vec2( y,p ) *0.5 + 0.5;
 		vec2 tc=vec2( y,p ) *0.5 + 0.5;
 
 
+		return pow( texture2D( r_EnvTexture2D,tc,roughness*r_EnvTextureMaxLod ).rgb,vec3( 2.2 ) ) * r_EnvColor.rgb;
+
+		/*
 		float lod=texture2D( r_EnvTexture2D,tc,r_EnvTextureMaxLod ).a * 255.0 - r_EnvTextureMaxLod;
 		float lod=texture2D( r_EnvTexture2D,tc,r_EnvTextureMaxLod ).a * 255.0 - r_EnvTextureMaxLod;
 		if( lod>0.0 ) lod=texture2D( r_EnvTexture2D,tc ).a * 255.0;
 		if( lod>0.0 ) lod=texture2D( r_EnvTexture2D,tc ).a * 255.0;
 	
 	
 		return pow( texture2D( r_EnvTexture2D,tc,max( roughness*r_EnvTextureMaxLod-lod,0.0 ) ).rgb,vec3( 2.2 ) ) * r_EnvColor.rgb;
 		return pow( texture2D( r_EnvTexture2D,tc,max( roughness*r_EnvTextureMaxLod-lod,0.0 ) ).rgb,vec3( 2.2 ) ) * r_EnvColor.rgb;
+		*/
 	}
 	}
 }
 }
 
 

+ 1 - 1
modules/mojo3d/render/renderer.monkey2

@@ -839,7 +839,7 @@ When a new renderer is created, the config setting `MOJO3D\_RENDERER` can be use
 		_gdevice.BindUniformBlock( _runiforms )
 		_gdevice.BindUniformBlock( _runiforms )
 		_gdevice.BindUniformBlock( _iuniforms )
 		_gdevice.BindUniformBlock( _iuniforms )
 		
 		
-		_defaultEnv=Texture.Load( "asset::textures/env_default.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap|TextureFlags.Envmap )
+		_defaultEnv=Texture.Load( "asset::textures/env_default.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap )
 		
 		
 		_skyboxShader=Shader.Open( "misc/skybox",ShaderDefs )
 		_skyboxShader=Shader.Open( "misc/skybox",ShaderDefs )
 
 

+ 1 - 1
modules/mojo3d/tests/pbrspheres.monkey2

@@ -30,7 +30,7 @@ Class MyWindow Extends Window
 		
 		
 		_scene=New Scene
 		_scene=New Scene
 		
 		
-		_scene.SkyTexture=Texture.Load( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap|TextureFlags.Envmap )
+		_scene.SkyTexture=Texture.Load( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap )
 		
 		
 		'create camera
 		'create camera
 		'
 		'

+ 1 - 1
modules/mojo3d/tests/sprites.monkey2

@@ -30,7 +30,7 @@ Class MyWindow Extends Window
 		
 		
 		_scene=New Scene( True )
 		_scene=New Scene( True )
 		
 		
-		_scene.SkyTexture=_scene.LoadTexture( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap~TextureFlags.Envmap )
+		_scene.SkyTexture=_scene.LoadTexture( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap )
 		_scene.FogColor=Color.Sky
 		_scene.FogColor=Color.Sky
 		_scene.FogNear=10
 		_scene.FogNear=10
 		_scene.FogFar=30
 		_scene.FogFar=30

+ 1 - 1
modules/mojo3d/tests/terrain.monkey2

@@ -75,7 +75,7 @@ Class MyWindow Extends Window
 	Method CreateScene()
 	Method CreateScene()
 
 
 		_scene=New Scene
 		_scene=New Scene
-		_scene.SkyTexture=Texture.Load( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap|TextureFlags.Envmap )
+		_scene.SkyTexture=Texture.Load( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap )
 		_scene.FogColor=New Color( .75,1,0 )*.25
 		_scene.FogColor=New Color( .75,1,0 )*.25
 		_scene.FogNear=75
 		_scene.FogNear=75
 		_scene.FogFar=100
 		_scene.FogFar=100

+ 1 - 1
modules/mojo3d/tests/water.monkey2

@@ -28,7 +28,7 @@ Class MyWindow Extends Window
 		
 		
 		_scene=New Scene
 		_scene=New Scene
 		
 		
-		_scene.SkyTexture=Texture.Load( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap|TextureFlags.Envmap )
+		_scene.SkyTexture=Texture.Load( "asset::miramar-skybox.jpg",TextureFlags.FilterMipmap|TextureFlags.Cubemap )
 		
 		
 		'create camera
 		'create camera
 		'
 		'

+ 27 - 1
modules/std/graphics/pixelformat.monkey2

@@ -31,6 +31,9 @@ Enum PixelFormat
 	Depth16
 	Depth16
 	Depth24
 	Depth24
 	Depth32
 	Depth32
+	
+	RGB16F
+	RGB32F
 
 
 	'deprecated
 	'deprecated
 	IA16=IA8
 	IA16=IA8
@@ -39,6 +42,27 @@ Enum PixelFormat
 
 
 End
 End
 
 
+Function IsAlphaPixelFormat:Bool( format:PixelFormat )
+	Select format
+	Case PixelFormat.A8,PixelFormat.IA8,PixelFormat.RGBA8,PixelFormat.RGBA16F,PixelFormat.RGBA32F Return True
+	End
+	Return False
+End
+
+Function IsDepthPixelFormat:Bool( format:PixelFormat )
+	Select format
+	Case PixelFormat.Depth16,PixelFormat.Depth24,PixelFormat.Depth32 Return True
+	End
+	Return False
+End
+
+Function IsFloatPixelFormat:Bool( format:PixelFormat )
+	Select format
+	Case PixelFormat.RGBA16F,PixelFormat.RGBA32F,PixelFormat.RGB16F,PixelFormat.RGB32F Return True
+	End
+	Return False
+End
+
 #rem monkeydoc Gets the number of bytes per pixel for a particular pixel format.
 #rem monkeydoc Gets the number of bytes per pixel for a particular pixel format.
 #end
 #end
 Function PixelFormatDepth:Int( format:PixelFormat )
 Function PixelFormatDepth:Int( format:PixelFormat )
@@ -54,6 +78,8 @@ Function PixelFormatDepth:Int( format:PixelFormat )
 	Case PixelFormat.Depth16 Return 2
 	Case PixelFormat.Depth16 Return 2
 	Case PixelFormat.Depth24 Return 4
 	Case PixelFormat.Depth24 Return 4
 	Case PixelFormat.Depth32 Return 4
 	Case PixelFormat.Depth32 Return 4
+	Case PixelFormat.RGB16F Return 6
+	Case PixelFormat.RGB32F Return 12
 		
 		
 	'deprecated
 	'deprecated
 	Case PixelFormat.IA16 Return 2
 	Case PixelFormat.IA16 Return 2
@@ -62,5 +88,5 @@ Function PixelFormatDepth:Int( format:PixelFormat )
 		
 		
 	End
 	End
 	
 	
-	Return PixelFormat.Unknown
+	Return 0
 End
 End

+ 58 - 20
modules/std/graphics/pixmap.monkey2

@@ -175,6 +175,17 @@ Class Pixmap Extends Resource
 			p[1]=color.g * 255
 			p[1]=color.g * 255
 			p[2]=color.b * 255
 			p[2]=color.b * 255
 			p[3]=color.a * 255
 			p[3]=color.a * 255
+		Case PixelFormat.RGB32F
+			Local fp:=Cast<Float Ptr>( p )
+			fp[0]=color.r
+			fp[1]=color.g
+			fp[2]=color.b
+		Case PixelFormat.RGBA32F
+			Local fp:=Cast<Float Ptr>( p )
+			fp[0]=color.r
+			fp[1]=color.g
+			fp[2]=color.b
+			fp[3]=color.a
 '		Default
 '		Default
 '			Assert( False )
 '			Assert( False )
 		End
 		End
@@ -210,6 +221,12 @@ Class Pixmap Extends Resource
 			Return New Color( p[0]/255.0,p[1]/255.0,p[2]/255.0,1 )
 			Return New Color( p[0]/255.0,p[1]/255.0,p[2]/255.0,1 )
 		Case PixelFormat.RGBA32
 		Case PixelFormat.RGBA32
 			Return New Color( p[0]/255.0,p[1]/255.0,p[2]/255.0,p[3]/255.0 )
 			Return New Color( p[0]/255.0,p[1]/255.0,p[2]/255.0,p[3]/255.0 )
+		Case PixelFormat.RGB32F
+			Local fp:=Cast<Float Ptr>( p )
+			Return New Color( fp[0],fp[1],fp[2] )
+		Case PixelFormat.RGBA32F
+			Local fp:=Cast<Float Ptr>( p )
+			Return New Color( fp[0],fp[1],fp[2],fp[3] )
 '		Default
 '		Default
 '			Assert( False )
 '			Assert( False )
 		End
 		End
@@ -250,6 +267,17 @@ Class Pixmap Extends Resource
 			p[1]=color Shr 8
 			p[1]=color Shr 8
 			p[2]=color
 			p[2]=color
 			p[3]=color Shr 24
 			p[3]=color Shr 24
+		Case PixelFormat.RGB32F
+			Local fp:=Cast<Float Ptr>( p )
+			fp[0]=((color Shr 16)&255)/255.0
+			fp[1]=((color Shr 8)&255)/255.0
+			fp[2]=(color&255)/255.0
+		Case PixelFormat.RGBA32F
+			Local fp:=Cast<Float Ptr>( p )
+			fp[0]=((color Shr 16)&255)/255.0
+			fp[1]=((color Shr 8)&255)/255.0
+			fp[2]=(color&255)/255.0
+			fp[3]=((color Shr 24)&255)/255.0
 		Default
 		Default
 			Assert( False )
 			Assert( False )
 		End
 		End
@@ -283,6 +311,12 @@ Class Pixmap Extends Resource
 			Return UByte($ff) Shl 24 | p[0] Shl 16 | p[1] Shl 8 | p[2]
 			Return UByte($ff) Shl 24 | p[0] Shl 16 | p[1] Shl 8 | p[2]
 		Case PixelFormat.RGBA32
 		Case PixelFormat.RGBA32
 			Return p[3] Shl 24 | p[0] Shl 16 | p[1] Shl 8 | p[2]
 			Return p[3] Shl 24 | p[0] Shl 16 | p[1] Shl 8 | p[2]
+		Case PixelFormat.RGB32F
+			Local fp:=Cast<Float Ptr>( p )
+			Return UInt($ff000000) | UInt(p[0]*255.0) Shl 16 | UInt(fp[1]*255.0) Shl 8 | UInt(fp[2]*255.0)
+		Case PixelFormat.RGBA32F
+			Local fp:=Cast<Float Ptr>( p )
+			Return UInt(fp[3]*255.0) Shl 24 | UInt(p[0]*255.0) Shl 16 | UInt(fp[1]*255.0) Shl 8 | UInt(fp[2]*255.0) 
 		Default
 		Default
 			Assert( False )
 			Assert( False )
 		End
 		End
@@ -298,7 +332,7 @@ Class Pixmap Extends Resource
 	
 	
 	#end
 	#end
 	Method Clear( color:Color )
 	Method Clear( color:Color )
-		
+
 		For Local y:=0 Until _height
 		For Local y:=0 Until _height
 			For Local x:=0 Until _width
 			For Local x:=0 Until _width
 				SetPixel( x,y,color )
 				SetPixel( x,y,color )
@@ -312,11 +346,9 @@ Class Pixmap Extends Resource
 	
 	
 	#end
 	#end
 	Method ClearARGB( color:UInt )
 	Method ClearARGB( color:UInt )
-		
+
 		For Local y:=0 Until _height
 		For Local y:=0 Until _height
-			
 			For Local x:=0 Until _width
 			For Local x:=0 Until _width
-				
 				SetPixelARGB( x,y,color )
 				SetPixelARGB( x,y,color )
 			Next
 			Next
 		Next
 		Next
@@ -328,16 +360,12 @@ Class Pixmap Extends Resource
 	
 	
 	#end
 	#end
 	Method Copy:Pixmap()
 	Method Copy:Pixmap()
-	
-		Local pitch:=Width * Depth
 		
 		
+		Local pitch:=Width * Depth
 		Local data:=Cast<UByte Ptr>( libc.malloc( pitch * Height ) )
 		Local data:=Cast<UByte Ptr>( libc.malloc( pitch * Height ) )
-		
 		For Local y:=0 Until Height
 		For Local y:=0 Until Height
-			
 			memcpy( data+y*pitch,PixelPtr( 0,y ),pitch )
 			memcpy( data+y*pitch,PixelPtr( 0,y ),pitch )
 		Next
 		Next
-		
 		Return New Pixmap( Width,Height,Format,data,pitch )
 		Return New Pixmap( Width,Height,Format,data,pitch )
 	End
 	End
 	
 	
@@ -355,12 +383,11 @@ Class Pixmap Extends Resource
 	
 	
 	#end
 	#end
 	Method Paste( pixmap:Pixmap,x:Int,y:Int )
 	Method Paste( pixmap:Pixmap,x:Int,y:Int )
+
 		DebugAssert( x>=0 And x+pixmap._width<=_width And y>=0 And y+pixmap._height<=_height )
 		DebugAssert( x>=0 And x+pixmap._width<=_width And y>=0 And y+pixmap._height<=_height )
 		
 		
 		For Local ty:=0 Until pixmap._height
 		For Local ty:=0 Until pixmap._height
-			
 			For Local tx:=0 Until pixmap._width
 			For Local tx:=0 Until pixmap._width
-				
 				SetPixel( x+tx,y+ty,pixmap.GetPixel( tx,ty ) )
 				SetPixel( x+tx,y+ty,pixmap.GetPixel( tx,ty ) )
 			Next
 			Next
 		Next
 		Next
@@ -379,13 +406,26 @@ Class Pixmap Extends Resource
 		
 		
 		Local t:=New Pixmap( _width,_height,format )
 		Local t:=New Pixmap( _width,_height,format )
 		
 		
-		For Local y:=0 Until _height
-			
-			For Local x:=0 Until _width
-				
-				t.SetPixel( x,y,GetPixel( x,y ) )
+		If IsFloatPixelFormat( _format ) And Not IsFloatPixelFormat( format )
+			For Local y:=0 Until _height
+				For Local x:=0 Until _width
+					Local c:=GetPixel( x,y )
+					c.r=Clamp( c.r,0.0,1.0 )
+					c.g=Clamp( c.g,0.0,1.0 )
+					c.b=Clamp( c.b,0.0,1.0 )
+					c.a=Clamp( c.a,0.0,1.0 )
+					t.SetPixel( x,y,c )
+				Next
 			Next
 			Next
-		Next
+		Else
+			For Local y:=0 Until _height
+				For Local x:=0 Until _width
+					t.SetPixel( x,y,GetPixel( x,y ) )
+				Next
+			Next
+		Endif
+		
+		
 		Return t
 		Return t
 	End
 	End
 	
 	
@@ -396,12 +436,10 @@ Class Pixmap Extends Resource
 	Method PremultiplyAlpha()
 	Method PremultiplyAlpha()
 		
 		
 		Select _format
 		Select _format
-		Case PixelFormat.IA16,PixelFormat.RGBA32
+		Case PixelFormat.IA16,PixelFormat.RGBA32,PixelFormat.RGBA16F,PixelFormat.RGBA32F
 			
 			
 			For Local y:=0 Until _height
 			For Local y:=0 Until _height
-				
 				For Local x:=0 Until _width
 				For Local x:=0 Until _width
-					
 					Local color:=GetPixel( x,y )
 					Local color:=GetPixel( x,y )
 					color.r*=color.a
 					color.r*=color.a
 					color.g*=color.a
 					color.g*=color.a

+ 37 - 1
modules/std/graphics/pixmaploader.monkey2

@@ -1,11 +1,22 @@
 
 
 Namespace std.graphics.pixmaploader
 Namespace std.graphics.pixmaploader
 
 
-Private
+#Import "rgbe/rgbe.c"
+#Import "rgbe/rgbe.h"
 
 
 Using stb.image
 Using stb.image
 Using std.stream
 Using std.stream
 
 
+Extern Private
+
+Struct rgbe_header_info
+End
+
+Function RGBE_ReadHeader:Int( fp:FILE Ptr,width:Int Ptr,height:Int Ptr,info:rgbe_header_info Ptr )
+Function RGBE_ReadPixels_RLE:Int( fp:FILE Ptr,data:Float Ptr,scanline_width:Int,num_scanlines:Int )
+
+Private
+
 Struct stbi_user
 Struct stbi_user
 	Field stream:Stream
 	Field stream:Stream
 End
 End
@@ -59,6 +70,31 @@ Public
 #rem monkeydoc @hidden
 #rem monkeydoc @hidden
 #end
 #end
 Function LoadPixmap:Pixmap( path:String,format:PixelFormat )
 Function LoadPixmap:Pixmap( path:String,format:PixelFormat )
+	
+	If ExtractExt( path )=".hdr"
+		path=RealPath( path )
+		
+		Local file:=libc.fopen( path,"rb" )
+		If Not file Return Null
+		
+		Local width:=0,height:=0
+		
+		If RGBE_ReadHeader( file,Varptr width,Varptr height,Null )<>0
+			libc.fclose( file )
+			Return Null
+		Endif
+		
+		Local pixmap:=New Pixmap( width,height,PixelFormat.RGB32F )
+	
+		RGBE_ReadPixels_RLE( file,Cast<Float Ptr>( pixmap.Data ),width,height )
+		
+		If format<>PixelFormat.Unknown And format<>PixelFormat.RGB32F
+			pixmap=pixmap.Convert( format )
+		Endif
+		
+		libc.fclose( file )
+		Return pixmap
+	Endif
 
 
 	Local x:Int,y:Int,comp:Int,req_comp:Int
 	Local x:Int,y:Int,comp:Int,req_comp:Int
 	
 	

+ 413 - 0
modules/std/graphics/rgbe/rgbe.c

@@ -0,0 +1,413 @@
+/* THIS CODE CARRIES NO GUARANTEE OF USABILITY OR FITNESS FOR ANY PURPOSE.
+ * WHILE THE AUTHORS HAVE TRIED TO ENSURE THE PROGRAM WORKS CORRECTLY,
+ * IT IS STRICTLY USE AT YOUR OWN RISK.  */
+
+#include "rgbe.h"
+#include <math.h>
+#include <malloc.h>
+#include <string.h>
+#include <ctype.h>
+
+/* This file contains code to read and write four byte rgbe file format
+ developed by Greg Ward.  It handles the conversions between rgbe and
+ pixels consisting of floats.  The data is assumed to be an array of floats.
+ By default there are three floats per pixel in the order red, green, blue.
+ (RGBE_DATA_??? values control this.)  Only the mimimal header reading and 
+ writing is implemented.  Each routine does error checking and will return
+ a status value as defined below.  This code is intended as a skeleton so
+ feel free to modify it to suit your needs.
+
+ (Place notice here if you modified the code.)
+ posted to http://www.graphics.cornell.edu/~bjw/
+ written by Bruce Walter  ([email protected])  5/26/95
+ based on code written by Greg Ward
+*/
+
+#ifdef _CPLUSPLUS
+/* define if your compiler understands inline commands */
+#define INLINE inline
+#else
+#define INLINE
+#endif
+
+/* offsets to red, green, and blue components in a data (float) pixel */
+#define RGBE_DATA_RED    0
+#define RGBE_DATA_GREEN  1
+#define RGBE_DATA_BLUE   2
+/* number of floats per pixel */
+#define RGBE_DATA_SIZE   3
+
+enum rgbe_error_codes {
+  rgbe_read_error,
+  rgbe_write_error,
+  rgbe_format_error,
+  rgbe_memory_error,
+};
+
+/* default error routine.  change this to change error handling */
+static int rgbe_error(int rgbe_error_code, char *msg)
+{
+  switch (rgbe_error_code) {
+  case rgbe_read_error:
+    perror("RGBE read error");
+    break;
+  case rgbe_write_error:
+    perror("RGBE write error");
+    break;
+  case rgbe_format_error:
+    fprintf(stderr,"RGBE bad file format: %s\n",msg);
+    break;
+  default:
+  case rgbe_memory_error:
+    fprintf(stderr,"RGBE error: %s\n",msg);
+  }
+  return RGBE_RETURN_FAILURE;
+}
+
+/* standard conversion from float pixels to rgbe pixels */
+/* note: you can remove the "inline"s if your compiler complains about it */
+static INLINE void 
+float2rgbe(unsigned char rgbe[4], float red, float green, float blue)
+{
+  float v;
+  int e;
+
+  v = red;
+  if (green > v) v = green;
+  if (blue > v) v = blue;
+  if (v < 1e-32) {
+    rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
+  }
+  else {
+    v = frexp(v,&e) * 256.0/v;
+    rgbe[0] = (unsigned char) (red * v);
+    rgbe[1] = (unsigned char) (green * v);
+    rgbe[2] = (unsigned char) (blue * v);
+    rgbe[3] = (unsigned char) (e + 128);
+  }
+}
+
+/* standard conversion from rgbe to float pixels */
+/* note: Ward uses ldexp(col+0.5,exp-(128+8)).  However we wanted pixels */
+/*       in the range [0,1] to map back into the range [0,1].            */
+static INLINE void 
+rgbe2float(float *red, float *green, float *blue, unsigned char rgbe[4])
+{
+  float f;
+
+  if (rgbe[3]) {   /*nonzero pixel*/
+    f = ldexp(1.0,rgbe[3]-(int)(128+8));
+    *red = rgbe[0] * f;
+    *green = rgbe[1] * f;
+    *blue = rgbe[2] * f;
+  }
+  else
+    *red = *green = *blue = 0.0;
+}
+
+/* default minimal header. modify if you want more information in header */
+int RGBE_WriteHeader(FILE *fp, int width, int height, rgbe_header_info *info)
+{
+  char *programtype = "RGBE";
+
+  if (info && (info->valid & RGBE_VALID_PROGRAMTYPE))
+    programtype = info->programtype;
+  if (fprintf(fp,"#?%s\n",programtype) < 0)
+    return rgbe_error(rgbe_write_error,NULL);
+  /* The #? is to identify file type, the programtype is optional. */
+  if (info && (info->valid & RGBE_VALID_GAMMA)) {
+    if (fprintf(fp,"GAMMA=%g\n",info->gamma) < 0)
+      return rgbe_error(rgbe_write_error,NULL);
+  }
+  if (info && (info->valid & RGBE_VALID_EXPOSURE)) {
+    if (fprintf(fp,"EXPOSURE=%g\n",info->exposure) < 0)
+      return rgbe_error(rgbe_write_error,NULL);
+  }
+  if (fprintf(fp,"FORMAT=32-bit_rle_rgbe\n\n") < 0)
+    return rgbe_error(rgbe_write_error,NULL);
+  if (fprintf(fp, "-Y %d +X %d\n", height, width) < 0)
+    return rgbe_error(rgbe_write_error,NULL);
+  return RGBE_RETURN_SUCCESS;
+}
+
+/* minimal header reading.  modify if you want to parse more information */
+int RGBE_ReadHeader(FILE *fp, int *width, int *height, rgbe_header_info *info)
+{
+  char buf[128];
+  int found_format;
+  float tempf;
+  int i;
+
+  found_format = 0;
+  if (info) {
+    info->valid = 0;
+    info->programtype[0] = 0;
+    info->gamma = info->exposure = 1.0;
+  }
+  if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == NULL)
+    return rgbe_error(rgbe_read_error,NULL);
+  if ((buf[0] != '#')||(buf[1] != '?')) {
+    /* if you want to require the magic token then uncomment the next line */
+    /*return rgbe_error(rgbe_format_error,"bad initial token"); */
+  }
+  else if (info) {
+    info->valid |= RGBE_VALID_PROGRAMTYPE;
+    for(i=0;i<sizeof(info->programtype)-1;i++) {
+      if ((buf[i+2] == 0) || isspace(buf[i+2]))
+	break;
+      info->programtype[i] = buf[i+2];
+    }
+    info->programtype[i] = 0;
+    if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
+      return rgbe_error(rgbe_read_error,NULL);
+  }
+  for(;;) {
+    if ((buf[0] == 0)||(buf[0] == '\n'))
+      return rgbe_error(rgbe_format_error,"no FORMAT specifier found");
+    else if (strcmp(buf,"FORMAT=32-bit_rle_rgbe\n") == 0)
+      break;       /* format found so break out of loop */
+    else if (info && (sscanf(buf,"GAMMA=%g",&tempf) == 1)) {
+      info->gamma = tempf;
+      info->valid |= RGBE_VALID_GAMMA;
+    }
+    else if (info && (sscanf(buf,"EXPOSURE=%g",&tempf) == 1)) {
+      info->exposure = tempf;
+      info->valid |= RGBE_VALID_EXPOSURE;
+    }
+    if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
+      return rgbe_error(rgbe_read_error,NULL);
+  }
+  if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
+    return rgbe_error(rgbe_read_error,NULL);
+  if (strcmp(buf,"\n") != 0)
+    return rgbe_error(rgbe_format_error,
+		      "missing blank line after FORMAT specifier");
+  if (fgets(buf,sizeof(buf)/sizeof(buf[0]),fp) == 0)
+    return rgbe_error(rgbe_read_error,NULL);
+  if (sscanf(buf,"-Y %d +X %d",height,width) < 2)
+    return rgbe_error(rgbe_format_error,"missing image size specifier");
+  return RGBE_RETURN_SUCCESS;
+}
+
+/* simple write routine that does not use run length encoding */
+/* These routines can be made faster by allocating a larger buffer and
+   fread-ing and fwrite-ing the data in larger chunks */
+int RGBE_WritePixels(FILE *fp, float *data, int numpixels)
+{
+  unsigned char rgbe[4];
+
+  while (numpixels-- > 0) {
+    float2rgbe(rgbe,data[RGBE_DATA_RED],
+	       data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
+    data += RGBE_DATA_SIZE;
+    if (fwrite(rgbe, sizeof(rgbe), 1, fp) < 1)
+      return rgbe_error(rgbe_write_error,NULL);
+  }
+  return RGBE_RETURN_SUCCESS;
+}
+
+/* simple read routine.  will not correctly handle run length encoding */
+int RGBE_ReadPixels(FILE *fp, float *data, int numpixels)
+{
+  unsigned char rgbe[4];
+
+  while(numpixels-- > 0) {
+    if (fread(rgbe, sizeof(rgbe), 1, fp) < 1)
+      return rgbe_error(rgbe_read_error,NULL);
+    rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],
+	       &data[RGBE_DATA_BLUE],rgbe);
+    data += RGBE_DATA_SIZE;
+  }
+  return RGBE_RETURN_SUCCESS;
+}
+
+/* The code below is only needed for the run-length encoded files. */
+/* Run length encoding adds considerable complexity but does */
+/* save some space.  For each scanline, each channel (r,g,b,e) is */
+/* encoded separately for better compression. */
+
+static int RGBE_WriteBytes_RLE(FILE *fp, unsigned char *data, int numbytes)
+{
+#define MINRUNLENGTH 4
+  int cur, beg_run, run_count, old_run_count, nonrun_count;
+  unsigned char buf[2];
+
+  cur = 0;
+  while(cur < numbytes) {
+    beg_run = cur;
+    /* find next run of length at least 4 if one exists */
+    run_count = old_run_count = 0;
+    while((run_count < MINRUNLENGTH) && (beg_run < numbytes)) {
+      beg_run += run_count;
+      old_run_count = run_count;
+      run_count = 1;
+      while( (beg_run + run_count < numbytes) && (run_count < 127)
+             && (data[beg_run] == data[beg_run + run_count]))
+	run_count++;
+    }
+    /* if data before next big run is a short run then write it as such */
+    if ((old_run_count > 1)&&(old_run_count == beg_run - cur)) {
+      buf[0] = 128 + old_run_count;   /*write short run*/
+      buf[1] = data[cur];
+      if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1)
+	return rgbe_error(rgbe_write_error,NULL);
+      cur = beg_run;
+    }
+    /* write out bytes until we reach the start of the next run */
+    while(cur < beg_run) {
+      nonrun_count = beg_run - cur;
+      if (nonrun_count > 128) 
+	nonrun_count = 128;
+      buf[0] = nonrun_count;
+      if (fwrite(buf,sizeof(buf[0]),1,fp) < 1)
+	return rgbe_error(rgbe_write_error,NULL);
+      if (fwrite(&data[cur],sizeof(data[0])*nonrun_count,1,fp) < 1)
+	return rgbe_error(rgbe_write_error,NULL);
+      cur += nonrun_count;
+    }
+    /* write out next run if one was found */
+    if (run_count >= MINRUNLENGTH) {
+      buf[0] = 128 + run_count;
+      buf[1] = data[beg_run];
+      if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1)
+	return rgbe_error(rgbe_write_error,NULL);
+      cur += run_count;
+    }
+  }
+  return RGBE_RETURN_SUCCESS;
+#undef MINRUNLENGTH
+}
+
+int RGBE_WritePixels_RLE(FILE *fp, float *data, int scanline_width,
+			 int num_scanlines)
+{
+  unsigned char rgbe[4];
+  unsigned char *buffer;
+  int i, err;
+
+  if ((scanline_width < 8)||(scanline_width > 0x7fff))
+    /* run length encoding is not allowed so write flat*/
+    return RGBE_WritePixels(fp,data,scanline_width*num_scanlines);
+  buffer = (unsigned char *)malloc(sizeof(unsigned char)*4*scanline_width);
+  if (buffer == NULL) 
+    /* no buffer space so write flat */
+    return RGBE_WritePixels(fp,data,scanline_width*num_scanlines);
+  while(num_scanlines-- > 0) {
+    rgbe[0] = 2;
+    rgbe[1] = 2;
+    rgbe[2] = scanline_width >> 8;
+    rgbe[3] = scanline_width & 0xFF;
+    if (fwrite(rgbe, sizeof(rgbe), 1, fp) < 1) {
+      free(buffer);
+      return rgbe_error(rgbe_write_error,NULL);
+    }
+    for(i=0;i<scanline_width;i++) {
+      float2rgbe(rgbe,data[RGBE_DATA_RED],
+		 data[RGBE_DATA_GREEN],data[RGBE_DATA_BLUE]);
+      buffer[i] = rgbe[0];
+      buffer[i+scanline_width] = rgbe[1];
+      buffer[i+2*scanline_width] = rgbe[2];
+      buffer[i+3*scanline_width] = rgbe[3];
+      data += RGBE_DATA_SIZE;
+    }
+    /* write out each of the four channels separately run length encoded */
+    /* first red, then green, then blue, then exponent */
+    for(i=0;i<4;i++) {
+      if ((err = RGBE_WriteBytes_RLE(fp,&buffer[i*scanline_width],
+				     scanline_width)) != RGBE_RETURN_SUCCESS) {
+	free(buffer);
+	return err;
+      }
+    }
+  }
+  free(buffer);
+  return RGBE_RETURN_SUCCESS;
+}
+      
+int RGBE_ReadPixels_RLE(FILE *fp, float *data, int scanline_width,
+			int num_scanlines)
+{
+  unsigned char rgbe[4], *scanline_buffer, *ptr, *ptr_end;
+  int i, count;
+  unsigned char buf[2];
+
+  if ((scanline_width < 8)||(scanline_width > 0x7fff))
+    /* run length encoding is not allowed so read flat*/
+    return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines);
+  scanline_buffer = NULL;
+  /* read in each successive scanline */
+  while(num_scanlines > 0) {
+    if (fread(rgbe,sizeof(rgbe),1,fp) < 1) {
+      free(scanline_buffer);
+      return rgbe_error(rgbe_read_error,NULL);
+    }
+    if ((rgbe[0] != 2)||(rgbe[1] != 2)||(rgbe[2] & 0x80)) {
+      /* this file is not run length encoded */
+      rgbe2float(&data[0],&data[1],&data[2],rgbe);
+      data += RGBE_DATA_SIZE;
+      free(scanline_buffer);
+      return RGBE_ReadPixels(fp,data,scanline_width*num_scanlines-1);
+    }
+    if ((((int)rgbe[2])<<8 | rgbe[3]) != scanline_width) {
+      free(scanline_buffer);
+      return rgbe_error(rgbe_format_error,"wrong scanline width");
+    }
+    if (scanline_buffer == NULL)
+      scanline_buffer = (unsigned char *)
+	malloc(sizeof(unsigned char)*4*scanline_width);
+    if (scanline_buffer == NULL) 
+      return rgbe_error(rgbe_memory_error,"unable to allocate buffer space");
+    
+    ptr = &scanline_buffer[0];
+    /* read each of the four channels for the scanline into the buffer */
+    for(i=0;i<4;i++) {
+      ptr_end = &scanline_buffer[(i+1)*scanline_width];
+      while(ptr < ptr_end) {
+	if (fread(buf,sizeof(buf[0])*2,1,fp) < 1) {
+	  free(scanline_buffer);
+	  return rgbe_error(rgbe_read_error,NULL);
+	}
+	if (buf[0] > 128) {
+	  /* a run of the same value */
+	  count = buf[0]-128;
+	  if ((count == 0)||(count > ptr_end - ptr)) {
+	    free(scanline_buffer);
+	    return rgbe_error(rgbe_format_error,"bad scanline data");
+	  }
+	  while(count-- > 0)
+	    *ptr++ = buf[1];
+	}
+	else {
+	  /* a non-run */
+	  count = buf[0];
+	  if ((count == 0)||(count > ptr_end - ptr)) {
+	    free(scanline_buffer);
+	    return rgbe_error(rgbe_format_error,"bad scanline data");
+	  }
+	  *ptr++ = buf[1];
+	  if (--count > 0) {
+	    if (fread(ptr,sizeof(*ptr)*count,1,fp) < 1) {
+	      free(scanline_buffer);
+	      return rgbe_error(rgbe_read_error,NULL);
+	    }
+	    ptr += count;
+	  }
+	}
+      }
+    }
+    /* now convert data from buffer into floats */
+    for(i=0;i<scanline_width;i++) {
+      rgbe[0] = scanline_buffer[i];
+      rgbe[1] = scanline_buffer[i+scanline_width];
+      rgbe[2] = scanline_buffer[i+2*scanline_width];
+      rgbe[3] = scanline_buffer[i+3*scanline_width];
+      rgbe2float(&data[RGBE_DATA_RED],&data[RGBE_DATA_GREEN],
+		 &data[RGBE_DATA_BLUE],rgbe);
+      data += RGBE_DATA_SIZE;
+    }
+    num_scanlines--;
+  }
+  free(scanline_buffer);
+  return RGBE_RETURN_SUCCESS;
+}
+

+ 61 - 0
modules/std/graphics/rgbe/rgbe.h

@@ -0,0 +1,61 @@
+#ifndef _H_RGBE
+#define _H_RGBE
+/* THIS CODE CARRIES NO GUARANTEE OF USABILITY OR FITNESS FOR ANY PURPOSE.
+ * WHILE THE AUTHORS HAVE TRIED TO ENSURE THE PROGRAM WORKS CORRECTLY,
+ * IT IS STRICTLY USE AT YOUR OWN RISK.  */
+
+/* utility for reading and writing Ward's rgbe image format.
+   See rgbe.txt file for more details.
+*/
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+typedef struct {
+  int valid;            /* indicate which fields are valid */
+  char programtype[16]; /* listed at beginning of file to identify it 
+                         * after "#?".  defaults to "RGBE" */ 
+  float gamma;          /* image has already been gamma corrected with 
+                         * given gamma.  defaults to 1.0 (no correction) */
+  float exposure;       /* a value of 1.0 in an image corresponds to
+			 * <exposure> watts/steradian/m^2. 
+			 * defaults to 1.0 */
+} rgbe_header_info;
+
+/* flags indicating which fields in an rgbe_header_info are valid */
+#define RGBE_VALID_PROGRAMTYPE 0x01
+#define RGBE_VALID_GAMMA       0x02
+#define RGBE_VALID_EXPOSURE    0x04
+
+/* return codes for rgbe routines */
+#define RGBE_RETURN_SUCCESS 0
+#define RGBE_RETURN_FAILURE -1
+
+/* read or write headers */
+/* you may set rgbe_header_info to null if you want to */
+int RGBE_WriteHeader(FILE *fp, int width, int height, rgbe_header_info *info);
+int RGBE_ReadHeader(FILE *fp, int *width, int *height, rgbe_header_info *info);
+
+/* read or write pixels */
+/* can read or write pixels in chunks of any size including single pixels*/
+int RGBE_WritePixels(FILE *fp, float *data, int numpixels);
+int RGBE_ReadPixels(FILE *fp, float *data, int numpixels);
+
+/* read or write run length encoded files */
+/* must be called to read or write whole scanlines */
+int RGBE_WritePixels_RLE(FILE *fp, float *data, int scanline_width,
+			 int num_scanlines);
+int RGBE_ReadPixels_RLE(FILE *fp, float *data, int scanline_width,
+			int num_scanlines);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _H_RGBE */
+
+
+

+ 61 - 0
modules/std/graphics/rgbe/rgbe.txt

@@ -0,0 +1,61 @@
+<HTML>
+The rgbe image file format was invented by Greg Ward to reduce the precision
+problems inherent in normal 24bit file formats.  Many programs including
+photorealistic renderers produce pixels with a wide range of values.  
+Internally the programs usually handle this by representing colors by
+floating point values.  However writing out the floating point values
+directly would produce very large files (~96 bits/pixel).  The rgbe format
+works by having all channels (typically red, green, and blue) share a single
+exponent.  Thus a pixel consists of three 8 bit mantissas and an 8 bit
+exponent for 32 bits per pixel.  This makes for a compact format which
+can handle wide range of pixels values (from 0 to 2^127) with reasonable
+precision.  See "Real Pixels" by Greg Ward in Graphics Gems II for more
+details.
+
+This code was written based on Greg Ward's code (available from the
+radiance home page ftp://radsite.lbl.gov/home.html) for reading and
+writing rgbe files.  I have rewritten the code as ANSI C and tried to
+clean up the code and comment it to make it easier to understand.  I've
+also tried to make the error detection a little more robust.  Here's the
+minimal code for using these files.
+
+sample minimal writing code:
+  f = fopen(image_filename,"wb");
+  RGBE_WriteHeader(f,image_width,image_height,NULL);
+  RGBE_WritePixels(f,image,image_width*image_height);
+  fclose(f);
+For run length encoding instead of RGBE_WritePixels, use 
+RGBE_WritePixels_RLE(f,image,image_width,image_height).
+
+sample minimal reading code:
+  f = fopen(image_filename,"rb");
+  RGBE_ReadHeader(f,&image_width,&image_height,NULL);
+  image = (float *)malloc(sizeof(float)*3*image_width*image_height);
+  RGBE_ReadPixels_RLE(f,image,image_width,image_height);
+  fclose(f);
+You can use RGBE_Read_Pixels instead but it will not handle run length
+encoded file correctly.  For more information see the rgbe.c file.
+(Note: these files are available at http://www.graphics.cornell.edu/~bjw/ )
+
+Please note: By definition of the rgbe format, all pixels should be in 
+units of watts/steradian/meter^2 unless otherwise noted in the header.
+If the header contains an exposure field then dividing pixels values by
+the <exposure value> should result in values in watts/steradian/meter^2.
+See the rgbe.h file for other fields in the header which are supported.
+
+The ReadPixels and WritePixels routines can read/write and entire image, or
+a single pixel, or anything in between.  The run length encoding routines
+can only handle complete scanlines, but can handle single scanlines.  No
+checking is done to see that an image contains the correct number of pixels.
+
+The return codes for routines are defined by RGBE_RETURN_SUCCESS and
+RGBE_RETURN_FAILURE and these can be modified to be compatible with whatever
+error convention you are using.  Error reporting is handled by the rgbe_error
+routine.  You can easily modify this if you want errors to be reported 
+somewhere other than STDERR.
+
+/* THIS CODE CARRIES NO GUARANTEE OF USABILITY OR FITNESS FOR ANY PURPOSE.
+ * WHILE THE AUTHORS HAVE TRIED TO ENSURE THE PROGRAM WORKS CORRECTLY,
+ * IT IS STRICTLY USE AT YOUR OWN RISK.  */
+</HTML>
+