diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..78cb8bb --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +all: visu_rule + +greedy: + @./res_npuzzle-gen.py -s -i 36 5 > test/test.txt + @head -1 test/test.txt + @./source/main.py -g test/test.txt + +run: + @./res_npuzzle-gen.py -s -i 30 4 > test/test.txt + @head -1 test/test.txt + @./source/main.py test/test.txt + +visu_rule: + @./res_npuzzle-gen.py -s -i 50000 3 > test/test.txt + @head -1 test/test.txt + @./source/main.py test/test.txt + @g++ visu/main.cpp visu/ogldev_util.cpp -lglut -lOpenGL -lGLEW + @./a.out diff --git a/author b/author new file mode 100644 index 0000000..1c891da --- /dev/null +++ b/author @@ -0,0 +1,2 @@ +gbrochar +ygarrot diff --git a/res_npuzzle-gen.py b/res_npuzzle-gen.py new file mode 100755 index 0000000..b1e6df4 --- /dev/null +++ b/res_npuzzle-gen.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python + +import sys +import argparse +import random + +def make_puzzle(s, solvable, iterations): + def swap_empty(p): + idx = p.index(0) + poss = [] + if idx % s > 0: + poss.append(idx - 1) + if idx % s < s - 1: + poss.append(idx + 1) + if idx / s > 0 and idx - s >= 0: + poss.append(idx - s) + if idx / s < s - 1: + poss.append(idx + s) + swi = random.choice(poss) + p[idx] = p[swi] + p[swi] = 0 + + p = make_goal(s) + for i in range(iterations): + swap_empty(p) + + if not solvable: + if p[0] == 0 or p[1] == 0: + p[-1], p[-2] = p[-2], p[-1] + else: + p[0], p[1] = p[1], p[0] + + return p + +def make_goal(s): + ts = s*s + puzzle = [-1 for i in range(ts)] + cur = 1 + x = 0 + ix = 1 + y = 0 + iy = 0 + while True: + puzzle[x + y*s] = cur + if cur == 0: + break + cur += 1 + if x + ix == s or x + ix < 0 or (ix != 0 and puzzle[x + ix + y*s] != -1): + iy = ix + ix = 0 + elif y + iy == s or y + iy < 0 or (iy != 0 and puzzle[x + (y+iy)*s] != -1): + ix = -iy + iy = 0 + x += ix + y += iy + if cur == s*s: + cur = 0 + + return puzzle + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + + parser.add_argument("size", type=int, help="Size of the puzzle's side. Must be >3.") + parser.add_argument("-s", "--solvable", action="store_true", default=False, help="Forces generation of a solvable puzzle. Overrides -u.") + parser.add_argument("-u", "--unsolvable", action="store_true", default=False, help="Forces generation of an unsolvable puzzle") + parser.add_argument("-i", "--iterations", type=int, default=10000, help="Number of passes") + + args = parser.parse_args() + + random.seed() + + if args.solvable and args.unsolvable: + print "Can't be both solvable AND unsolvable, dummy !" + sys.exit(1) + + if args.size < 3: + print "Can't generate a puzzle with size lower than 2. It says so in the help. Dummy." + sys.exit(1) + + if not args.solvable and not args.unsolvable: + solv = random.choice([True, False]) + elif args.solvable: + solv = True + elif args.unsolvable: + solv = False + + s = args.size + + puzzle = make_puzzle(s, solvable=solv, iterations=args.iterations) + + w = len(str(s*s)) + print "# This puzzle is %s" % ("solvable" if solv else "unsolvable") + print "%d" % s + for y in range(s): + for x in range(s): + print "%s" % (str(puzzle[x + y*s]).rjust(w)), + print diff --git a/source/Node.py b/source/Node.py new file mode 100755 index 0000000..1361c25 --- /dev/null +++ b/source/Node.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 + +import config +from heuristics import * +from math import sqrt +import numpy as np +import copy + +def LEFT(i): + return i - 1 + +def RIGHT(i): + return i + 1 + +def UP(i, puzzle_size): + return i - puzzle_size + +def DOWN(i, puzzle_size): + return i + puzzle_size + +def chunks(l, n): + return [l[i:i+n] for i in range(0, len(l), n)] + +class Node(object): + def __init__(self, h = 0, g = 0, f = 0, empty_case_index = 0, grid = []): + self.h = h + self.g = g + self.f = f + self.index = empty_case_index + self.right = None + self.left = None + self.up = None + self.down = None + self.size = len(grid) + self.sqrt = int(sqrt(len(grid))) + self.child = None + self.parents = [] + self.grid = grid + + + def __eq__(self, other): + return self.f == other.f + + def __lt__(self, other): + return self.f < other.f + + def __str__(self): + lst = np.matrix(chunks(self.grid, int(sqrt(len(self.grid))))) + return str(lst) + + def set_parent(self): + self.left = self.swap_left() + self.right = self.swap_right() + self.up = self.swap_up() + self.down = self.swap_down() + self.parents = [x for x in [self.right, self.left, self.up, self.down] if x is not None] + + for node in self.parents: + node.h = config.heuristic_fn(node.grid) + node.size = len(node.grid) + node.sqrt = int(sqrt(len(node.grid))) + node.child = self + node.g = self.g + 1 + node.f = config.calc_fScore(node.h, node.g) + + def swap_left(self): + return self.tile_swap_2_index(LEFT(self.index), self.is_valid_horizontal_move) + + def swap_right(self): + return self.tile_swap_2_index(RIGHT(self.index), self.is_valid_horizontal_move) + + def swap_down(self): + return self.tile_swap_2_index(DOWN(self.index, self.sqrt), self.is_valid_vertical_move) + + def swap_up(self): + return self.tile_swap_2_index(UP(self.index, self.sqrt), self.is_valid_vertical_move) + + def is_valid_vertical_move(self, new_index): + return new_index >= 0 and new_index < self.size + + def is_valid_horizontal_move(self, new_index): + index = self.index + i = index - new_index + if (new_index < 0 or new_index > self.size): + return False + if (index is 0 and i is -1): + return True + if (index is 1): + return True + if (((index + 1) % self.sqrt) is 0 and i is -1): + return False + if (((index + 1) % self.sqrt) is 1 and i is +1): + return False + return True + + def tile_swap_2_index(self, new_index, valid_move_fn): + index = self.index + if not valid_move_fn(new_index): + return None + lst = copy.deepcopy(self.grid) + lst[index], lst[new_index] = lst[new_index], lst[index] + node = Node() + node.grid = lst + node.index = new_index + return node diff --git a/source/PriorityQueue.py b/source/PriorityQueue.py new file mode 100644 index 0000000..97996c8 --- /dev/null +++ b/source/PriorityQueue.py @@ -0,0 +1,14 @@ +import heapq + +class PriorityQueue: + def __init__(self): + self.elements = [] + + def empty(self): + return len(self.elements) == 0 + + def put(self, item): + heapq.heappush(self.elements, (item.f, item)) + + def get(self): + return heapq.heappop(self.elements)[1] diff --git a/source/a_star.py b/source/a_star.py new file mode 100755 index 0000000..88f7cf8 --- /dev/null +++ b/source/a_star.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +#f score is the sum of the cost to reach that node and the heuristic value of that node. +import config +from Node import * +import numpy as np +from PriorityQueue import * + +def chunks(l, n): + return [l[i:i+n] for i in range(0, len(l), n)] + +def print_recc(f, elem): + if (elem.child): + print_recc(f, elem.child) + print(np.matrix(chunks(elem.grid, elem.sqrt))) + print() + f.write(' '.join(['{: >2}'.format(x) for x in elem.grid])) + f.write('\n') + +def print_for_visu(process): + f = open("test/visu.txt", "w") + print_recc(f, process) + f.close() + +def a_star_impl(grid, goal, heuristic_ptr): + heuristic_ptr= config.heuristic_fn + start = Node(h = heuristic_ptr(grid), empty_case_index = grid.index(0), grid = grid) + open_set = PriorityQueue() + closed_set = PriorityQueue() + open_set.put(start) + time_complexity = 0 + size_complexity = 1 + + while open_set: + process = open_set.get() + if process.h is 0 or process.grid is goal: + print("Ordered Sequence:") + print_for_visu(process) + print("Number of moves: {}\n" + "Time Complexity: {}\n" + "Size Complexity: {}" + .format(process.g, time_complexity, size_complexity)) + return + closed_set.put(process) + process.set_parent() + for node in process.parents: + in_close = node.grid in [x.grid for (p, x) in closed_set.elements] + in_open = node.grid in [x.grid for (p, x) in open_set.elements] + + if in_close: + continue + new_g = process.g + 1 + + if not in_open: + node.g = new_g + open_set.put(node) + size_complexity += 1 + else: + if (node.g > new_g): + node.g = new_g + + node.f = config.calc_fScore(node.h, node.g) + time_complexity += 1 + raise ValueError('No Path Found') diff --git a/source/config.py b/source/config.py new file mode 100644 index 0000000..79e2ce2 --- /dev/null +++ b/source/config.py @@ -0,0 +1,8 @@ +import heuristics + +is_greedy = False +goal = [] +heuristic_fn = None + +def calc_fScore(h, g): + return h if is_greedy else g + h diff --git a/source/heuristics.py b/source/heuristics.py new file mode 100755 index 0000000..aca7d80 --- /dev/null +++ b/source/heuristics.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +import math +import config + +def hamming_distance(grid): + h = 0 + for i, v in enumerate(grid): + if i != config.goal.index(v): + h += 1 + return h + +def manhattan_distance(grid): + h = 0 + size = int(math.sqrt(len(grid))) + for i, v in enumerate(grid): + if i != config.goal.index(v): + curr_col = i % size + curr_row = i // size + target_col = (config.goal.index(v)) % size + target_row = (config.goal.index(v)) // size + h += abs(target_col - curr_col) + abs(target_row - curr_row) + return h + +def linear_conflict_manhattan_distance(grid): + h = manhattan_distance(grid) + size = int(math.sqrt(len(grid))) + for i, v in enumerate(grid): + if i != config.goal.index(v): + curr_col = i % size + curr_row = i // size + target_col = (config.goal.index(v)) % size + target_row = (config.goal.index(v)) // size + #move left + if target_col - curr_col > 0: + while (curr_col < target_col): + i += 1 + curr_col = i % size + if (grid[v] - 1) // size == target_row: + h += 1 + #move right + elif target_col - curr_col < 0: + while (curr_col > target_col): + i -= 1 + curr_col = i % size + if (grid[v] - 1) // size == target_row: + h += 1 + #move up + if target_row - curr_row > 0: + while (curr_row < target_row): + i += 3 + curr_row = i // size + if (grid[i] - 1) % size == target_col: + h += 1 + #move down + elif target_row - curr_row < 0: + while (curr_row > target_row): + i -= 3 + curr_row = i // size + if (grid[i] - 1) % size == target_col: + h += 1 + return h diff --git a/source/main.py b/source/main.py new file mode 100755 index 0000000..cbeb28e --- /dev/null +++ b/source/main.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +import argparse +import config +import re +import heuristics +from solvable import * +from snail import * +from a_star import a_star_impl + + +def make_goal(s): + ts = s*s + puzzle = [-1 for i in range(ts)] + cur = 1 + x = 0 + ix = 1 + y = 0 + iy = 0 + while True: + puzzle[x + y*s] = cur + if cur == 0: + break + cur += 1 + if x + ix == s or x + ix < 0 or (ix != 0 and puzzle[x + ix + y*s] != -1): + iy = ix + ix = 0 + elif y + iy == s or y + iy < 0 or (iy != 0 and puzzle[x + (y+iy)*s] != -1): + ix = -iy + iy = 0 + x += ix + y += iy + if cur == s*s: + cur = 0 + + return puzzle + + +def parse_file(file_name): + dict = {} + with open(file_name) as f: + content = f.read() + without_hash = re.sub('#.*', '', content).strip() + puzzles = without_hash.split() + try: + puzzle_size = int(puzzles[0]) + except: + exit("Invalid size: " + puzzles[0]) + + puzzles = [ int(puzzle) for puzzle in puzzles[1:]] + without_hash = without_hash.splitlines()[1:] + + for line in without_hash: + line_length = len(line.split()) + if (line_length is not puzzle_size): + exit("Invalid value in puzzle") + return puzzles, puzzle_size + +def parse_arg(): + parser = argparse.ArgumentParser(description='Faster N-Puzzle you have ever seen') + parser.add_argument("-g", "--greedy", default=False, action="store_true", + help="Are You a Greedy Bastard?") + parser.add_argument("-a", "--algorithm", dest="heuristic", + default="manhattan_distance", + choices=["hamming_distance", "manhattan_distance", "linear_conflict_manhattan_distance"], + help="choose algorithm function") + parser.add_argument("path", type=str, default="none", help="input file name") + args = parser.parse_args() + config.is_greedy = args.greedy + config.heuristic_fn = getattr(heuristics, args.heuristic) + print("heuristic choosen: {}".format(args.heuristic)) + return args.path + +def main(): + grid, size = parse_file(parse_arg()) + config.goal = make_goal(size) + for tile in config.goal: + if tile not in grid: + exit("Parsing Error") + if not solvable(snail_to_ordered_by_ygarrot(grid, config.goal, size)): + exit("Error : N-puzzle not solvable !") + print("N-puzzle is solvable !") + #check if input puzzle go from 0 to N - 1 + a_star_impl(grid, config.goal, config.heuristic_fn) + +if __name__ == '__main__': + main() diff --git a/source/snail.py b/source/snail.py new file mode 100644 index 0000000..ae63859 --- /dev/null +++ b/source/snail.py @@ -0,0 +1,83 @@ +import numpy as np +from math import sqrt + +def chunks(l): + n = int(sqrt(len(l))) + return np.matrix([l[i:i+n] for i in range(0, len(l), n)]) + +def snail_to_ordered_by_ygarrot(snail, goal, size): + ''' + snail_to_ordered and ordered_to_snail functions are + historical curiosities left over from earlier days before + the advent of N-puzzle solving. + ''' + toto = [] + ordered = [i + 1 for i in range(size * size)] + ordered[-1] = 0 + + for i in range(len(ordered)): + toto.insert(i, snail[goal.index(ordered[i])]) + return toto + + +# def snail_to_ordered(grid): +# size = int(math.sqrt(len(grid))) +# grid_ret = grid.copy() +# for i in range(size // 2): +# for j in range(size - 1 - 2 * i): +# index = size + j +# for k in range(i): +# index += (4 * (size - 2 * (k + 1))) + 2 +# grid_ret[index] = grid[size * (j + i + 2) - i - 1] +# for i in range((size - 1) // 2 + (1 - size % 2)): +# for j in range(size - 1 - 2 * i): +# index = size + (size - 1) + j +# for k in range(i): +# index += (4 * (size - 2 * (k + 1))) +# grid_ret[index] = grid[size * (size - i) - (2 + i) - j] +# for i in range((size - 1) // 2): +# for j in range(size - 2 - 2 * i): +# index = size + 2 * (size - 1) + j +# for k in range(i): +# index += (4 * (size - 2 * (k + 1))) - 2 +# grid_ret[index] = grid[size * (size - (2 + i)) - size * j + i] +# for i in range((size - 2) // 2 + size % 2): +# for j in range(size - 2 - 2 * i): +# index = size + 2 * (size - 1) + (size - 2) + j +# for k in range(i): +# index += (4 * (size - 2 * (k + 1))) - 4 +# grid_ret[index] = grid[size * (i + 1) + (i + 1) + j] +# return grid_ret + +# def ordered_to_snail(grid): +# size = int(math.sqrt(len(grid))) +# grid_ret = grid.copy() +# for i in range(size // 2): +# for j in range(size - 1 - 2 * i): +# index = size + j +# for k in range(i): +# index += (4 * (size - 2 * (k + 1))) + 2 +# grid_ret[size * (j + i + 2) - i - 1] = grid[index] +# for i in range((size - 1) // 2): +# for j in range(size - 1 - 2 * i): +# index = size + (size - 1) + j +# for k in range(i): +# index += (4 * (size - 2 * (k + 1))) +# grid_ret[size * (size - i) - (2 + i) - j] = grid[index] +# for i in range((size - 1) // 2): +# for j in range(size - 2 - 2 * i): +# index = size + 2 * (size - 1) + j +# for k in range(i): +# index += (4 * (size - 2 * (k + 1))) - 2 +# grid_ret[size * (size - (2 + i)) - size * j + i] = grid[index] +# for i in range((size - 2) // 2): +# for j in range(size - 2 - 2 * i): +# index = size + 2 * (size - 1) + (size - 2) + j +# for k in range(i): +# index += (4 * (size - 2 * (k + 1))) - 4 +# grid_ret[size * (i + 1) + (i + 1) + j] = grid[index] +# if size % 2: +# grid_ret[len(grid_ret) // 2] = 0 +# else: +# grid_ret[len(grid_ret) // 2 + (size - 4) // 2 + 1] = 0 +# return grid_ret diff --git a/source/solvable.py b/source/solvable.py new file mode 100644 index 0000000..f675526 --- /dev/null +++ b/source/solvable.py @@ -0,0 +1,25 @@ +import math + +def get_inversions(grid): + inversions = 0 + for i in range(len(grid)): + if grid[i] is 0: + continue + for j in range(i + 1, len(grid)): + if grid[j] is not 0 and grid[i] > grid[j]: + inversions += 1 + return inversions + +def odd(n): + return (n % 2) != 0 + +def solvable(grid): + """Return True if the puzzle is solvable or False if it's not.""" + size = int(math.sqrt(len(grid))) + inversions = get_inversions(grid) + if odd(size): + return not odd(inversions) + else: + if odd(grid.index(0)): + return not odd(inversions) + return odd(inversions) diff --git a/test/test.txt b/test/test.txt new file mode 100644 index 0000000..10940ea --- /dev/null +++ b/test/test.txt @@ -0,0 +1,7 @@ +# This puzzle is solvable +5 + 2 18 3 4 5 + 1 0 19 20 6 +24 14 23 22 7 +17 16 15 21 8 +13 12 11 10 9 diff --git a/test/test_3.txt b/test/test_3.txt new file mode 100644 index 0000000..f31b5b7 --- /dev/null +++ b/test/test_3.txt @@ -0,0 +1,5 @@ +# This puzzle is solvable +3 +1 2 3 +8 6 4 +7 5 0 diff --git a/test/test_4.txt b/test/test_4.txt new file mode 100644 index 0000000..8acd321 --- /dev/null +++ b/test/test_4.txt @@ -0,0 +1,6 @@ +# This puzzle is solvable +4 + 1 2 4 5 +12 14 0 3 +11 13 15 6 +10 9 8 7 diff --git a/test/test_5.txt b/test/test_5.txt new file mode 100644 index 0000000..e53298f --- /dev/null +++ b/test/test_5.txt @@ -0,0 +1,7 @@ +# This puzzle is solvable +5 + 1 2 3 4 5 +16 17 18 19 6 +15 23 20 21 7 +12 0 22 24 8 +14 13 11 10 9 diff --git a/test/test_6.txt b/test/test_6.txt new file mode 100644 index 0000000..1c1c531 --- /dev/null +++ b/test/test_6.txt @@ -0,0 +1,8 @@ +# This puzzle is solvable +6 + 1 2 3 5 24 6 +20 21 23 4 0 7 +19 32 22 34 25 8 +18 31 33 35 26 9 +17 30 29 13 27 10 +16 15 14 12 28 11 diff --git a/test/test_7.txt b/test/test_7.txt new file mode 100644 index 0000000..fe692d2 --- /dev/null +++ b/test/test_7.txt @@ -0,0 +1,9 @@ +# This puzzle is solvable +7 + 1 2 3 5 27 6 7 +24 25 26 4 28 29 8 +23 40 41 42 43 9 0 +22 39 48 46 31 30 10 +21 38 47 45 44 32 11 +20 37 36 35 34 33 12 +19 18 17 16 15 14 13 diff --git a/test/test_8.txt b/test/test_8.txt new file mode 100644 index 0000000..8c06391 --- /dev/null +++ b/test/test_8.txt @@ -0,0 +1,10 @@ +# This puzzle is solvable +8 + 1 2 3 4 5 6 7 8 +28 29 30 31 32 33 34 9 +27 48 49 50 51 52 35 10 +26 47 60 62 63 53 36 11 +25 46 59 61 54 55 37 12 +24 45 58 57 56 40 38 13 +23 44 43 42 18 41 39 14 +22 21 20 19 17 16 0 15 diff --git a/test/test_9.txt b/test/test_9.txt new file mode 100644 index 0000000..c0b5b73 --- /dev/null +++ b/test/test_9.txt @@ -0,0 +1,11 @@ +# This puzzle is solvable +9 + 1 2 3 4 5 6 7 8 9 +32 33 34 35 36 37 38 39 10 +31 56 57 58 59 60 61 40 11 +30 55 72 73 74 75 62 41 12 +29 54 71 80 78 76 63 42 13 +28 53 70 79 77 66 64 43 14 +27 52 69 68 65 47 46 44 15 +26 51 50 49 67 21 19 45 16 +25 24 23 22 48 20 0 18 17 diff --git a/test/unsolvable_test_3.txt b/test/unsolvable_test_3.txt new file mode 100644 index 0000000..7b59dbe --- /dev/null +++ b/test/unsolvable_test_3.txt @@ -0,0 +1,5 @@ +# This puzzle is unsolvable +3 +1 8 2 +7 4 3 +0 6 5 diff --git a/test/unsolvable_test_4.txt b/test/unsolvable_test_4.txt new file mode 100644 index 0000000..c5013ee --- /dev/null +++ b/test/unsolvable_test_4.txt @@ -0,0 +1,6 @@ +# This puzzle is unsolvable +4 + 3 1 14 4 +12 13 2 5 +11 9 15 6 + 0 10 8 7 diff --git a/test/unsolvable_test_5.txt b/test/unsolvable_test_5.txt new file mode 100644 index 0000000..97082f6 --- /dev/null +++ b/test/unsolvable_test_5.txt @@ -0,0 +1,7 @@ +# This puzzle is unsolvable +5 + 2 1 3 4 5 +16 17 18 6 8 +15 24 20 19 21 +14 23 22 0 10 +13 12 11 9 7 diff --git a/test/unsolvable_test_6.txt b/test/unsolvable_test_6.txt new file mode 100644 index 0000000..3407b4d --- /dev/null +++ b/test/unsolvable_test_6.txt @@ -0,0 +1,8 @@ +# This puzzle is unsolvable +6 + 2 1 3 4 5 6 +20 22 0 23 24 7 +19 21 33 34 25 8 +31 32 29 35 26 9 +18 30 28 13 27 10 +17 16 15 14 12 11 diff --git a/test/unsolvable_test_7.txt b/test/unsolvable_test_7.txt new file mode 100644 index 0000000..bc394c7 --- /dev/null +++ b/test/unsolvable_test_7.txt @@ -0,0 +1,9 @@ +# This puzzle is unsolvable +7 + 2 1 3 4 5 6 7 +24 25 26 27 28 29 8 +23 41 42 43 30 31 9 +22 40 39 48 44 32 10 +21 38 47 46 45 33 11 +20 37 36 35 34 0 12 +19 18 17 16 15 14 13 diff --git a/test/unsolvable_test_8.txt b/test/unsolvable_test_8.txt new file mode 100644 index 0000000..21cf18e --- /dev/null +++ b/test/unsolvable_test_8.txt @@ -0,0 +1,10 @@ +# This puzzle is unsolvable +8 + 2 1 3 4 5 6 8 9 +28 29 30 31 32 33 34 7 +27 48 49 50 51 0 35 10 +26 47 60 61 53 52 36 11 +25 46 59 63 62 54 37 12 +24 45 58 57 56 55 38 13 +23 44 43 42 41 40 39 14 +22 21 20 19 18 17 16 15 diff --git a/test/unsolvable_test_9.txt b/test/unsolvable_test_9.txt new file mode 100644 index 0000000..d8b1215 --- /dev/null +++ b/test/unsolvable_test_9.txt @@ -0,0 +1,11 @@ +# This puzzle is unsolvable +9 + 2 1 3 4 5 6 7 8 9 +32 33 34 35 36 37 38 39 10 +31 56 57 73 58 60 61 40 11 +30 55 72 80 59 75 62 41 12 +29 54 71 79 74 76 63 42 13 +28 53 70 68 78 77 64 43 14 +27 52 50 67 0 66 65 44 15 +26 51 49 69 48 47 46 45 16 +25 24 23 22 21 20 19 18 17 diff --git a/test/visu.txt b/test/visu.txt new file mode 100644 index 0000000..d059a38 --- /dev/null +++ b/test/visu.txt @@ -0,0 +1,47 @@ + 2 18 3 4 5 1 0 19 20 6 24 14 23 22 7 17 16 15 21 8 13 12 11 10 9 + 2 0 3 4 5 1 18 19 20 6 24 14 23 22 7 17 16 15 21 8 13 12 11 10 9 + 0 2 3 4 5 1 18 19 20 6 24 14 23 22 7 17 16 15 21 8 13 12 11 10 9 + 1 2 3 4 5 0 18 19 20 6 24 14 23 22 7 17 16 15 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 19 20 6 0 14 23 22 7 17 16 15 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 19 20 6 14 0 23 22 7 17 16 15 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 19 20 6 14 23 0 22 7 17 16 15 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 19 20 6 14 23 22 0 7 17 16 15 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 19 0 6 14 23 22 20 7 17 16 15 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 0 19 6 14 23 22 20 7 17 16 15 21 8 13 12 11 10 9 + 1 2 3 4 5 24 0 18 19 6 14 23 22 20 7 17 16 15 21 8 13 12 11 10 9 + 1 2 3 4 5 24 23 18 19 6 14 0 22 20 7 17 16 15 21 8 13 12 11 10 9 + 1 2 3 4 5 24 23 18 19 6 14 16 22 20 7 17 0 15 21 8 13 12 11 10 9 + 1 2 3 4 5 24 23 18 19 6 14 16 22 20 7 17 15 0 21 8 13 12 11 10 9 + 1 2 3 4 5 24 23 18 19 6 14 16 0 20 7 17 15 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 23 18 19 6 14 0 16 20 7 17 15 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 23 18 19 6 14 15 16 20 7 17 0 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 23 18 19 6 14 15 16 20 7 0 17 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 23 18 19 6 0 15 16 20 7 14 17 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 23 18 19 6 15 0 16 20 7 14 17 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 0 18 19 6 15 23 16 20 7 14 17 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 0 19 6 15 23 16 20 7 14 17 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 16 19 6 15 23 0 20 7 14 17 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 16 19 6 15 0 23 20 7 14 17 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 16 19 6 15 17 23 20 7 14 0 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 16 19 6 15 17 23 20 7 14 22 0 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 16 19 6 15 17 0 20 7 14 22 23 21 8 13 12 11 10 9 + 1 2 3 4 5 24 18 0 19 6 15 17 16 20 7 14 22 23 21 8 13 12 11 10 9 + 1 2 3 4 5 24 0 18 19 6 15 17 16 20 7 14 22 23 21 8 13 12 11 10 9 + 1 2 3 4 5 24 17 18 19 6 15 0 16 20 7 14 22 23 21 8 13 12 11 10 9 + 1 2 3 4 5 24 17 18 19 6 15 16 0 20 7 14 22 23 21 8 13 12 11 10 9 + 1 2 3 4 5 24 17 18 19 6 15 16 23 20 7 14 22 0 21 8 13 12 11 10 9 + 1 2 3 4 5 24 17 18 19 6 15 16 23 20 7 14 0 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 17 18 19 6 15 16 23 20 7 0 14 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 17 18 19 6 0 16 23 20 7 15 14 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 17 18 19 6 16 0 23 20 7 15 14 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 17 18 19 6 16 23 0 20 7 15 14 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 17 0 19 6 16 23 18 20 7 15 14 22 21 8 13 12 11 10 9 + 1 2 3 4 5 24 0 17 19 6 16 23 18 20 7 15 14 22 21 8 13 12 11 10 9 + 1 2 3 4 5 0 24 17 19 6 16 23 18 20 7 15 14 22 21 8 13 12 11 10 9 + 1 2 3 4 5 16 24 17 19 6 0 23 18 20 7 15 14 22 21 8 13 12 11 10 9 + 1 2 3 4 5 16 24 17 19 6 15 23 18 20 7 0 14 22 21 8 13 12 11 10 9 + 1 2 3 4 5 16 24 17 19 6 15 23 18 20 7 14 0 22 21 8 13 12 11 10 9 + 1 2 3 4 5 16 24 17 19 6 15 0 18 20 7 14 23 22 21 8 13 12 11 10 9 + 1 2 3 4 5 16 0 17 19 6 15 24 18 20 7 14 23 22 21 8 13 12 11 10 9 + 1 2 3 4 5 16 17 0 19 6 15 24 18 20 7 14 23 22 21 8 13 12 11 10 9 + 1 2 3 4 5 16 17 18 19 6 15 24 0 20 7 14 23 22 21 8 13 12 11 10 9 diff --git a/visu/main.cpp b/visu/main.cpp new file mode 100644 index 0000000..256aa3f --- /dev/null +++ b/visu/main.cpp @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include "ogldev_math_3d.h" +#include +#include +#include + +GLuint VBO; +GLuint gridLocation; +GLuint nLocation; +GLuint timeLocation; + +const char* pVSFileName = "visu/shader.vs"; +const char* pFSFileName = "visu/shader.fs"; +const char* pGridFileName = "./test/visu.txt"; + +static void RenderSceneCB() +{ + glClear(GL_COLOR_BUFFER_BIT); + + string grid_file; + + if (!ReadFile(pGridFileName, grid_file)) + exit(1); + static float time = 0.0f; + time += 0.03; + + stringstream ssin(grid_file); + string token; + string token2; + int garbage[1024]; + int i = 0; + int j = 0; + int x = 0, y = 0; + while (std::getline(ssin, token, '\n')) + { + j = 0; + stringstream ssin2(token); + while (ssin2.good()) + { + ssin2 >> garbage[j]; + j++; + if (j > x) + x = j; + } + i++; + if (i > y) + y = i; + } + int n = (int)sqrt(x); + int grid[y][x]; + stringstream ssin3(grid_file); + i = 0; + while (ssin3.good() && i < x * y) + { + ssin3 >> grid[(int)(i / x)][i % x]; + i++; + } + glUniform1f(timeLocation, time); + glUniform1i(nLocation, n); + if ((int)time < sizeof(grid) / sizeof(*grid)) + glUniform1iv(gridLocation, n * n, grid[(int)time]); + else + exit(1); + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + + // first GL_POINT or GL_TRIANGLES + // second start of draw + // third number of vertices to draw + glDrawArrays(GL_QUADS, 0, 4); + + glDisableVertexAttribArray(0); + + glutSwapBuffers(); +} + +static void InitializeGlutCallbacks(void) +{ + glutDisplayFunc(RenderSceneCB); + glutIdleFunc(RenderSceneCB); +} + +static void CreateVertexBuffer(void) +{ + Vector3f Vertices[4]; + Vertices[0] = Vector3f(-1.0f, -1.0f, 0.0f); + Vertices[1] = Vector3f(1.0f, -1.0f, 0.0f); + Vertices[2] = Vector3f(1.0f, 1.0f, 0.0f); + Vertices[3] = Vector3f(-1.0f, 1.0f, 0.0f); + + glGenBuffers(1, &VBO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW); +} + +static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType) +{ + GLuint ShaderObj = glCreateShader(ShaderType); + + if (ShaderObj == 0) + { + fprintf(stderr, "Error creating shader type %d\n", ShaderType); + exit(0); + } + + const GLchar* p[1]; + p[0] = pShaderText; + GLint Lengths[1]; + Lengths[0] = strlen(pShaderText); + glShaderSource(ShaderObj, 1, p, Lengths); + glCompileShader(ShaderObj); + GLint success; + glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success); + if (!success) + { + GLchar InfoLog[1024]; + glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog); + fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog); + exit(1); + } + + glAttachShader(ShaderProgram, ShaderObj); + +} + +static void CompileShaders() +{ + GLuint ShaderProgram = glCreateProgram(); + + if (ShaderProgram == 0) + { + fprintf(stderr, "Error creating shader program\n"); + exit(1); + } + + string vs; + string fs; + + if (!ReadFile(pVSFileName, vs)) + exit(1); + + if (!ReadFile(pFSFileName, fs)) + exit(1); + + AddShader(ShaderProgram, vs.c_str(), GL_VERTEX_SHADER); + AddShader(ShaderProgram, fs.c_str(), GL_FRAGMENT_SHADER); + + GLint Success = 0; + GLchar ErrorLog[1024] = { 0 }; + + glLinkProgram(ShaderProgram); + glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success); + if (Success == 0) + { + glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); + fprintf(stderr, "Error linking shader program : '%s'\n", ErrorLog); + exit(1); + } + + glValidateProgram(ShaderProgram); + glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success); + if (!Success) + { + glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); + fprintf(stderr, "Invalid shader program '%s'\n", ErrorLog); + exit(1); + } + + glUseProgram(ShaderProgram); + gridLocation = glGetUniformLocation(ShaderProgram, "grid"); + assert(gridLocation != 0xFFFFFFFF); + nLocation = glGetUniformLocation(ShaderProgram, "n"); + assert(nLocation != 0xFFFFFFFF); + timeLocation = glGetUniformLocation(ShaderProgram, "time"); + assert(timeLocation != 0xFFFFFFFF); +} + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); + glutInitWindowSize(800, 600); + glutCreateWindow("N-Puzzle"); + //glutFullScreen(); + + InitializeGlutCallbacks(); + + // Must be done after glut is initialized ! + GLenum res = glewInit(); + if (res != GLEW_OK) + { + fprintf(stderr, "Error : '%s'\n", glewGetErrorString(res)); + return (1); + } + + printf("GL version: %s\n", glGetString(GL_VERSION)); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + CreateVertexBuffer(); + + CompileShaders(); + + glutMainLoop(); + return (0); +} diff --git a/visu/ogldev_math_3d.h b/visu/ogldev_math_3d.h new file mode 100644 index 0000000..f8401c5 --- /dev/null +++ b/visu/ogldev_math_3d.h @@ -0,0 +1,369 @@ +/* + + Copyright 2010 Etay Meiri + + This program 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 3 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see . +*/ + +#ifndef MATH_3D_H +#define MATH_3D_H + +#include +#ifdef WIN32 +#define _USE_MATH_DEFINES +#include +#else +#include +#endif + +#include +#include +#include + +#include "ogldev_util.h" + +#define ToRadian(x) (float)(((x) * M_PI / 180.0f)) +#define ToDegree(x) (float)(((x) * 180.0f / M_PI)) + +float RandomFloat(); + +struct Vector2i +{ + int x; + int y; +}; + +struct Vector2f +{ + float x; + float y; + + Vector2f() + { + } + + Vector2f(float _x, float _y) + { + x = _x; + y = _y; + } +}; + + +struct Vector3f +{ + float x; + float y; + float z; + + Vector3f() {} + + Vector3f(float _x, float _y, float _z) + { + x = _x; + y = _y; + z = _z; + } + + Vector3f(const float* pFloat) + { + x = pFloat[0]; + y = pFloat[0]; + z = pFloat[0]; + } + + Vector3f(float f) + { + x = y = z = f; + } + + Vector3f& operator+=(const Vector3f& r) + { + x += r.x; + y += r.y; + z += r.z; + + return *this; + } + + Vector3f& operator-=(const Vector3f& r) + { + x -= r.x; + y -= r.y; + z -= r.z; + + return *this; + } + + Vector3f& operator*=(float f) + { + x *= f; + y *= f; + z *= f; + + return *this; + } + + operator const float*() const + { + return &(x); + } + + + Vector3f Cross(const Vector3f& v) const; + + Vector3f& Normalize(); + + void Rotate(float Angle, const Vector3f& Axis); + + void Print() const + { + printf("(%.02f, %.02f, %.02f)", x, y, z); + } +}; + + +struct Vector4f +{ + float x; + float y; + float z; + float w; + + Vector4f() + { + } + + Vector4f(float _x, float _y, float _z, float _w) + { + x = _x; + y = _y; + z = _z; + w = _w; + } + + void Print(bool endl = true) const + { + printf("(%.02f, %.02f, %.02f, %.02f)", x, y, z, w); + + if (endl) { + printf("\n"); + } + } + + Vector3f to3f() const + { + Vector3f v(x, y, z); + return v; + } +}; + + + +inline Vector3f operator+(const Vector3f& l, const Vector3f& r) +{ + Vector3f Ret(l.x + r.x, + l.y + r.y, + l.z + r.z); + + return Ret; +} + +inline Vector3f operator-(const Vector3f& l, const Vector3f& r) +{ + Vector3f Ret(l.x - r.x, + l.y - r.y, + l.z - r.z); + + return Ret; +} + +inline Vector3f operator*(const Vector3f& l, float f) +{ + Vector3f Ret(l.x * f, + l.y * f, + l.z * f); + + return Ret; +} + + +inline Vector4f operator/(const Vector4f& l, float f) +{ + Vector4f Ret(l.x / f, + l.y / f, + l.z / f, + l.w / f); + + return Ret; +} + + +struct PersProjInfo +{ + float FOV; + float Width; + float Height; + float zNear; + float zFar; +}; + + +struct OrthoProjInfo +{ + float r; // right + float l; // left + float b; // bottom + float t; // top + float n; // z near + float f; // z far +}; + +struct Quaternion +{ + float x, y, z, w; + + Quaternion(float _x, float _y, float _z, float _w); + + void Normalize(); + + Quaternion Conjugate(); + + Vector3f ToDegrees(); + }; + + +class Matrix4f +{ +public: + float m[4][4]; + + Matrix4f() + { + } + + // constructor from Assimp matrix + Matrix4f(const aiMatrix4x4& AssimpMatrix) + { + m[0][0] = AssimpMatrix.a1; m[0][1] = AssimpMatrix.a2; m[0][2] = AssimpMatrix.a3; m[0][3] = AssimpMatrix.a4; + m[1][0] = AssimpMatrix.b1; m[1][1] = AssimpMatrix.b2; m[1][2] = AssimpMatrix.b3; m[1][3] = AssimpMatrix.b4; + m[2][0] = AssimpMatrix.c1; m[2][1] = AssimpMatrix.c2; m[2][2] = AssimpMatrix.c3; m[2][3] = AssimpMatrix.c4; + m[3][0] = AssimpMatrix.d1; m[3][1] = AssimpMatrix.d2; m[3][2] = AssimpMatrix.d3; m[3][3] = AssimpMatrix.d4; + } + + Matrix4f(const aiMatrix3x3& AssimpMatrix) + { + m[0][0] = AssimpMatrix.a1; m[0][1] = AssimpMatrix.a2; m[0][2] = AssimpMatrix.a3; m[0][3] = 0.0f; + m[1][0] = AssimpMatrix.b1; m[1][1] = AssimpMatrix.b2; m[1][2] = AssimpMatrix.b3; m[1][3] = 0.0f; + m[2][0] = AssimpMatrix.c1; m[2][1] = AssimpMatrix.c2; m[2][2] = AssimpMatrix.c3; m[2][3] = 0.0f; + m[3][0] = 0.0f ; m[3][1] = 0.0f ; m[3][2] = 0.0f ; m[3][3] = 1.0f; + } + + Matrix4f(float a00, float a01, float a02, float a03, + float a10, float a11, float a12, float a13, + float a20, float a21, float a22, float a23, + float a30, float a31, float a32, float a33) + { + m[0][0] = a00; m[0][1] = a01; m[0][2] = a02; m[0][3] = a03; + m[1][0] = a10; m[1][1] = a11; m[1][2] = a12; m[1][3] = a13; + m[2][0] = a20; m[2][1] = a21; m[2][2] = a22; m[2][3] = a23; + m[3][0] = a30; m[3][1] = a31; m[3][2] = a32; m[3][3] = a33; + } + + void SetZero() + { + ZERO_MEM(m); + } + + Matrix4f Transpose() const + { + Matrix4f n; + + for (unsigned int i = 0 ; i < 4 ; i++) { + for (unsigned int j = 0 ; j < 4 ; j++) { + n.m[i][j] = m[j][i]; + } + } + + return n; + } + + + inline void InitIdentity() + { + m[0][0] = 1.0f; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f; + m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f; + m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f; + m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f; + } + + inline Matrix4f operator*(const Matrix4f& Right) const + { + Matrix4f Ret; + + for (unsigned int i = 0 ; i < 4 ; i++) { + for (unsigned int j = 0 ; j < 4 ; j++) { + Ret.m[i][j] = m[i][0] * Right.m[0][j] + + m[i][1] * Right.m[1][j] + + m[i][2] * Right.m[2][j] + + m[i][3] * Right.m[3][j]; + } + } + + return Ret; + } + + Vector4f operator*(const Vector4f& v) const + { + Vector4f r; + + r.x = m[0][0]* v.x + m[0][1]* v.y + m[0][2]* v.z + m[0][3]* v.w; + r.y = m[1][0]* v.x + m[1][1]* v.y + m[1][2]* v.z + m[1][3]* v.w; + r.z = m[2][0]* v.x + m[2][1]* v.y + m[2][2]* v.z + m[2][3]* v.w; + r.w = m[3][0]* v.x + m[3][1]* v.y + m[3][2]* v.z + m[3][3]* v.w; + + return r; + } + + operator const float*() const + { + return &(m[0][0]); + } + + void Print() const + { + for (int i = 0 ; i < 4 ; i++) { + printf("%f %f %f %f\n", m[i][0], m[i][1], m[i][2], m[i][3]); + } + } + + float Determinant() const; + + Matrix4f& Inverse(); + + void InitScaleTransform(float ScaleX, float ScaleY, float ScaleZ); + void InitRotateTransform(float RotateX, float RotateY, float RotateZ); + void InitRotateTransform(const Quaternion& quat); + void InitTranslationTransform(float x, float y, float z); + void InitCameraTransform(const Vector3f& Target, const Vector3f& Up); + void InitPersProjTransform(const PersProjInfo& p); + void InitOrthoProjTransform(const OrthoProjInfo& p); +}; + +Quaternion operator*(const Quaternion& l, const Quaternion& r); + +Quaternion operator*(const Quaternion& q, const Vector3f& v); + +#endif /* MATH_3D_H */ + diff --git a/visu/ogldev_types.h b/visu/ogldev_types.h new file mode 100644 index 0000000..c43df49 --- /dev/null +++ b/visu/ogldev_types.h @@ -0,0 +1,35 @@ +/* + + Copyright 2011 Etay Meiri + + This program 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 3 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see . +*/ + +#ifndef OGLDEV_TYPES_H +#define OGLDEV_TYPES_H + +#ifndef WIN32 +#include +#endif + +#include + +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned char uchar; +typedef int32_t i32; +typedef uint32_t u32; + +#endif /* OGLDEV_TYPES_H */ + diff --git a/visu/ogldev_util.cpp b/visu/ogldev_util.cpp new file mode 100644 index 0000000..41ca06c --- /dev/null +++ b/visu/ogldev_util.cpp @@ -0,0 +1,162 @@ +/* + + Copyright 2014 Etay Meiri + + This program 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 3 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see . + +*/ + +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif + +#include +#include +#include +#include +#include + +#include "ogldev_util.h" + +bool ReadFile(const char* pFileName, string& outFile) +{ + ifstream f(pFileName); + + bool ret = false; + + if (f.is_open()) { + string line; + while (getline(f, line)) { + outFile.append(line); + outFile.append("\n"); + } + + f.close(); + + ret = true; + } + else { + OGLDEV_FILE_ERROR(pFileName); + } + + return ret; +} + + +#ifdef WIN32 + +char* ReadBinaryFile(const char* pFileName, int& size) +{ + HANDLE f = CreateFileA(pFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (f == INVALID_HANDLE_VALUE) { + OGLDEV_FILE_ERROR(pFileName); + return false; + } + + size = GetFileSize(f, NULL); + + if (size == INVALID_FILE_SIZE) { + OGLDEV_ERROR("Invalid file size %s\n", pFileName); + return false; + } + + // wip for tutorial51 + assert(0); + + return true; +} + +#else +char* ReadBinaryFile(const char* pFileName, int& size) +{ + int f = open(pFileName, O_RDONLY); + + if (f == -1) { + OGLDEV_ERROR("Error opening '%s': %s\n", pFileName, strerror(errno)); + return NULL; + } + + struct stat stat_buf; + int error = stat(pFileName, &stat_buf); + + if (error) { + OGLDEV_ERROR("Error getting file stats: %s\n", strerror(errno)); + return NULL; + } + + size = stat_buf.st_size; + + char* p = (char*)malloc(size); + assert(p); + + int read_len = read(f, p, size); + + if (read_len != size) { + OGLDEV_ERROR("Error reading file: %s\n", strerror(errno)); + return NULL; + } + + close(f); + + return p; +} +#endif + +void OgldevError(const char* pFileName, uint line, const char* format, ...) +{ + char msg[1000]; + va_list args; + va_start(args, format); + VSNPRINTF(msg, sizeof(msg), format, args); + va_end(args); + +#ifdef WIN32 + char msg2[1000]; + _snprintf_s(msg2, sizeof(msg2), "%s:%d: %s", pFileName, line, msg); + MessageBoxA(NULL, msg2, NULL, 0); +#else + fprintf(stderr, "%s:%d - %s", pFileName, line, msg); +#endif +} + + +void OgldevFileError(const char* pFileName, uint line, const char* pFileError) +{ +#ifdef WIN32 + char msg[1000]; + _snprintf_s(msg, sizeof(msg), "%s:%d: unable to open file `%s`", pFileName, line, pFileError); + MessageBoxA(NULL, msg, NULL, 0); +#else + fprintf(stderr, "%s:%d: unable to open file `%s`\n", pFileName, line, pFileError); +#endif +} + + +long long GetCurrentTimeMillis() +{ +#ifdef WIN32 + return GetTickCount(); +#else + timeval t; + gettimeofday(&t, NULL); + + long long ret = t.tv_sec * 1000 + t.tv_usec / 1000; + return ret; +#endif +} diff --git a/visu/ogldev_util.h b/visu/ogldev_util.h new file mode 100644 index 0000000..5d41c81 --- /dev/null +++ b/visu/ogldev_util.h @@ -0,0 +1,88 @@ +/* + + Copyright 2014 Etay Meiri + + This program 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 3 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see . +*/ + +#ifndef OGLDEV_UTIL_H +#define OGLDEV_UTIL_H + +#ifndef WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include +#include "ogldev_types.h" + +using namespace std; + +bool ReadFile(const char* fileName, string& outFile); +char* ReadBinaryFile(const char* pFileName, int& size); + +void OgldevError(const char* pFileName, uint line, const char* msg, ... ); +void OgldevFileError(const char* pFileName, uint line, const char* pFileError); + +#define OGLDEV_ERROR0(msg) OgldevError(__FILE__, __LINE__, msg) +#define OGLDEV_ERROR(msg, ...) OgldevError(__FILE__, __LINE__, msg, __VA_ARGS__) +#define OGLDEV_FILE_ERROR(FileError) OgldevFileError(__FILE__, __LINE__, FileError); + +#define ZERO_MEM(a) memset(a, 0, sizeof(a)) +#define ZERO_MEM_VAR(var) memset(&var, 0, sizeof(var)) +#define ARRAY_SIZE_IN_ELEMENTS(a) (sizeof(a)/sizeof(a[0])) + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifdef WIN32 +#define SNPRINTF _snprintf_s +#define VSNPRINTF vsnprintf_s +#define RANDOM rand +#define SRANDOM srand((unsigned)time(NULL)) +#else +#define SNPRINTF snprintf +#define VSNPRINTF vsnprintf +#define RANDOM random +#define SRANDOM srandom(getpid()) +#endif + +#define INVALID_UNIFORM_LOCATION 0xffffffff +#define INVALID_OGL_VALUE 0xffffffff + +#define SAFE_DELETE(p) if (p) { delete p; p = NULL; } + +#define GLExitIfError \ +{ \ + GLenum Error = glGetError(); \ + \ + if (Error != GL_NO_ERROR) { \ + printf("OpenGL error in %s:%d: 0x%x\n", __FILE__, __LINE__, Error); \ + exit(0); \ + } \ +} + +#define GLCheckError() (glGetError() == GL_NO_ERROR) + +long long GetCurrentTimeMillis(); + + +#define ASSIMP_LOAD_FLAGS (aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_JoinIdenticalVertices) + +#endif /* OGLDEV_UTIL_H */ + diff --git a/visu/old_a b/visu/old_a new file mode 100755 index 0000000..5d9684e Binary files /dev/null and b/visu/old_a differ diff --git a/visu/shader.fs b/visu/shader.fs new file mode 100644 index 0000000..877d91b --- /dev/null +++ b/visu/shader.fs @@ -0,0 +1,28 @@ +#version 330 + +uniform float time; +uniform int n; +vec2 resolution = vec2(800, 600); +uniform int grid[1024]; + +void main() +{ + vec2 uv = (gl_FragCoord.xy-0.5*resolution.xy)/resolution.y; + vec3 col = vec3(0); + + vec2 guv = fract(vec2(uv + 0.5 + 1. / float(n)) * float(n)); + vec2 id = floor(vec2(uv + 0.5 + 1. / float(n)) * float(n)); + + float m = 0.; + + if (id.x > 0. && id.x <= float(n) && id.y > 0. && id.y <= float(n)) + { + col.gb = smoothstep(1., float(n), abs(mod(id + time, float(n)) - float(n) / 2.) + 1.); + float d = length(guv - 0.5); + float dist = length(id) * 10.; + float r = mix(.0001, .2, (sin(time) * 0.2 + 1.2) * float(grid[int(float(n) - id.y) * n + int(id.x - 1.)]) / float(n * n)); + m += 1 - smoothstep(r, r * .1, d); + } + col.xyz += vec3(m); + gl_FragColor = vec4(col,1.0); +} diff --git a/visu/shader.vs b/visu/shader.vs new file mode 100644 index 0000000..e5b7171 --- /dev/null +++ b/visu/shader.vs @@ -0,0 +1,10 @@ +#version 330 + +layout (location = 0) in vec3 Position; + +uniform float gScale; + +void main() +{ + gl_Position = vec4(Position.x, Position.y, Position.z, 1.0); +}