How to change textures in OpenGL using Haskell - opengl

I'm stuck trying to get multiple textures working in OpenGL using Haskell. I've been following the NeHe tuts and some various other OpenGL resources online, but the combination of slightly different calls and my newbness has caused a roadblock.
To be specific I want to render two cubes, each with a different texture (same texture for all 6 faces for the time being). Rendering one cube, with a texture is fine. Rendering multiple cubes of the same texture works fine as well. But I've not been able to figure out how to change textures for the two cubes
If I'm not mistaken the call to change textures is:
textureBinding $ Texture2D $= Just *mytexture*
where mytexture is supposed to be some form of textureID (a TextureObject). What the heck goes into the mytexture spot? This should be really easy but I've spent the better part of 2 days trying to figure this out to no avail. Any help is appreciated.
Main:
-- imports --
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT
import Data.IORef
import Display
import Bindings
import Control.Monad
import Textures
-- main --
main = do
(program, _) <- getArgsAndInitialize -- convenience, return program name and non-GLUT commands
initialDisplayMode $= [DoubleBuffered, WithDepthBuffer] -- inital display mode
initialWindowSize $= Size 600 600
createWindow "OpenGL Basics"
reshapeCallback $= Just reshape
angle <- newIORef (0.1::GLfloat) -- linked to angle of rotation (speed?)
delta <- newIORef (0.1::GLfloat)
position <- newIORef (0.0::GLfloat, 0.0) -- position, pass to display
texture Texture2D $= Enabled
tex <- getAndCreateTextures ["goldblock","pumpkintop"]
keyboardMouseCallback $= Just (keyboardMouse delta position) --require keys, delta, and position
idleCallback $= Just (idle angle delta) --ref idle angle and delta
displayCallback $= (display angle position tex) --ref display angle and delta
cullFace $= Just Front
mainLoop -- runs forever until a hard exit is called
In Main I call getAndCreateTextures (borrowed from the net), which returns a list of texture objects.
Display (for rendering):
-- display (main) --
display angle position tex = do
clear [ColorBuffer, DepthBuffer]
loadIdentity --modelview
shadeModel $= Smooth
(x,z) <- get position --get current position from init or keys
translate $ Vector3 x 0 z -- move to the position before drawing stuff
-- DO STUFF HERE
-- texture $ Texture2D $= Just wtfgoeshere
preservingMatrix $ do
a <- get angle
rotate a $ Vector3 (1::GLfloat) 0 0
-- rotate a $ Vector3 0 0 (1::GLfloat)
rotate a $ Vector3 0 (1::GLfloat) 0
-- scale 0.7 0.7 (0.7::GLfloat)
-- color $ Color3 (0.5::GLfloat) (0.1::GLfloat) (0.1::GLfloat)
cubeTexture (0.1::GLfloat)
swapBuffers
--idle (main)
idle angle delta = do
a <- get angle -- get existing angle
d <- get delta -- get delta
angle $= a + d -- new angle is old angle plus plus delta
postRedisplay Nothing

getAndCreateTextures is almost certainly doing what you need. The function of that name I found on the web has type IO [Maybe TextureObject], those are the TextureObject values you need. So you could do,
[gtex, ptex] <- getAndCreateTextures ["goldblock","pumpkintop"]
textureBinding Texture2D $= gtex
for example.

You pass the texture object. getAndCreateTextures seemingly gives you a list of texture objects. You pass one of those to the binding, like
textureBinding $ Texture2D $= Just tex[0]

Related

GeoDjango: How to create a circle anywhere on earth based on point and radius?

I have a similar question to this one. Using geodjango, I want to draw a circle on a map with a certain radius in km. However, the suggested solution
a) does not use km but instead degrees, and
b) becomes an oval further north or south.
Here is what I do:
from django.contrib.gis import geos
lat = 49.17
lng = -123.96
center = geos.Point(lng, lat)
radius = 0.01
circle = center.buffer(radius)
# And I then use folium to show a map on-screen:
map = folium.Map(
location=[lat,lng],
zoom_start=14,
attr="Mapbox"
)
folium.GeoJson(
circle.geojson,
name="geojson",
).add_to(map)
The result is this:
How can I
a) draw a circle that is always 3 km in radius, independent from the position on the globe, and
b) ensure this is a circle and not an oval at all latitudes?
Here is the Code
from django.contrib.gis import geos
import folium
lat = 49.17
lng = -123.96
center = geos.Point(x=lng, y=lat, srid=4326)
center.transform(3857) # Transform Projection to Web Mercator
radius = 3000 # now you can use meters
circle = center.buffer(radius)
circle.transform(4326) # Transform back to WGS84 to create geojson
# And I then use folium to show a map on-screen:
map = folium.Map(
location=[lat,lng],
zoom_start=14,
attr="Mapbox"
)
geojson = folium.GeoJson(
circle.geojson,
name="geojson",
)
geojson.add_to(map)
Explanation
This problem occurs due to Map Projections.
Lat/Long Coordinates are represented by the Map Projection WGS84. The Values are in degrees.
The map you see in folium has another map projection (Web Mercator). It tries to represent the world as a plane, which produces distortions to the north and south. The coordinate values are in meters.
On a globe your created circle would look completely round, but because folium uses another projection it gets distorted.
It is also important to know that every projection is represented by a number (EPSG Code). With this epsg codes, you can transform your coordinates from one projection into another.
Web Mercator -> EPSG 3857
WGS84 -> EPSG 4326
With my Code you now get a round circle in folium for Web Mercator, but be aware that it would look oval and distorted, when looking at it on a globe.
This is just a very easy explanation. You might have a look at Map Projections to better understand the problem.
This guide gives a good overview:
Map Projections
try this
folium.Circle(
radius=3000,
location=[lat,lng],
popup="Whatever name",
color="#3186cc",
fill=True,
fill_color="#3186cc",
).add_to(m)

