Compare commits

..

No commits in common. "7a68447085e64f92cf94bbf49855ae4279199ce4" and "897dd94c24830250061ca7cd68a3450b92ce6cc5" have entirely different histories.

63 changed files with 375 additions and 574257 deletions

View File

@ -1,254 +0,0 @@
import sys
import pygame
import requests
from bs4 import BeautifulSoup, NavigableString
def parse_css(css_text):
"""
A simple CSS parser mapping selectors to a dictionary
of property names and values.
"""
styles = {}
css_text = css_text.replace("\n", "")
blocks = css_text.split("}")
for block in blocks:
if "{" in block:
selector, props = block.split("{", 1)
selector = selector.strip()
props = props.strip()
prop_dict = {}
for declaration in props.split(";"):
if ":" in declaration:
key, value = declaration.split(":", 1)
key = key.strip()
value = value.strip()
# For font-size, store the raw value so percentages can be processed.
if key == "font-size":
prop_dict[key] = value
else:
prop_dict[key] = value
styles[selector] = prop_dict
return styles
def get_computed_style(element, css_styles):
"""
Merge CSS rules (by tag name) with inline style declarations.
"""
style = {}
if element.name in css_styles:
style.update(css_styles[element.name])
if 'style' in element.attrs:
declarations = element['style'].split(";")
for decl in declarations:
if ":" in decl:
key, value = decl.split(":", 1)
style[key.strip()] = value.strip()
return style
def render_element(surface, element, x, y, css_styles, base_font):
"""
Recursively render an element (or text node) on the surface.
Returns the total height rendered.
"""
total_height = 0
# Handle text nodes.
if isinstance(element, NavigableString):
text = str(element).strip()
if text:
text_surface = base_font.render(text, True, pygame.Color("black"))
surface.blit(text_surface, (x, y))
return text_surface.get_height()
return 0
# For tag nodes, compute the style.
computed_style = get_computed_style(element, css_styles)
# Handle margins (defaults: top=0, bottom=5).
try:
margin_top = int(computed_style.get("margin-top", "0"))
except ValueError:
margin_top = 0
try:
margin_bottom = int(computed_style.get("margin-bottom", "5"))
except ValueError:
margin_bottom = 5
total_height += margin_top
# Process font size.
fs_val = computed_style.get("font-size", None)
if fs_val:
fs_val = fs_val.strip()
if fs_val.endswith('%'):
try:
percent = float(fs_val.strip('%'))
font_size = int(base_font.get_height() * percent / 100.0)
except Exception:
font_size = base_font.get_height()
else:
try:
font_size = int(fs_val)
except ValueError:
font_size = base_font.get_height()
else:
font_size = base_font.get_height()
# Process color, with fallback.
color_str = computed_style.get("color", "black")
try:
color = pygame.Color(color_str)
except ValueError:
color = pygame.Color("black")
# Create a new font with the computed font size.
font = pygame.font.SysFont(None, font_size)
# Apply simple tag-based styling.
if element.name == "b":
font.set_bold(True)
elif element.name == "i":
font.set_italic(True)
# Recursively render children.
for child in element.children:
child_height = render_element(surface, child, x, y + total_height, css_styles, font)
total_height += child_height
total_height += margin_bottom
return total_height
def render_html(surface, html, css_text):
"""
Renders the HTML content onto a Pygame surface.
Returns the total height used.
"""
css_styles = parse_css(css_text)
soup = BeautifulSoup(html, "html.parser")
# Remove tags that are non-renderable.
for tag in soup.find_all(["script", "style", "meta", "link", "head"]):
tag.decompose()
y = 10
base_font = pygame.font.SysFont(None, 24)
# Prefer content inside <body>, if available.
body = soup.find("body")
if body:
for element in body.children:
y += render_element(surface, element, 10, y, css_styles, base_font)
else:
for element in soup.contents:
y += render_element(surface, element, 10, y, css_styles, base_font)
return y
def fetch_html(url):
"""
Download the HTML content from a URL.
"""
response = requests.get(url)
response.raise_for_status()
return response.text
def render_html_to_surface(html, css_text, width):
"""
Render the HTML to an offscreen surface for scrolling.
"""
# Create a temporary surface with extra height.
temp_surface = pygame.Surface((width, 3000))
rendered_height = render_html(temp_surface, html, css_text)
# If nothing was rendered (common with complex pages), fallback to plain text.
if rendered_height < 20:
plain_text = BeautifulSoup(html, "html.parser").get_text()
temp_surface.fill((255, 255, 255))
font = pygame.font.SysFont(None, 24)
y = 10
for line in plain_text.splitlines():
line = line.strip()
if line:
text_surface = font.render(line, True, pygame.Color("black"))
temp_surface.blit(text_surface, (10, y))
y += text_surface.get_height() + 5
rendered_height = y
# Create a surface exactly as tall as the rendered content.
content_surface = pygame.Surface((width, rendered_height))
content_surface.blit(temp_surface, (0, 0))
return content_surface, rendered_height
def main():
pygame.init()
screen_width, screen_height = 800, 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("HTML Renderer with URL Fetch, CSS, and Scrolling")
# Fetch HTML from a URL if provided; otherwise, use sample HTML.
if len(sys.argv) > 1:
url = sys.argv[1]
try:
html = fetch_html(url)
except Exception as e:
print(f"Error fetching {url}: {e}")
return
else:
html = """
<html>
<body>
<h1>Hello, Pygame HTML Renderer!</h1>
<p>This is a <b>proof of concept</b> for rendering <i>HTML</i> with CSS in Pygame.</p>
<p style="color: red;">This paragraph is red!</p>
<p style="font-size: 150;">This paragraph is larger.</p>
<p style="margin-top: 20; margin-bottom: 20;">This paragraph has margins!</p>
<p>Scroll down for more content!</p>
</body>
</html>
"""
# A minimal default CSS.
css_text = """
h1 {
font-size: 36;
color: blue;
margin-bottom: 10;
}
p {
font-size: 24;
color: black;
}
"""
# Render the HTML to an offscreen content surface.
content_surface, content_height = render_html_to_surface(html, css_text, screen_width)
scroll_offset = 0
clock = pygame.time.Clock()
max_scroll = max(0, content_height - screen_height)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Handle keyboard scrolling.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
scroll_offset = min(max_scroll, scroll_offset + 20)
elif event.key == pygame.K_UP:
scroll_offset = max(0, scroll_offset - 20)
# Handle mouse wheel scrolling.
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 4: # Wheel up.
scroll_offset = max(0, scroll_offset - 20)
elif event.button == 5: # Wheel down.
scroll_offset = min(max_scroll, scroll_offset + 20)
screen.fill((255, 255, 255))
screen.blit(content_surface, (0, -scroll_offset))
pygame.display.flip()
clock.tick(30)
pygame.quit()
if __name__ == "__main__":
main()

