essytas 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README +3 -0
- data/Rakefile +44 -0
- data/bin/essytas +2 -0
- data/lib/animation.rb +74 -0
- data/lib/config.rb +63 -0
- data/lib/core.rb +242 -0
- data/lib/cursor.rb +43 -0
- data/lib/def/animations/explosion1.anim +103 -0
- data/lib/def/characters.def +132 -0
- data/lib/def/de/dialogues/test.dlg +4 -0
- data/lib/def/de/enemies.trans +6 -0
- data/lib/def/de/items.trans +84 -0
- data/lib/def/de/skills.trans +48 -0
- data/lib/def/de/spells.trans +31 -0
- data/lib/def/en/dialogues/test.dlg +4 -0
- data/lib/def/en/enemies.trans +6 -0
- data/lib/def/en/items.trans +78 -0
- data/lib/def/en/skills.trans +48 -0
- data/lib/def/en/spells.trans +31 -0
- data/lib/def/enemies.def +8 -0
- data/lib/def/enemies/wolf.bhv +11 -0
- data/lib/def/init.def +5 -0
- data/lib/def/items.def +153 -0
- data/lib/def/loot.def +2 -0
- data/lib/def/particles.def +66 -0
- data/lib/def/recipies.def +18 -0
- data/lib/def/skills.def +40 -0
- data/lib/def/spells.def +42 -0
- data/lib/def/spells.rb +16 -0
- data/lib/def/weapons.def +9 -0
- data/lib/ext/astar/AMap.rb +146 -0
- data/lib/ext/astar/node.rb +72 -0
- data/lib/ext/astar/priority_queue.rb +44 -0
- data/lib/ext/shader.rb +116 -0
- data/lib/game/alchemy/recipe.rb +26 -0
- data/lib/game/character.rb +102 -0
- data/lib/game/combat/bar.rb +119 -0
- data/lib/game/combat/battle.rb +345 -0
- data/lib/game/combat/control.rb +18 -0
- data/lib/game/combat/gui.rb +190 -0
- data/lib/game/combat/gui/select_item.rb +11 -0
- data/lib/game/combat/gui/select_spell.rb +38 -0
- data/lib/game/constitution.rb +48 -0
- data/lib/game/equipment.rb +34 -0
- data/lib/game/inventory.rb +37 -0
- data/lib/game/item.rb +54 -0
- data/lib/game/magic.rb +33 -0
- data/lib/game/map/events.rb +29 -0
- data/lib/game/map/fog.rb +41 -0
- data/lib/game/map/map.rb +247 -0
- data/lib/game/map/map_animation.rb +26 -0
- data/lib/game/map/map_loader.rb +177 -0
- data/lib/game/map/map_object.rb +208 -0
- data/lib/game/map/map_particle.rb +27 -0
- data/lib/game/map/player.rb +78 -0
- data/lib/game/map/tile.rb +35 -0
- data/lib/game/mind.rb +24 -0
- data/lib/game/npc/behaviour.rb +45 -0
- data/lib/game/npc/bubble.rb +28 -0
- data/lib/game/npc/goal.rb +93 -0
- data/lib/game/npc/npc.rb +95 -0
- data/lib/game/npc/task.rb +73 -0
- data/lib/game/osd/magic.rb +24 -0
- data/lib/game/party.rb +42 -0
- data/lib/game/skills.rb +64 -0
- data/lib/game/spell.rb +35 -0
- data/lib/game_window.rb +95 -0
- data/lib/glsl/contrast.frag +12 -0
- data/lib/glsl/fade.frag +11 -0
- data/lib/glsl/mezzotint.frag +20 -0
- data/lib/glsl/noise.frag +20 -0
- data/lib/glsl/pixelate.frag +42 -0
- data/lib/glsl/radialblur.frag +28 -0
- data/lib/glsl/sepia.frag +15 -0
- data/lib/glsl/shockwave.frag +24 -0
- data/lib/glsl/tv_screen.frag +17 -0
- data/lib/graphics/animations/credits.txt +1 -0
- data/lib/graphics/animations/explosion2.png +0 -0
- data/lib/graphics/backgrounds/white_ties_grass.png +0 -0
- data/lib/graphics/chars/ejera.png +0 -0
- data/lib/graphics/chars/salyjea.png +0 -0
- data/lib/graphics/chars/tharat.png +0 -0
- data/lib/graphics/combat/tharat.png +0 -0
- data/lib/graphics/cursors/normal.png +0 -0
- data/lib/graphics/fog/clouds1.png +0 -0
- data/lib/graphics/gui/bar_center.png +0 -0
- data/lib/graphics/gui/bar_left.png +0 -0
- data/lib/graphics/gui/bar_right.png +0 -0
- data/lib/graphics/gui/button_background.png +0 -0
- data/lib/graphics/gui/button_close.png +0 -0
- data/lib/graphics/gui/button_close_hi.png +0 -0
- data/lib/graphics/gui/button_highlight.png +0 -0
- data/lib/graphics/gui/charequip_background.png +0 -0
- data/lib/graphics/gui/charselect_background.png +0 -0
- data/lib/graphics/gui/container_background.png +0 -0
- data/lib/graphics/gui/drop_item.png +0 -0
- data/lib/graphics/gui/equip_Etarae.png +0 -0
- data/lib/graphics/gui/equip_Mensch.png +0 -0
- data/lib/graphics/gui/equipslot_background.png +0 -0
- data/lib/graphics/gui/iteminfo_background.png +0 -0
- data/lib/graphics/gui/msg_background.png +0 -0
- data/lib/graphics/gui/scrollbar_background.png +0 -0
- data/lib/graphics/gui/scroller.png +0 -0
- data/lib/graphics/gui/tile_32.png +0 -0
- data/lib/graphics/gui/tile_32_highlight.png +0 -0
- data/lib/graphics/icons/items/arrow.png +0 -0
- data/lib/graphics/icons/items/bandage.png +0 -0
- data/lib/graphics/icons/items/boots_leather.png +0 -0
- data/lib/graphics/icons/items/bow.png +0 -0
- data/lib/graphics/icons/items/credits.txt +8 -0
- data/lib/graphics/icons/items/harness_leather.png +0 -0
- data/lib/graphics/icons/items/knife.png +0 -0
- data/lib/graphics/icons/items/shirt_linen.png +0 -0
- data/lib/graphics/items/none.png +0 -0
- data/lib/graphics/menu/ingame_background.png +0 -0
- data/lib/graphics/menu/ingame_background.xcf +0 -0
- data/lib/graphics/menu/start_background.png +0 -0
- data/lib/graphics/missing.png +0 -0
- data/lib/graphics/osd/magic_bg.png +0 -0
- data/lib/graphics/particles/leaf.png +0 -0
- data/lib/graphics/particles/smoke.png +0 -0
- data/lib/graphics/pixel.png +0 -0
- data/lib/graphics/tiles/test.png +0 -0
- data/lib/gui/base.rb +278 -0
- data/lib/gui/button.rb +93 -0
- data/lib/gui/char_equip.rb +118 -0
- data/lib/gui/char_selector.rb +54 -0
- data/lib/gui/context_menu.rb +115 -0
- data/lib/gui/draggable.rb +18 -0
- data/lib/gui/grid.rb +118 -0
- data/lib/gui/image.rb +17 -0
- data/lib/gui/inventory.rb +42 -0
- data/lib/gui/item_info.rb +33 -0
- data/lib/gui/slider.rb +10 -0
- data/lib/gui/textfield.rb +57 -0
- data/lib/layer.rb +64 -0
- data/lib/load.rb +31 -0
- data/lib/main.rb +18 -0
- data/lib/maps/def/test.bhv +26 -0
- data/lib/maps/def/test.rb +14 -0
- data/lib/maps/test.tmx +133 -0
- data/lib/maps/test2.tmx +94 -0
- data/lib/maps/test3.tmx +29 -0
- data/lib/maps/test3_lower.tmx +25 -0
- data/lib/maps/test3_upper.tmx +25 -0
- data/lib/maps/test_left.tmx +25 -0
- data/lib/maps/test_upper.tmx +25 -0
- data/lib/music/Butterfly Tea - A New Hope 2K11.mp3 +0 -0
- data/lib/music/Greendjohn - Rebirth.mp3 +0 -0
- data/lib/music/credits.txt +8 -0
- data/lib/parse.rb +605 -0
- data/lib/parse_tmx.rb +114 -0
- data/lib/particles.rb +127 -0
- data/lib/sample.rb +29 -0
- data/lib/save.rb +44 -0
- data/lib/song.rb +41 -0
- data/lib/sounds/click1.wav +0 -0
- data/lib/sounds/credits.txt +2 -0
- data/lib/sounds/error1.wav +0 -0
- data/lib/sprite.rb +35 -0
- data/lib/states/menus.rb +17 -0
- data/lib/states/menus/alchemy.rb +53 -0
- data/lib/states/menus/equip.rb +79 -0
- data/lib/states/menus/ingame.rb +34 -0
- data/lib/states/menus/magic.rb +31 -0
- data/lib/states/menus/options.rb +54 -0
- data/lib/states/menus/start.rb +38 -0
- data/lib/states/states.rb +154 -0
- data/lib/tileset.rb +42 -0
- data/lib/tools/world.rb +103 -0
- data/lib/tools/worldmap_editor.rb +221 -0
- data/lib/translate.rb +368 -0
- metadata +255 -0
data/lib/def/skills.def
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
{
|
3
|
+
name = healing
|
4
|
+
icon = "skills/healing"
|
5
|
+
}
|
6
|
+
|
7
|
+
{
|
8
|
+
name = crafting
|
9
|
+
icon = "skills/crafting"
|
10
|
+
}
|
11
|
+
|
12
|
+
{
|
13
|
+
name = botany
|
14
|
+
icon = "skills/botany"
|
15
|
+
}
|
16
|
+
|
17
|
+
{
|
18
|
+
name = healing_magic
|
19
|
+
icon = "skills/healing_magic"
|
20
|
+
}
|
21
|
+
|
22
|
+
{
|
23
|
+
name = mind
|
24
|
+
icon = "skills/mind"
|
25
|
+
}
|
26
|
+
|
27
|
+
{
|
28
|
+
name = elemental
|
29
|
+
icon = "skills/elemental"
|
30
|
+
}
|
31
|
+
|
32
|
+
{
|
33
|
+
name = ranged
|
34
|
+
icon = "skills/ranged"
|
35
|
+
}
|
36
|
+
|
37
|
+
{
|
38
|
+
name = melee
|
39
|
+
icon = "skills/melee"
|
40
|
+
}
|
data/lib/def/spells.def
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
# Healing
|
3
|
+
|
4
|
+
{
|
5
|
+
name = stop_bleed
|
6
|
+
icon = "spells/stop_bleed"
|
7
|
+
type = healing
|
8
|
+
cost = 2
|
9
|
+
}
|
10
|
+
|
11
|
+
# Mind
|
12
|
+
|
13
|
+
{
|
14
|
+
name = protect
|
15
|
+
icon = "spells/protect"
|
16
|
+
type = mind
|
17
|
+
cost = 1
|
18
|
+
}
|
19
|
+
|
20
|
+
# Elemental
|
21
|
+
|
22
|
+
{
|
23
|
+
name = heat
|
24
|
+
icon = "spells/heat"
|
25
|
+
type = elemental
|
26
|
+
cost = 10
|
27
|
+
}
|
28
|
+
|
29
|
+
{
|
30
|
+
name = cold
|
31
|
+
icon = "spells/cold"
|
32
|
+
type = elemental
|
33
|
+
cost = 10
|
34
|
+
}
|
35
|
+
|
36
|
+
#EOF
|
37
|
+
{
|
38
|
+
name =
|
39
|
+
icon = "spells/"
|
40
|
+
type =
|
41
|
+
cost =
|
42
|
+
}
|
data/lib/def/spells.rb
ADDED
data/lib/def/weapons.def
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
#AStar Map
|
2
|
+
#by Marcin Coles
|
3
|
+
#27/Sep/2007
|
4
|
+
require_relative 'priority_queue.rb'
|
5
|
+
require_relative 'node.rb'
|
6
|
+
|
7
|
+
module AStar
|
8
|
+
|
9
|
+
class AMap
|
10
|
+
attr_reader :nodes
|
11
|
+
def initialize(costmap)
|
12
|
+
#cost map is a 2D array - eg a 2x2 map is AMap.new([[3,5],[3,2]])
|
13
|
+
# the values are the movement cost for the node at those co-ordinates
|
14
|
+
#should do some error checking for size of the map, but anyway
|
15
|
+
# note that the costmap array is indexed @costmap[y][x],
|
16
|
+
# which is the opposite way to Node(x,y)
|
17
|
+
##note that it's probably easier to use AMap.load(file)
|
18
|
+
@costmap=costmap
|
19
|
+
@height=costmap.size
|
20
|
+
@width=costmap.first.size
|
21
|
+
@nodes=[]
|
22
|
+
@output="\n"
|
23
|
+
costmap.each_index do |row|
|
24
|
+
costmap[row].each_index do |col|
|
25
|
+
@nodes.push(Node.new(col,row,costmap[row][col]))
|
26
|
+
@output<<"|#{costmap[row][col]}"
|
27
|
+
end
|
28
|
+
@output<<"|\n"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.load(filename)
|
33
|
+
#loads a map from a text file - see map.txt for example, reproduced here
|
34
|
+
#~ 1,1,1,1,1,1
|
35
|
+
#~ 1,2,2,2,2,1
|
36
|
+
#~ 1,3,3,3,3,1
|
37
|
+
#~ 1,3,3,3,3,1
|
38
|
+
#~ 1,2,2,2,2,1
|
39
|
+
#~ 1,1,1,1,1,1
|
40
|
+
mmap=[]
|
41
|
+
File.open(filename) do |f|
|
42
|
+
f.each_line do |line|
|
43
|
+
linearr=[]
|
44
|
+
line.chomp.split(',').each do |e|
|
45
|
+
linearr.push(e.to_i)
|
46
|
+
end
|
47
|
+
mmap.push(linearr)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
return AMap.new(mmap)
|
51
|
+
end
|
52
|
+
|
53
|
+
def generate_successor_nodes(anode)
|
54
|
+
# determine nodes bordering this one - only North,S,E,W for now
|
55
|
+
# no boundary condition check, eg if anode.x==-4
|
56
|
+
# considers a wall to be a 0 so therefore not allow that to be a neighbour
|
57
|
+
north=@costmap[anode.y-1][(anode.x)] unless (anode.y-1)<0 #boundary check for -1
|
58
|
+
south=@costmap[anode.y+1][(anode.x)] unless (anode.y+1)>(@height-1)
|
59
|
+
east=@costmap[anode.y][(anode.x+1)] unless (anode.x+1)>(@width-1)
|
60
|
+
west=@costmap[anode.y][(anode.x-1)] unless (anode.x-1)<0 #boundary check for -1
|
61
|
+
|
62
|
+
if (west && west>0) then # not on left edge, so provide a left-bordering node
|
63
|
+
newnode=Node.new((anode.x-1),anode.y,@costmap[anode.y][(anode.x-1)])
|
64
|
+
yield newnode
|
65
|
+
end
|
66
|
+
if (east && east>0) then # not on right edge, so provide a right-bordering node
|
67
|
+
newnode=Node.new((anode.x+1),anode.y,@costmap[anode.y][(anode.x+1)])
|
68
|
+
yield newnode
|
69
|
+
end
|
70
|
+
if (north && north>0) then # not on left edge, so provide a left-bordering node
|
71
|
+
newnode=Node.new(anode.x,(anode.y-1),@costmap[(anode.y-1)][anode.x])
|
72
|
+
yield newnode
|
73
|
+
end
|
74
|
+
if (south && south>0) then # not on right edge, so provide a right-bordering node
|
75
|
+
newnode=Node.new(anode.x,(anode.y+1),@costmap[(anode.y+1)][anode.x])
|
76
|
+
yield newnode
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def astar(node_start,node_goal)
|
81
|
+
iterations=0
|
82
|
+
open=PriorityQueue.new()
|
83
|
+
closed=PriorityQueue.new()
|
84
|
+
node_start.calc_h(node_goal)
|
85
|
+
open.push(node_start)
|
86
|
+
while !open.empty? do
|
87
|
+
iterations+=1 #keep track of how many times this itersates
|
88
|
+
node_current=open.find_best
|
89
|
+
if node_current==node_goal then #found the solution
|
90
|
+
puts "Iterations: #{iterations}"
|
91
|
+
return node_current
|
92
|
+
end
|
93
|
+
generate_successor_nodes(node_current) do |node_successor|
|
94
|
+
#now doing for each successor node of node_current
|
95
|
+
node_successor.calc_g(node_current)
|
96
|
+
#skip to next node_successor if better one already on open or closed list
|
97
|
+
if open_successor=open.find(node_successor) then
|
98
|
+
if open_successor<=node_successor then next end #need to account for nil result
|
99
|
+
end
|
100
|
+
if closed_successor=closed.find(node_successor) then
|
101
|
+
if closed_successor<=node_successor then next end
|
102
|
+
end
|
103
|
+
#still here, then there's no better node yet, so remove any copies of this node on open/closed lists
|
104
|
+
open.remove(node_successor)
|
105
|
+
closed.remove(node_successor)
|
106
|
+
# set the parent node of node_successor to node_current
|
107
|
+
node_successor.parent=node_current
|
108
|
+
# set h to be the estimated distance to node_goal using the heuristic
|
109
|
+
node_successor.calc_h(node_goal)
|
110
|
+
# so now we know this is the best copy of the node so far, so put it onto the open list
|
111
|
+
open.push(node_successor)
|
112
|
+
end
|
113
|
+
#now we've gone through all the successors, so the current node can be closed
|
114
|
+
closed.push(node_current)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def co_ord(x,y)
|
119
|
+
a=Node.new(x,y)
|
120
|
+
@nodes.find {|n| n==a}
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_s
|
124
|
+
@output
|
125
|
+
end
|
126
|
+
|
127
|
+
def show_path(anode)
|
128
|
+
#shows the path back from node 'anode' by following the parent pointer
|
129
|
+
curr=anode
|
130
|
+
pathmap=@costmap.clone
|
131
|
+
while curr.parent do
|
132
|
+
pathmap[curr.y][curr.x]='*'
|
133
|
+
curr=curr.parent
|
134
|
+
end
|
135
|
+
pathmap[curr.y][curr.x]='*'
|
136
|
+
pathstr="\n"
|
137
|
+
pathmap.each_index do |row|
|
138
|
+
pathmap[row].each_index do |col|
|
139
|
+
pathstr<<"|#{pathmap[row][col]}"
|
140
|
+
end
|
141
|
+
pathstr<<"|\n"
|
142
|
+
end
|
143
|
+
pathstr
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#AStar map Node
|
2
|
+
#by Marcin Coles
|
3
|
+
#27/Sep/2007
|
4
|
+
module AStar
|
5
|
+
|
6
|
+
class Node
|
7
|
+
#class Node provides a node on a map which can be used for pathfinding.
|
8
|
+
#For Node to work with PriorityQueue and AMap it needs to implement the following
|
9
|
+
# <= used for comparing g values
|
10
|
+
# == used for finding the same node - using the x,y co-ordinates
|
11
|
+
attr_accessor :parent
|
12
|
+
attr_reader :x,:y,:g,:h,:m
|
13
|
+
|
14
|
+
def initialize(x,y,move_cost=0)
|
15
|
+
@x,@y,@m=x,y,move_cost
|
16
|
+
@g=@m
|
17
|
+
@h=0
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
#prints the node in the following format [x,y] f:g:h
|
22
|
+
"[#{@x},#{@y}] #{@g+@h}:#{@g}:#{@h}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def <=>(other)
|
26
|
+
#can be used for ordering the priority list
|
27
|
+
#puts "using <=>" #currently unused - can delete this line if required
|
28
|
+
self.f<=>other.f
|
29
|
+
end
|
30
|
+
|
31
|
+
def <=(other)
|
32
|
+
#used for comparing cost so far
|
33
|
+
@g<=other.g
|
34
|
+
end
|
35
|
+
|
36
|
+
def ==(other)
|
37
|
+
# nodes are == if x and y are the same - used for finding and removing same node
|
38
|
+
return false if other==nil
|
39
|
+
return (@x==other.x)&(@y==other.y)
|
40
|
+
end
|
41
|
+
|
42
|
+
def calc_g(previous)
|
43
|
+
#cost so far is total cost of previous step plus the movement cost of this one
|
44
|
+
@g=previous.g+@m
|
45
|
+
end
|
46
|
+
|
47
|
+
def calc_h(goal)
|
48
|
+
#using manhattan distance to generate a heuristic value
|
49
|
+
@h=(@x-goal.x).abs+(@y-goal.y).abs
|
50
|
+
end
|
51
|
+
def f
|
52
|
+
@g+@h
|
53
|
+
end
|
54
|
+
def better?(other,tbmul=1.01)
|
55
|
+
#which is better, self or other
|
56
|
+
#can pass a tie-breaker multiplier (tbmul) if required
|
57
|
+
if other==nil then return false end
|
58
|
+
if self==other then return false end
|
59
|
+
if f<other.f then
|
60
|
+
return true
|
61
|
+
#here's the tie-breaker
|
62
|
+
elsif f==other.f then
|
63
|
+
nf=@g+tbmul*@h
|
64
|
+
bf=other.g+tbmul*other.h
|
65
|
+
if nf<bf then return true end
|
66
|
+
end
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#AStar PriorityQueue
|
2
|
+
#by Marcin Coles
|
3
|
+
#27/Sep/2007
|
4
|
+
#note - not really a priority queue at this point
|
5
|
+
|
6
|
+
require_relative "node.rb"
|
7
|
+
|
8
|
+
module AStar
|
9
|
+
|
10
|
+
class PriorityQueue
|
11
|
+
def initialize(nodes=[])
|
12
|
+
@nodes=nodes
|
13
|
+
#tie-breaker multiplier (tbmul) is 1+1/(the sqrt of the map size)
|
14
|
+
@tbmul=1+1/(Math.sqrt(@nodes.size))
|
15
|
+
end
|
16
|
+
def method_missing(methodname, *args)
|
17
|
+
#if in doubt, act like an array
|
18
|
+
@nodes.send(methodname, *args)
|
19
|
+
end
|
20
|
+
def find_best
|
21
|
+
#finds the best node, then pops it out
|
22
|
+
best=@nodes.first
|
23
|
+
@nodes.each do |node|
|
24
|
+
if node.better?(best,@tbmul) then best=node end
|
25
|
+
end
|
26
|
+
remove(best)
|
27
|
+
end
|
28
|
+
def find(node)
|
29
|
+
#finds a node - requires that node implements ==
|
30
|
+
@nodes.find {|x| x==node }
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove(node)
|
34
|
+
#removes a node
|
35
|
+
@nodes.delete(find(node))
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
output=""
|
40
|
+
@nodes.each {|e| output<<"#{e};"}
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/lib/ext/shader.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
|
2
|
+
class Shader
|
3
|
+
include Gl
|
4
|
+
|
5
|
+
attr_reader :window, :shader_filename
|
6
|
+
attr_reader :program_id, :vertex_shader_id, :fragment_shader_id
|
7
|
+
|
8
|
+
@@canvas_texture_id = nil
|
9
|
+
|
10
|
+
def initialize(window, shader_filename)
|
11
|
+
@window = window
|
12
|
+
@shader_filename = shader_filename
|
13
|
+
|
14
|
+
@program_id = nil
|
15
|
+
@vertex_shader_id = nil
|
16
|
+
@fragment_shader_id = nil
|
17
|
+
|
18
|
+
create_canvas unless @@canvas_texture_id
|
19
|
+
compile
|
20
|
+
end
|
21
|
+
|
22
|
+
def apply
|
23
|
+
@window.gl do
|
24
|
+
# copy frame buffer to canvas texture
|
25
|
+
glBindTexture(GL_TEXTURE_2D, @@canvas_texture_id)
|
26
|
+
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, @window.width, @window.height, 0)
|
27
|
+
|
28
|
+
# apply shader
|
29
|
+
glUseProgram(@program_id)
|
30
|
+
|
31
|
+
# clear screen
|
32
|
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
33
|
+
glColor4f(1.0, 1.0, 1.0, 1.0)
|
34
|
+
glMatrixMode(GL_PROJECTION)
|
35
|
+
glPushMatrix
|
36
|
+
glLoadIdentity
|
37
|
+
glViewport(0, 0, @window.width, @window.height)
|
38
|
+
glOrtho(0, @window.width, @window.height, 0, -1, 1)
|
39
|
+
|
40
|
+
# draw processed canvas texture over the screen
|
41
|
+
glBindTexture(GL_TEXTURE_2D, @@canvas_texture_id)
|
42
|
+
|
43
|
+
glBegin(GL_QUADS)
|
44
|
+
glTexCoord2f(0.0, 1.0); glVertex2f(0.0, 0.0)
|
45
|
+
glTexCoord2f(1.0, 1.0); glVertex2f(@window.width, 0.0)
|
46
|
+
glTexCoord2f(1.0, 0.0); glVertex2f(@window.width, @window.height)
|
47
|
+
glTexCoord2f(0.0, 0.0); glVertex2f(0.0, @window.height)
|
48
|
+
glEnd
|
49
|
+
|
50
|
+
# done, disable shader
|
51
|
+
glUseProgram(0)
|
52
|
+
|
53
|
+
# and out
|
54
|
+
glPopMatrix
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def uniform(name, value)
|
59
|
+
glUseProgram(@program_id)
|
60
|
+
if value.is_a?(Float)
|
61
|
+
glUniform1f(glGetUniformLocation(@program_id, name), value)
|
62
|
+
elsif value.is_a?(Integer)
|
63
|
+
glUniform1i(glGetUniformLocation(@program_id, name), value)
|
64
|
+
else
|
65
|
+
raise ArgumentError, "Uniform data type not supported"
|
66
|
+
end
|
67
|
+
glUseProgram(0)
|
68
|
+
end
|
69
|
+
|
70
|
+
alias []= uniform
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def create_canvas
|
75
|
+
@@canvas_texture_id = glGenTextures(1).first
|
76
|
+
glBindTexture(GL_TEXTURE_2D, @@canvas_texture_id)
|
77
|
+
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1)
|
78
|
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
|
79
|
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
|
80
|
+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, @window.width, @window.height, 0, GL_RGB, GL_UNSIGNED_BYTE, "\0" * @window.width * @window.height * 3)
|
81
|
+
return @@canvas_texture_id
|
82
|
+
end
|
83
|
+
|
84
|
+
def compile
|
85
|
+
# create program
|
86
|
+
@program_id = glCreateProgram
|
87
|
+
|
88
|
+
# create vertex shader
|
89
|
+
@vertex_shader_id = glCreateShader(GL_VERTEX_SHADER)
|
90
|
+
puts("INFO: Compiling vertex shader (#{@shader_filename})")
|
91
|
+
if File.exist?(@shader_filename + ".vert")
|
92
|
+
glShaderSource(@vertex_shader_id, File.read(@shader_filename + ".vert"))
|
93
|
+
else
|
94
|
+
glShaderSource(@vertex_shader_id, "void main(void)\r\n{\r\ngl_Position = ftransform();\r\ngl_TexCoord[0] = gl_MultiTexCoord0;\r\n}\r\n")
|
95
|
+
end
|
96
|
+
glCompileShader(@vertex_shader_id)
|
97
|
+
glAttachShader(@program_id, @vertex_shader_id)
|
98
|
+
|
99
|
+
# create fragment shader
|
100
|
+
@fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER)
|
101
|
+
puts("INFO: Compiling fragment shader (#{@shader_filename})")
|
102
|
+
glShaderSource(@fragment_shader_id, File.read(@shader_filename + ".frag"))
|
103
|
+
glCompileShader(@fragment_shader_id)
|
104
|
+
glAttachShader(@program_id, @fragment_shader_id)
|
105
|
+
|
106
|
+
# compile program
|
107
|
+
glLinkProgram(@program_id)
|
108
|
+
|
109
|
+
# check for compile errors
|
110
|
+
unless glGetProgramiv(@program_id, GL_LINK_STATUS) == GL_TRUE
|
111
|
+
raise glGetProgramInfoLog(@program_id).chomp
|
112
|
+
end
|
113
|
+
|
114
|
+
return @program_id
|
115
|
+
end
|
116
|
+
end
|