Pygame - Is it possible to create everything in one surface and scale it down to display surface?

I wish to draw a few circles of large radius on the screen using pygame. I would like to define a surface called surface1 larger than my display surface (screen) and plot my circles in the actual dimension. Once I do that I am planning to rescale surface1 and display it on screen. Here is my code:
import pygame
pygame.init()
live = True
while live:
surface1 = pygame.Surface((7680, 4320))
screen = pygame.display.set_mode((1280, 720))
# pygame.display.flip()
surface1.fill((255, 255, 255))
pygame.draw.circle(surface1, (0, 0, 0), (3839, 2160), 4500, 10)
surface1 = pygame.transform.scale(surface1, (1280, 720))
surface1.convert()
screen.blit(surface1, (0, 0))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
live = False
For some reason I can't see the circle. However, the color of the displayed window changes according to what I set inside surface1. Why is this behaving that way? Any help would be appreciated. Thanks in advance.
The circle is bigger than the big surface. The pos argument is the center of the circle and the radius is larger than half of both the width and the height. Try to draw something smaller.
Also, manipulating such a huge surface will result in very poor performance.

GNUPLOT: draw a circle and letters in histogram

i want to draw a circle in an histogram with a radius equal to one and origin in x=0 and y=0. Also i want to draw a point and a letter in a particular position: x=0.5 and y=0.86 and a letter 'L_4' near the same position. Is it possible?
Here my code:
clear
reset
# wxt
#set terminal wxt size 350,262 enhanced font 'Verdana,10' persist
# png
set terminal pngcairo size 500,500 enhanced font 'Verdana,10'
set output 'Err_rev3bp.png'
set title "\n"
set label 1 "Reversibility Error\n 3bp mu=0.001" at graph 0.5,1.15 center
set view map
set xlabel 'x_0'
set xrange [*:*]
set ylabel 'y_0'
set yrange [*:*]
#set logscale z
set zlabel 'Err'
set border linewidth 1.0
set key outside
set pm3d at b
set dgrid 100,100
splot 'trecorpi.txt' w pm3d notitle
exit
I use the following command:
set object 10 circle at 0,0 size 1,1 fc rgb "red"
But i can't see the circle.
Thanks
You can't see a circle because you are using splot, which renders 3D plots. Circle is a 2D object and only compatible with plot command instead. There is a polygon object that is compatible with splot, but it seems there is no sphere object available.
set object 1 polygon from 0,0,0 to 1,1,10 to 2,0,0
set object 1 fc rgb "cyan" fillstyle solid 1.0 border lt -1
splot x

New StdGen for each OpenGL/GLUT loop iteration

I have a program that displays a bunch of random triangles using Haskell, OpenGL, and GLUT. However I'd like the random triangles to change every time I click, or something of that nature (not important when they change).
Currently my working code looks like this:
main :: IO ()
main = do
(pname, _) <- getArgsAndInitialize
createWindow $ "Haskellisa"
-- TODO set based on command line args
windowSize $= (Size 640 480)
blend $= Enabled
blendFunc $= (SrcAlpha, OneMinusSrcAlpha)
displayCallback $= display
keyboardMouseCallback $= Just (keyboardMouse)
mainLoop
display :: IO ()
display = do
clear [ ColorBuffer ]
gen0 <- getStdGen
let (tris,gen1) = randomTris 10 gen0
let (cols,gen2) = randomColor4s 10 gen1
let triColPairs = zip tris cols
mapM_ (\(tri, col) -> drawTri tri col) triColPairs
flush
However display takes the same StdGen every time by calling getStdGen. What I'd like is for the gen2 from the line let (cols,gen2)... to be used as the generator for the next time, but obviously that requires some sort of mutable state or something of that nature.
What's the best way to do what I'm asking, such that I will get different randomness every time display runs?
Since you're in IO anyway, you could just store gen2 via setStdGen:
setStdGen gen2
so your next round takes off where your previous stopped.
Another option is to split the StdGen and use one of the results using newStdGen instead of getStdGen.