View File

@ -1,9 +0,0 @@
{
"files.associations": {
"*.pyx": "python",
"*.js": "javascript",
"*.c": "c",
"*.scene": "yaml",
"ostream": "cpp"
}
}

View File

@ -1,10 +0,0 @@
albedo: [1, 1, 1]
metallic: 0
roughness: 0.0500000007
ao: 0
albedo_texture: C:\Users\spenc\Downloads\alien-carnivorous-plant-bl\alien-carnivorous-plant-bl\alien-carniverous-plant_albedo.png
metallic_texture: C:\Users\spenc\Downloads\alien-carnivorous-plant-bl\alien-carnivorous-plant-bl\alien-carniverous-plant_metallic.png
roughness_texture: C:\Users\spenc\Downloads\alien-carnivorous-plant-bl\alien-carnivorous-plant-bl\alien-carniverous-plant_roughness.png
ao_texture: C:\Users\spenc\Downloads\alien-carnivorous-plant-bl\alien-carnivorous-plant-bl\alien-carniverous-plant_ao.png
normal_texture: C:\Users\spenc\Downloads\alien-carnivorous-plant-bl\alien-carnivorous-plant-bl\alien-carniverous-plant_normal-ogl.png
height_texture: C:\Users\spenc\Downloads\alien-carnivorous-plant-bl\alien-carnivorous-plant-bl\alien-carniverous-plant_height.png

View File

@ -1,9 +0,0 @@
albedo: [1, 0, 0]
metallic: 1
roughness: 1
ao: 1
albedo_texture: C:\Users\spenc\Downloads\alley-brick-wall-bl\alley-brick-wall-bl\alley-brick-wall_albedo.png
metallic_texture: C:\Users\spenc\Downloads\alley-brick-wall-bl\alley-brick-wall-bl\alley-brick-wall_metallic.png
roughness_texture: C:\Users\spenc\Downloads\alley-brick-wall-bl\alley-brick-wall-bl\alley-brick-wall_roughness.png
ao_texture: C:\Users\spenc\Downloads\alley-brick-wall-bl\alley-brick-wall-bl\alley-brick-wall_ao.png
normal_texture: C:\Users\spenc\Downloads\alley-brick-wall-bl\alley-brick-wall-bl\alley-brick-wall_normal-ogl.png

View File