How to use lighting values from 3ds max in OpenGL

I'm struggling to see how I should use material and lighting values obtained from 3DS Max to recreate similar lighting. I am taking the material and lighting from a Collada file exported from 3DS Max and using them to render a scene in OpenGL. The scene is rendered using a Blinn-Phong shader. However the scene always ends up way to bright.
The light data from 3DS max seems quite odd to me. It consists of two lights, an ambient light and a directional light which only has a single colour. As I was not quite sure what this single colour relates to I've applied it to both the diffuse and specular components of the light.
Anyways, does anyone know if there is something odd with the 3DS Max/Collada material and lighting data? Or have you used it successfully with no problems meaning that I'm simply doing something wrong?
Edit #1
As requested, heres the material/lighting info from collada. I'm afraid I cannot post any screenshots, however the scene is coming out painfully bright, e.g Oranges becoming bright yellow. The specular values in particular seem very high, yet they seem to work fine in Max...
Collada Material:
<library_effects>
<effect id="WorldTexture">
<profile_COMMON>
<newparam sid="world_texture_png-surface">
<surface type="2D">
<init_from>world_texture_png</init_from>
</surface>
</newparam>
<newparam sid="world_texture_png-sampler">
<sampler2D>
<source>world_texture_png-surface</source>
</sampler2D>
</newparam>
<technique sid="common">
<blinn>
<emission>
<color>0 0 0 1</color>
</emission>
<ambient>
<color>0.588 0.588 0.588 1</color>
</ambient>
<diffuse>
<texture texture="world_texture_png-sampler" texcoord="CHANNEL1"/>
</diffuse>
<specular>
<color>0.9 0.9 0.9 1</color>
</specular>
<shininess>
<float>10</float>
</shininess>
<reflective>
<color>0 0 0 1</color>
</reflective>
<transparent opaque="A_ONE">
<color>1 1 1 1</color>
</transparent>
<transparency>
<float>1</float>
</transparency>
</blinn>
</technique>
</profile_COMMON>
<extra>
<technique profile="OpenCOLLADA3dsMax">
<extended_shader>
<apply_reflection_dimming>0</apply_reflection_dimming>
<dim_level>0</dim_level>
<falloff_type>0</falloff_type>
<index_of_refraction>1.5</index_of_refraction>
<opacity_type>0</opacity_type>
<reflection_level>3</reflection_level>
<wire_size>1</wire_size>
<wire_units>0</wire_units>
</extended_shader>
<shader>
<ambient_diffuse_lock>1</ambient_diffuse_lock>
<ambient_diffuse_texture_lock>1</ambient_diffuse_texture_lock>
<diffuse_specular_lock>0</diffuse_specular_lock>
<soften>0.1</soften>
<use_self_illum_color>0</use_self_illum_color>
</shader>
</technique>
</extra>
</effect>
Collada Lights:
<library_lights>
<light id="EnvironmentAmbientLight" name="EnvironmentAmbientLight">
<technique_common>
<ambient>
<color>0.6235294 0.6235294 0.6235294</color>
</ambient>
</technique_common>
</light>
<light id="FDirect001-light" name="FDirect001">
<technique_common>
<directional>
<color>0.937255 0.7921569 0.5411765</color>
</directional>
</technique_common>
<extra>
<technique profile="OpenCOLLADA3dsMax">
<max_light>
<aspect_ratio>1</aspect_ratio>
<atmosphere_color_amount>1</atmosphere_color_amount>
<atmosphere_on>0</atmosphere_on>
<atmosphere_opacity>1</atmosphere_opacity>
<attenuation_far_end>100</attenuation_far_end>
<attenuation_far_start>80</attenuation_far_start>
<attenuation_near_end>26.8</attenuation_near_end>
<attenuation_near_start>0</attenuation_near_start>
<contrast>0</contrast>
<decay_falloff>40</decay_falloff>
<decay_type>0</decay_type>
<diffuse_soften>0</diffuse_soften>
<falloff>902</falloff>
<hotspot_beam>900</hotspot_beam>
<multiplier>0.5</multiplier>
<overshoot>0</overshoot>
<shadow_density>1</shadow_density>
<shadow_map>0</shadow_map>
<target_distance>440</target_distance>
<use_far_attenuation>0</use_far_attenuation>
<use_near_attenuation>0</use_near_attenuation>
</max_light>
</technique>
</extra>
</light>
</library_lights>