@ -4,7 +4,7 @@ Size=400,400
Collapsed=0
[Window][Scene Controls]
Pos=13,10
Size=484,570
Pos=121,151
Size=334,445
Collapsed=0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -6,5 +6,4 @@ albedo_texture: C:\Users\spenc\Downloads\used-stainless-steel-bl\used-stainless-
metallic_texture: C:\Users\spenc\Downloads\used-stainless-steel-bl\used-stainless-steel-bl\used-stainless-steel_metallic.png
roughness_texture: C:\Users\spenc\Downloads\used-stainless-steel-bl\used-stainless-steel-bl\used-stainless-steel_roughness.png
ao_texture: C:\Users\spenc\Downloads\used-stainless-steel-bl\used-stainless-steel-bl\used-stainless-steel_ao.png
normal_texture: C:\Users\spenc\Downloads\used-stainless-steel-bl\used-stainless-steel-bl\used-stainless-steel_normal-ogl.png
height_texture: C:\Users\spenc\Downloads\used-stainless-steel-bl\used-stainless-steel-bl\used-stainless-steel_height.png
normal_texture: C:\Users\spenc\Downloads\used-stainless-steel-bl\used-stainless-steel-bl\used-stainless-steel_normal-ogl.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 588 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 KiB

View File

@ -1,306 +0,0 @@
# Blender MTL File: 'None'
# Material Count: 25
newmtl Material__25
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/lion.tga
map_Disp textures/lion_ddn.tga
map_Ka textures/lion.tga
newmtl Material__298
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/background.tga
map_Disp textures/background_ddn.tga
map_Ka textures/background.tga
newmtl Material__47
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
newmtl Material__57
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd textures/vase_plant.tga
map_d textures/vase_plant_mask.tga
map_Ka textures/vase_plant.tga
newmtl arch
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_arch_diff.tga
map_Ka textures/sponza_arch_diff.tga
map_Disp textures/sponza_arch_ddn.tga
newmtl bricks
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/spnza_bricks_a_diff.tga
map_Disp textures/spnza_bricks_a_ddn.tga
map_Ka textures/spnza_bricks_a_diff.tga
newmtl ceiling
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_ceiling_a_diff.tga
map_Ka textures/sponza_ceiling_a_diff.tga
map_Disp textures/sponza_ceiling_a_ddn.tga
newmtl chain
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd textures/chain_texture.tga
map_d textures/chain_texture_mask.tga
map_Disp textures/chain_texture_ddn.tga
map_Ka textures/chain_texture.tga
newmtl column_a
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_column_a_diff.tga
map_Disp textures/sponza_column_a_ddn.tga
map_Ka textures/sponza_column_a_diff.tga
newmtl column_b
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_column_b_diff.tga
map_Disp textures/sponza_column_b_ddn.tga
map_Ka textures/sponza_column_b_diff.tga
newmtl column_c
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_column_c_diff.tga
map_Disp textures/sponza_column_c_ddn.tga
map_Ka textures/sponza_column_c_diff.tga
newmtl details
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_details_diff.tga
map_Ka textures/sponza_details_diff.tga
map_Disp textures/sponza_details_ddn.tga
newmtl fabric_a
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_fabric_diff.tga
map_Ka textures/sponza_fabric_diff.tga
map_Disp textures/sponza_fabric_ddn.tga
newmtl fabric_c
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_curtain_diff.tga
map_Ka textures/sponza_curtain_diff.tga
map_Disp textures/sponza_curtain_ddn.tga
newmtl fabric_d
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_fabric_blue_diff.tga
map_Ka textures/sponza_fabric_blue_diff.tga
map_Disp textures/sponza_fabric_ddn.tga
newmtl fabric_e
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_fabric_green_diff.tga
map_Ka textures/sponza_fabric_green_diff.tga
map_Disp textures/sponza_fabric_ddn.tga
newmtl fabric_f
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_curtain_green_diff.tga
map_Ka textures/sponza_curtain_green_diff.tga
map_Disp textures/sponza_curtain_ddn.tga
newmtl fabric_g
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_curtain_blue_diff.tga
map_Ka textures/sponza_curtain_blue_diff.tga
map_Disp textures/sponza_curtain_ddn.tga
newmtl flagpole
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_flagpole_diff.tga
map_Ka textures/sponza_flagpole_diff.tga
map_Disp textures/sponza_flagpole_ddn.tga
newmtl floor
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_floor_a_diff.tga
map_Ka textures/sponza_floor_a_diff.tga
map_Disp textures/sponza_floor_a_ddn.tga
newmtl leaf
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd textures/sponza_thorn_diff.tga
map_d textures/sponza_thorn_mask.tga
map_Disp textures/sponza_thorn_ddn.tga
map_Ka textures/sponza_thorn_diff.tga
newmtl roof
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_roof_diff.tga
map_Ka textures/sponza_roof_diff.tga
map_Disp textures/sponza_roof_ddn.tga
newmtl vase
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/vase_dif.tga
map_Ka textures/vase_dif.tga
map_Disp textures/vase_ddn.tga
newmtl vase_hanging
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/vase_hanging.tga
map_Ka textures/vase_hanging.tga
map_Disp textures/vase_hanging_ddn.tga
newmtl vase_round
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/vase_round.tga
map_Disp textures/vase_round_ddn.tga
map_Ka textures/vase_round.tga

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB