Initial commit - that's out of the way.

This commit is contained in:
Thomas Touhey 2017-03-07 01:17:53 +01:00
commit 10a973e2f1
15 changed files with 1210 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/Makefile.cfg
/obj
/lib*.a
/lib*-*.tar.gz

6
AUTHORS.md Normal file
View File

@ -0,0 +1,6 @@
# libwindmill authors
Copyright (C) 2017 Olivier "Ninestars" Lanneau
Copyright (C) 2017 Thomas "Cakeisalie5" Touhey
Ninestars was the one thinking and making the actual code, I (Cakeisalie5)
just came along and reorganized the project.

3
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,3 @@
# Contributing to libwindmill
For now, external contributions aren't allowed, as the project is in
very alpha. Maybe later :)

157
LICENSE.md Normal file
View File

@ -0,0 +1,157 @@
### GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
<http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates the
terms and conditions of version 3 of the GNU General Public License,
supplemented by the additional permissions listed below.
#### 0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the
GNU General Public License.
"The Library" refers to a covered work governed by this License, other
than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
#### 1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
#### 2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
- a) under this License, provided that you make a good faith effort
to ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
- b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
#### 3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from a
header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
- a) Give prominent notice with each copy of the object code that
the Library is used in it and that the Library and its use are
covered by this License.
- b) Accompany the object code with a copy of the GNU GPL and this
license document.
#### 4. Combined Works.
You may convey a Combined Work under terms of your choice that, taken
together, effectively do not restrict modification of the portions of
the Library contained in the Combined Work and reverse engineering for
debugging such modifications, if you also do each of the following:
- a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
- b) Accompany the Combined Work with a copy of the GNU GPL and this
license document.
- c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
- d) Do one of the following:
- 0) Convey the Minimal Corresponding Source under the terms of
this License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
- 1) Use a suitable shared library mechanism for linking with
the Library. A suitable mechanism is one that (a) uses at run
time a copy of the Library already present on the user's
computer system, and (b) will operate properly with a modified
version of the Library that is interface-compatible with the
Linked Version.
- e) Provide Installation Information, but only if you would
otherwise be required to provide such information under section 6
of the GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the Application
with a modified version of the Linked Version. (If you use option
4d0, the Installation Information must accompany the Minimal
Corresponding Source and Corresponding Application Code. If you
use option 4d1, you must provide the Installation Information in
the manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.)
#### 5. Combined Libraries.
You may place library facilities that are a work based on the Library
side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
- a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities, conveyed under the terms of this License.
- b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
#### 6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
as you received it specifies that a certain numbered version of the
GNU Lesser General Public License "or any later version" applies to
it, you have the option of following the terms and conditions either
of that published version or of any later version published by the
Free Software Foundation. If the Library as you received it does not
specify a version number of the GNU Lesser General Public License, you
may choose any version of the GNU Lesser General Public License ever
published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

120
Makefile Executable file
View File

@ -0,0 +1,120 @@
#!/usr/bin/make -f
#******************************************************************************#
# Include variables and message subsystem #
#******************************************************************************#
include Makefile.vars Makefile.msg
#******************************************************************************#
# General targets #
#******************************************************************************#
# Build everything.
all: all-lib
# Mostly clean everything. (remove everything but the end results)
mostlyclean: mostlyclean-lib
mclean: mostlyclean
# Clean everything.
clean fclean: clean-lib
$(call qcmd,$(RM) -r lib$(NAME)-*)
# Clean everything, and configuration.
mrproper: clean
$(call rmsg,Removing configuration.)
$(call qcmd,$(RM) Makefile.cfg)
# Make a distribution tarball
dist: mrproper
$(call bcmd,mkdir,lib$(NAME)-$(VERSION),\
$(MD) .dist)
$(call bcmd,cp,* lib$(NAME)-$(VERSION),\
$(CP) -R * .dist)
$(call qcmd,\
$(MV) .dist lib$(NAME)-$(VERSION))
$(call bcmd,tarball,lib$(NAME)-$(VERSION),\
tar czf lib$(NAME)-$(VERSION).tar.gz \
--exclude .git lib$(NAME)-$(VERSION))
$(call qcmd,$(RM) -r lib$(NAME)-$(VERSION))
# Remake everything. (clean and build)
re: clean all
.PHONY: all mostlyclean mclean clean fclean dist mrproper re
#******************************************************************************#
# Configuration (version) checking dependencies #
#******************************************************************************#
# Define the dependencies.
CHECKCFG := $(if $(shell test -f Makefile.cfg || echo y),check-config, \
$(if $(shell [ "$(VERSION)" = "$(CONFIG_VERSION)" ] || echo y), \
check-config-version))
# Define the rules.
check-config:
@echo -e "\033[1;31mNo configuration file found!"
@echo -e "You should configure before re-running this target.\033[0m"
@false
check-config-version:
@echo -e "\033[1;31mConfiguration version is incorrect!"
@echo -e "You should re-configure before re-running this target.\033[0m"
@false
.PHONY: check-config check-config-version
#******************************************************************************#
# Information getting from the Makefile variables #
#******************************************************************************#
# Get the project name.
getname:
@echo lib$(NAME)
# Get the maintainer
getmaintainer:
@echo "$(MAINTAINER_NAME) <$(MAINTAINER_MAIL)>"
# Get the project version.
getversion:
@echo "$(VERSION)"
.PHONY: getname getmaintainer getversion
#******************************************************************************#
# Library-specific targets #
#******************************************************************************#
# Make the library.
all-lib: $(CHECKCFG) lib$(NAME).a
# Make an object directory.
$(OBJDIR)/ $(DIRS:%=$(OBJDIR)/%):
$(call bcmd,mkdir,$@,$(MD) $@)
# Make an object out of a source file.
define make-obj-rules
ifeq ($(shell test -f $(SRCDIR)/$1.c && echo y),y)
$(OBJDIR)/$1.o: $(SRCDIR)/$1.c $(INC) | $(dir $(OBJDIR)/$1)
$(call bcmd,cc,$$@,$(CC) -c -o $$@ $$< $(CFLAGS))
else
$(OBJDIR)/$1.o: $(SRCDIR)/$1.s | $(dir $(OBJDIR)/$1)
$(call bcmd,as,$$@,$(AS) -c -o $$@ $$< $(ASFLAGS))
endif
endef
$(foreach src,$(SRC), \
$(eval $(call make-obj-rules,$(src))))
# Make the library.
lib$(NAME).a: $(SRC:%=$(OBJDIR)/%.o)
$(call bcmd,ar rcs,$@,$(AR) rc $@ $^)
# Remove the objects directory.
mostlyclean-lib:
$(call rmsg,Removing object directory.)
$(call qcmd,$(RM) -r $(OBJDIR))
mclean-lib: mostlyclean-lib
# Clean and remove the built library.
clean-lib: mclean-lib
$(call rmsg,Removing the library.)
$(call qcmd,$(RM) lib$(NAME).a)
# Remake the library.
re-lib: clean-lib all-lib
.PHONY: all-lib mostlyclean-lib mclean-lib clean-lib re-lib
# End of file.

58
Makefile.msg Executable file
View File

@ -0,0 +1,58 @@
#!/usr/bin/make -f
# The Makefile message subsystem.
# For nice logs. 5 dollars per log only.
#******************************************************************************#
# Colors and misc #
#******************************************************************************#
# Used colors ANSI modifiers escape codes
color_green := 32
color_red := 31
color_yellow := 33
# Newline - comes handy in some situations
define \n
endef
#******************************************************************************#
# General messages #
#******************************************************************************#
# Command message - display basic info about the command, and run it.
define cmd
@$(if $(MAKE_FULL_LOG),,printf "\033[1;""$4""m>\033[0m \033[1m%s\033[0m %s\n" "$1" "$2";)
$(if $(MAKE_FULL_LOG),,@)$3
endef
# Quiet command - make it non-quiet if full log is enabled.
define qcmd
$(if $(MAKE_FULL_LOG),,@)$1
endef
# Normal message - display it.
define msg
$(if $(MAKE_FULL_LOG),,@printf "\033[1;""$2""m>\033[0m \033[1m%s\033[0m\n" "$1")
endef
#******************************************************************************#
# Commands #
#******************************************************************************#
# Build command
define bcmd
$(call cmd,$1,$2,$3,$(color_green))
endef
#******************************************************************************#
# Messages #
#******************************************************************************#
# Remove message
define rmsg
$(call msg,$1,$(color_red))
endef
# Install message
define imsg
$(call msg,$1,$(color_yellow))
endef
# End of file

82
Makefile.vars Executable file
View File

@ -0,0 +1,82 @@
#!/usr/bin/make -f
#******************************************************************************#
# Include configuration #
#******************************************************************************#
-include Makefile.cfg
#******************************************************************************#
# Project main information #
#******************************************************************************#
# Project name and supported targets
NAME := windmill
# Maintainer information
MAINTAINER_NAME := Thomas \"Cakeisalie5\" Touhey
MAINTAINER_MAIL := thomas@touhey.fr
# Project version
MAJOR := 0
MINOR := 1
INDEV := yes
# Project version string
VERSION := $(MAJOR).$(MINOR)$(if $(INDEV),-indev)
#******************************************************************************#
# Project directories #
#******************************************************************************#
# Headers directory - where all the headers are.
INCDIR := ./include
# Sources directory - where all the sources are.
SRCDIR := ./src
# Objects directory - where the objects will be put.
OBJDIR := ./obj
#******************************************************************************#
# Binary utilities #
#******************************************************************************#
# Compiler
CC := sh3eb-elf-gcc
# - Check flags (warnings)
CWARN := -Wall -Wextra -Wno-attributes
# - For random manipulations (profiling, ...)
#CMOREFLAGS :=
# - All C compiling flags
CFLAGS := $(CWARN) -I $(INCDIR) -std=gnu11 -O2 -ffreestanding
# Assembler
AS := sh3eb-elf-as
# - All assembling flags
ASFLAGS :=
# Archiver
AR := sh3eb-elf-ar
# Directory maker
MD := mkdir -p
# Symbolic link maker
LN := ln -sf
# Copier
CP := cp
# Mover
MV := mv
# File remover
RM := rm -f
# Installer
INST := install
# GZipper
GZIP := gzip -f
#******************************************************************************#
# Look for modules and modules sources #
#******************************************************************************#
# Look up the sources
SRC := $(basename $(shell find $(SRCDIR) -mindepth 1 -type f \
-name "*.[cs]" -printf "%P\n"))
DIRS := $(sort $(dir $(SRC)))
# Look up the includes
INC := $(shell find $(INCDIR) -mindepth 1 -name "*.h")
# End of file.

48
README.md Normal file
View File

@ -0,0 +1,48 @@
# libwindmill - a 3D engine for your CASIO fx-9860G
## Introduction
Windmill is a 3D engine project by Ninestars, originally developed in C++ and
built with the CASIO fx-9860G SDK. It was adapted to compile with GNU
utilities by Cakeisalie5.
This 3D engine is made to be easy to use, and modular, in order to quickly
create a game, or to use it in an existing project.
It features the following:
* Calculates coordinates to display them on screen;
* Camera that can move in any direction and turn around using two axes;
* Management of display windows;
* Depth buffer so objects hidden behind others aren't displayed;
* Display of textures defined as images;
* Simplified management of meshes and textures;
* Display of fixed and dynamic objects that can turn following three axes;
* Simultaneous renders.
Windmill is only a graphical engine, it only displays predefined triangles
in space on the screen, which means it doesn't manage collisions between
objects, or between an object and the camera.
## Requirements/setup
This project is easier to build under GNU/Linux. It might be possible to
build it for Microsoft Windows, but this host platform is not officially
supported.
You will need [GCC][gcc] and [GNU Binutils][binutils], both compiled for the
`sh3eb-elf` target, and the [G1A wrapper][wrapper]. A french tutorial of how
to make and install all of these can be found [on Planète Casio][pc-gcc-tuto]
(steps 1 to 6 included).
## Build
Just type in the following:
./configure && make
## Miscellaneous information
For the authors of the project, check `AUTHORS.md`.
For the license of the project, check `LICENSE.md`.
If you want to contribute to this project, check the contribution guide
in the `CONTRIBUTING.md` file.
[gcc]: https://gcc.gnu.org/
[binutils]: https://www.gnu.org/software/binutils/
[wrapper]: https://bitbucket.org/Lephenixnoir/add-in-wrapper.git
[pc-gcc-tuto]: http://www.planet-casio.com/Fr/programmation/tutoriels.php?id=61

96
configure vendored Executable file
View File

@ -0,0 +1,96 @@
#!/bin/sh
cd "$(dirname $0)"
#******************************************************************************#
# Defaults #
#******************************************************************************#
# Project variables
name="$(make -s getname)"
version="$(make -s getversion)"
# Maintainer info
maintainer="$(make -s getmaintainer)"
# Make options
make_full_log=
#******************************************************************************#
# Help message #
#******************************************************************************#
usage() {
cat <<EOF
\`configure\` configures ${name} to adapt to systems that aren't mine.
Usage: $0 [OPTION]
Defaults for the options are specified in brackets.
General options:
--help display this help and exit
--version display version information and quit
--make-full-log display full commands while making
Report bugs to ${maintainer}.
EOF
exit 0
}
#******************************************************************************#
# Version message #
#******************************************************************************#
version() {
cat <<EOF
${name} configure script v${version}
Hand-written by Thomas "Cakeisalie5" Touhey.
This configure script is free software.
There is NO warranty; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
EOF
exit 0
}
#******************************************************************************#
# Check for help and version #
#******************************************************************************#
put_version=
put_help=
for arg ; do case "$arg" in
--help|-h) put_help=1 ;;
--version|-v) put_version=1 ;;
esac; done
[ $put_version ] && version
[ $put_help ] && usage
#******************************************************************************#
# Parse arguments #
#******************************************************************************#
for arg ; do case "$arg" in
--make-full-log) make_full_log=yes ;;
*) echo "$arg: didn't read" ;;
esac; done
#******************************************************************************#
# Create Makefile configuration #
#******************************************************************************#
# Clean before.
make mrproper MAKE_FULL_LOG=y 1>/dev/null 2>/dev/null
# Do it!
exec 3>&1 1>Makefile.cfg
cat <<EOF
#!/usr/bin/make -f
#******************************************************************************#
# Makefile configuration generated by ./configure #
#******************************************************************************#
# Configuration version and messages configuration
CONFIG_VERSION = $version
MAKE_FULL_LOG = $make_full_log
# End of file.
EOF
exec 1>&3 3>&-
chmod +x Makefile.cfg
# Put the lil' message.
echo "Configuration loaded, you can make now."
# End of file.

156
include/libwindmill.h Normal file
View File

@ -0,0 +1,156 @@
/* *****************************************************************************
* libwindmill.h -- 3D rendering engine.
* Copyright (C) 2017 Olivier "Ninestars" Lanneau
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libwindmill.
* libwindmill is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libwindmill 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libwindmill; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#ifndef LIBWINDMILL_H
# define LIBWINDMILL_H
# include <stdlib.h>
# include <string.h>
# include <math.h>
# define N 0
# define X 1
# define Y 2
# define Z 3
# define XC 4
# define YC 5
# define ZC 6
/* ************************************************************************** */
/* Types */
/* ************************************************************************** */
/* a vertex */
typedef struct Vertex {
int x, y, z;
char tx, ty;
int z_normalized;
} wml_vertex_t;
/* a texture */
typedef struct Texture {
const unsigned char *sprite;
char width, height, offset;
} wml_texture_t;
/* a triangle */
typedef struct Triangle {
/* coordinates */
short x0, y0, z0;
short x1, y1, z1;
short x2, y2, z2;
/* textures */
struct Texture *texture_front;
struct Texture *texture_back;
} wml_triangle_t;
/* a rectangle */
typedef struct Rectangle {
/* coordinates */
short x0, y0, z0;
short x1, y1, z1;
short x2, y2, z2;
/* textures */
struct Texture *texture_front;
struct Texture *texture_back;
} wml_rectangle_t;
/* an object */
typedef struct Object {
/* coordinates */
int x, y, z;
char axe; float angle;
/* rectangles */
wml_rectangle_t *list_rect;
int list_rect_size;
/* triangles */
wml_triangle_t *list_tri;
int list_tri_size;
} wml_object_t;
/* a map */
typedef struct Map {
int id;
/* objects */
struct Object **list_object;
int list_object_size;
} wml_map_t;
/* a scene */
typedef struct Scene {
/* flow control */
int stop_execution;
/* camera */
float camera_x, camera_y, camera_z;
float camera_yaw, camera_pitch;
int scale_coef, near, far;
float near_coef;
int far_coef;
float div_coef;
int viewport_x1, viewport_y1, viewport_x2, viewport_y2;
int shift_x, shift_y;
unsigned short *z_buffer;
int z_buffer_size, z_buffer_offset, z_buffer_width;
/* texture, map, background */
struct Texture *hidden, *black, *white;
struct Map map;
const unsigned char *background;
/* i don't know what this is, yet */
int a1, a2, a3, a4, a5, a6, a7, a8, a9;
} wml_scene_t;
/* ************************************************************************** */
/* Functions */
/* ************************************************************************** */
/* update things */
void wml_update_camera(wml_scene_t *scene);
void wml_update_viewport(wml_scene_t *scene);
/* render */
void wml_render_draw(wml_scene_t *scene);
void wml_dynamic(wml_vertex_t *vertex,
int axe, int x, int y, int z,
float cosinus, float sinus);
void wml_transform(wml_scene_t *scene, wml_vertex_t *vertex);
void wml_render_triangle(wml_scene_t *scene,
wml_vertex_t *vertex1, wml_vertex_t *vertex2, wml_vertex_t *vertex3,
wml_texture_t *texture);
void wml_render_triangle_black(wml_scene_t *scene,
wml_vertex_t *vertex1, wml_vertex_t *vertex2, wml_vertex_t *vertex3,
wml_texture_t *texture);
void wml_render_triangle_white(wml_scene_t *scene,
wml_vertex_t *vertex1, wml_vertex_t *vertex2, wml_vertex_t *vertex3,
wml_texture_t *texture);
void wml_edge(wml_vertex_t *a, wml_vertex_t *b, wml_vertex_t *c);
void wml_edge_start(wml_vertex_t *a, wml_vertex_t *b, int px, int py);
void wml_edge_step_x(wml_vertex_t *a, wml_vertex_t *b);
void wml_edge_step_y(wml_vertex_t *a, wml_vertex_t *b);
void wml_move_camera_face(wml_scene_t *scene, float value);
void wml_move_camera_side(wml_scene_t *scene, float value);
#endif /* LIBWINDMILL_H */

View File

@ -0,0 +1,27 @@
/* *****************************************************************************
* libwindmill/internals.h -- libwindmill internal utilities.
* Copyright (C) 2017 Olivier "Ninestars" Lanneau
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libwindmill.
* libwindmill is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libwindmill 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libwindmill; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#ifndef LIBWINDMILL_INTERNALS_H
# define LIBWINDMILL_INTERNALS_H
# include <libwindmill.h>
void wml_set_vertex_xyz(wml_vertex_t *vertex, int x, int y, int z);
void wml_set_vertex_txy(wml_vertex_t *vertex, char tx, char ty);
#endif /* LIBWINDMILL_INTERNALS_H */

191
src/draw.c Normal file
View File

@ -0,0 +1,191 @@
/* *****************************************************************************
* draw.c -- draw the scene.
* Copyright (C) 2017 Olivier "Ninestars" Lanneau
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libwindmill.
* libwindmill is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libwindmill 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libwindmill; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include <libwindmill/internals.h>
/* ************************************************************************** */
/* Rectangle */
/* ************************************************************************** */
static void render_rectangle_part(wml_scene_t *scene,
wml_texture_t *texture, wml_vertex_t *vertex0,
wml_vertex_t *vertex1, wml_vertex_t *vertex2,
wml_vertex_t *vertex3)
{
if (texture == hidden) {
/* do nothing */
} else if (texture == scene->black) {
wml_render_triangle_black(scene, vertex0, vertex1, vertex2);
wml_render_triangle_black(scene, vertex1, vertex3, vertex2);
} else if (texture == scene->white) {
wml_render_triangle_white(scene, vertex0, vertex1, vertex2);
wml_render_triangle_white(scene, vertex1, vertex3, vertex2);
} else {
wml_set_vertex_txy(vertex0, 0, texture->height);
wml_set_vertex_txy(vertex1, texture->width, texture->height);
wml_set_vertex_txy(vertex2, 0, 0);
wml_set_vertex_txy(vertex3, texture->width, 0);
wml_render_triangle(scene, vertex0, vertex1, vertex2, texture);
wml_render_triangle(scene, vertex1, vertex3, vertex2, texture);
}
}
static void render_rectangle(wml_scene_t *scene, wml_polygon_t *polygon,
float cosinus, float sinus)
{
wml_vertex_t vertex0, vertex1, vertex2, vertex3;
int x0 = polygon->x0, y0 = polygon->y0, z0 = polygon->z0;
int x1 = polygon->x1, y1 = polygon->y1, z1 = polygon->z1;
int x2 = polygon->x2, y2 = polygon->y2, z2 = polygon->z2;
int x3 = x1 + x2 - x0, y3 = y1 + y2 - y0, z3 = z1 + z2 - z0;
wml_set_vertex_xyz(&vertex0, x0, y0, z0);
wml_set_vertex_xyz(&vertex1, x1, y1, z1);
wml_set_vertex_xyz(&vertex2, x2, y2, z2);
wml_set_vertex_xyz(&vertex3, x3, y3, z3);
/* object dynamique */
wml_dynamic(&vertex0, polygon->axe,
current_object->x, polygon->y, cosinus, sinus);
wml_dynamic(&vertex1, polygon->axe,
current_object->x, polygon->y, cosinus, sinus);
wml_dynamic(&vertex2, polygon->axe,
current_object->x, polygon->y, cosinus, sinus);
wml_dynamic(&vertex3, polygon->axe,
current_object->x, polygon->y, cosinus, sinus);
/* calcul des coordonnées après rotation de la caméra et projection
* des coordonnées 3D sur l'écran */
wml_transform(&vertex0);
wml_transform(&vertex1);
wml_transform(&vertex2);
wml_transform(&vertex3);
/* si devant la caméra */
if (vertex0.z < 0 && vertex1.z < 0 && vertex2.z < 0
&& vertex3.z < 0) {
int area = wml_edge(&vertex0, &vertex1, &vertex2);
if (area > 0) render_rectangle_part(scene,
current_rect->texture_front,
&vertex0, &vertex1, &vertex2, &vertex3);
if (area < 0) render_rectangle_part(scene,
current_rect->texture_back,
&vertex0, &vertex2, &vertex1, &vertex3);
}
}
/* ************************************************************************** */
/* Triangle */
/* ************************************************************************** */
static void render_triangle_part(wml_scene_t *scene,
wml_texture_t *texture, wml_vertex_t *vertex0,
wml_vertex_t *vertex1, wml_vertex_t *vertex2)
{
if (texture == hidden) {
/* do nothing */
} else if (texture == scene->black) {
wml_render_triangle_black(scene, vertex0, vertex1, vertex2);
} else if (texture == scene->white) {
wml_render_triangle_white(scene, vertex0, vertex1, vertex2);
} else {
wml_set_vertex_txy(vertex0, 0, texture->height);
wml_set_vertex_txy(vertex1, texture->width, texture->height);
wml_set_vertex_txy(vertex2, texture->width, 0);
wml_render_triangle(scene, vertex0, vertex1, vertex2, texture);
}
}
static void render_triangle(wml_scene_t *scene,
wml_object_t *object, wml_triangle_t *triangle,
float cosinus, float sinus)
{
wml_vertex_t vertex0, vertex1, vertex2;
int x0 = triangle->x0, y0 = triangle->y0, z0 = triangle->z0;
int x1 = triangle->x1, y1 = triangle->y1, z1 = triangle->z1;
int x2 = triangle->x2, y2 = triangle->y2, z2 = triangle->z2;
wml_set_vertex_xyz(&vertex0, x0, y0, z0);
wml_set_vertex_xyz(&vertex1, x1, y1, z1);
wml_set_vertex_xyz(&vertex2, x2, y2, z2);
/* object dynamique */
wml_dynamic(&vertex0, triangle->axe,
object->x, object->y, cosinus, sinus);
wml_dynamic(&vertex1, polygon->axe,
object->x, object->y, cosinus, sinus);
wml_dynamic(&vertex2, polygon->axe,
object->x, object->y, cosinus, sinus);
/* calcul des coordonnées après rotation de la caméra et projection
* des coordonnées 3D sur l'écran */
wml_transform(&vertex0);
wml_transform(&vertex1);
wml_transform(&vertex2);
/* si devant la caméra */
if (vertex0.z < 0 && vertex1.z < 0 && vertex2.z < 0) {
int area = wml_edge(&vertex0, &vertex1, &vertex2);
if (area > 4) render_triangle_part(scene,
current_rect->texture_front,
&vertex0, &vertex1, &vertex2, &vertex3);
if (area < 4) render_triangle_part(scene,
current_rect->texture_back,
&vertex0, &vertex2, &vertex1, &vertex3);
}
}
/* ************************************************************************** */
/* Main function */
/* ************************************************************************** */
/**
* wml_render_draw:
* Render.
*
* @arg scene the scene to render.
*/
void wml_render_draw(wml_scene_t *scene)
{
wml_update_camera(scene);
memset(scene->z_buffer, 0xFF, scene->z_buffer_size * 2);
for (int i = 0; i < scene->map.list_object_size; i++) {
wml_object_t *current_object = scene->map.list_object[i];
/* object dynamique */
float cosinus, sinus;
if (current_object->axe == N) {
cosinus = 0;
sinus = 1;
} else {
cosinus = cosf(current_object->angle);
sinus = sinf(current_object->angle);
}
for (int j = 0; j < current_object->list_rect_size; j++)
render_rectangle(scene, &current_object->list_rect[j],
cosinus, sinus);
for (int j = 0; j < current_object->list_tri_size; j++)
render_triangle(scene, &current_object->list_tri[j],
cosinus, sinus);
}
}

69
src/dynamic.c Normal file
View File

@ -0,0 +1,69 @@
/* *****************************************************************************
* dynamic.c -- dynamic thingies.
* Copyright (C) 2017 Olivier "Ninestars" Lanneau
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libwindmill.
* libwindmill is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libwindmill 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libwindmill; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include <libwindmill/internals.h>
void wml_dynamic(wml_vertex_t *vertex, int axe, int x, int y, int z,
float cosinus, float sinus)
{
int vertex_x = vertex->x,
vertex_y = vertex->y,
vertex_z = vertex->z;
if (axe == N) {
vertex->x = vertex_x + x;
vertex->y = vertex_y + y;
vertex->z = vertex_z + z;
} else if (axe == X) {
vertex->x = vertex_x + x;
vertex->y = vertex_y * cosinus - vertex_z * sinus + y;
vertex->z = vertex_z * sinus + vertex_z * cosinus + z;
} else if (axe == Y) {
vertex->x = vertex_x * cosinus - vertex_z * sinus + x;
vertex->y = vertex_y + y;
vertex->z = vertex_x * sinus + vertex_z * cosinus + z;
} else if (axe == Z) {
vertex->x = vertex_x * cosinus - vertex_y * sinus + x;
vertex->y = vertex_x * sinus + vertex_y * cosinus + y;
vertex->z = vertex_z + z;
}
}
void wml_transform(wml_scene_t *scene, wml_vertex_t *vertex)
{
int vertex_x = vertex->x - (int)scene->camera_x,
vertex_y = vertex->y - (int)scene->camera_y,
vertex_z = vertex->z - (int)scene->camera_z;
/* produit matriciel */
int x = scene->a1 * vertex_x + scene->a2 * vertex_y;
int y = scene->a4 * vertex_x + scene->a5 * vertex_y + scene->a6 * vertex_z;
int z = scene->a7 * vertex_x + scene->a8 * vertex_y + scene->a9 * vertex_z;
/* perspective */
if (z < 0) { /* z < near * 128 * 128 */
vertex->x = -(x * scene->scale_coef + 8192) / z + shift_x;
vertex->y = -(y * scene->scale_coef + 8192) / z + shift_y;
vertex->z = 8192 / z;
/* calcul de z normalise entre les deux plans de clipping */
vertex->z_normalized = -(0xFFFF *
(scene->near_coef * z + scene->far_coef) + 32767) / z;
} else
vertex->z = 1;
}

121
src/render.c Normal file
View File

@ -0,0 +1,121 @@
/* *****************************************************************************
* render.c -- draw the triangles.
* Copyright (C) 2017 Olivier "Ninestars" Lanneau
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libwindmill.
* libwindmill is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libwindmill 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libwindmill; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include <libwindmill/internals.h>
void wml_render_triangle(wml_scene_t *scene,
wml_vertex_t *vertex1, wml_vertex_t *vertex2, wml_vertex_t *vertex3,
wml_texture_t *texture)
{
/* calcul du rectangle circonscrit au triangle */
int min_x = max(scene->viewport_x1 - 64,
min(vertex0->x, min(vertex1->x, vertex2->x)));
int max_x = min(scene->viewport_x2 - 64,
max(vertex0->x, max(vertex1->x, vertex2->x)));
int min_y = max(scene->viewport_y1 - 32,
min(vertex0->y, min(vertex1->y, vertex2->y)));
int max_y = min(scene->viewport_y2 - 32,
max(vertex0->y, max(vertex1->y, vertex2->y)));
/* pré-calcul des coordonnées de la texture */
int tx0 = vertex0->tx * vertex0->z;
int ty0 = vertex0->ty * vertex0->z;
int tx1 = vertex1->tx * vertex1->z;
int ty1 = vertex1->ty * vertex1->z;
int tx2 = vertex2->tx * vertex2->z;
int tx2 = vertex2->ty * vertex2->z;
/* calcul des produits vectoriels */
int px = min_x, py = min_y;
int w0_start = wml_edge_start(vertex1, vertex2, px, py);
int w0_step_x = wml_edge_step_x(vertex1, vertex2);
int w0_step_y = wml_edge_step_y(vertex1, vertex2);
int w1_start = wml_edge_start(vertex2, vertex0, px, py);
int w1_step_x = wml_edge_step_x(vertex2, vertex0);
int w1_step_y = wml_edge_step_y(vertex2, vertex0);
int w2_start = wml_edge_start(vertex0, vertex1, px, py);
int w2_step_x = wml_edge_step_x(vertex0, vertex1);
int w2_step_y = wml_edge_step_y(vertex0, vertex1);
/* calcul de l'aire du triangle */
int area = wml_edge(vertex0, vertex1, vertex2);
/* ? */
int z_num_start = (w0_start * vertex0->z_normalized
+ w1_start * vertex1->z_normalized
+ w2_start * vertex2->z_normalized) / area;
int z_num_step_x = (w0_step_x * vertex0->z_normalized
+ w1_step_x * vertex1->z_normalized
+ w2_step_x * vertex2->z_normalized) / area;
int z_num_step_y = (w0_step_y * vertex0->z_normalized
+ w1_step_y * vertex1->z_normalized
+ w2_step_y * vertex2->z_normalized) / area;
/* ? */
int z_div_start = w0_start * vertex0->z
+ w1_start * vertex1->z
+ w2_start * vertex2->z;
int z_div_step_x = w0_step_x * vertex0->z
+ w1_step_x * vertex1->z
+ w2_step_x * vertex2->z;
int z_div_step_y = w0_step_y * vertex0->z
+ w1_step_y * vertex1->z
+ w2_step_y * vertex2->z;
/* pré-calcul largeur en octet des tableaux */
int nbw_tex = (texture->width - 1) / 8 + 1;
for (int x = min_x; x <= max_x; x++) {
int w0 = w0_start, w1 = w1_start, w2 = w2_start;
int z_num = z_num_start, z_div = z_div_start;
int offset_vram = (x >> 3) + 520;
char mask_vram = 128 >> (x & 7);
/* parcours en colonne */
for (int y = min_y; y <= max_y; y++) {
if (w0 >= 0 && w1 >= 0 && w2 >= 0 && z_num > 0) {
int address = x + y * z_buffer_width + z_buffer_offset;
if (z_num <= z_buffer[address]) {
z_buffer[address] = z_num;
/* calcul des coordonnées pour la texture */
int f_tx = (w0 * tx0 + w1 * tx1 + w2 * tx2) / z_div;
int f_ty = (w0 * ty0 + w1 * ty1 + w2 * ty2) / z_div;
/* calcul du masque pour l'octet */
char mask_tx = 128 >> (f_tx & 7);
int black = texture->sprite[(f_tx >> 3) + (f_ty * nbw_tex)]
& mask_tx;
/* affichage du pixel */
if (black) vram[(y << 4) + offset_vram] |= mask_vram;
else vram[(y << 4) + offset_vram] &= ~mask_vram;
}
}
w0 += w0_step_y;
w1 += w1_step_y;
w2 += w2_step_y;
z_num += z_num_step_y;
z_div += z_div_step_y;
}
w0_start += w0_step_x;
w1_start += w1_step_x;
w2_start += w2_step_x;
z_num_start += z_num_step_x;
z_div_start += z_div_step_x;
}
}

72
src/update.c Normal file
View File

@ -0,0 +1,72 @@
/* *****************************************************************************
* update.c -- update the scene.
* Copyright (C) 2017 Olivier "Ninestars" Lanneau
* Copyright (C) 2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libwindmill.
* libwindmill is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libwindmill 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libwindmill; if not, see <http://www.gnu.org/licenses/>.
* ************************************************************************** */
#include <libwindmill/internals.h>
/**
* wml_update_camera:
* Update the camera.
*
* @arg scene the scene to update.
*/
void wml_update_camera(wml_scene_t *scene)
{
scene->camera_yaw = (int)(scene->camera_yaw + 360) % 360;
float camera_yaw_rad = M_PI * scene->camera_yaw / 180.0;
/* calculate intermediate value */
float camera_pitch_rad = M_PI * scene->camera_pitch / 180.0;
float cos_yaw = cosf(camera_yaw_rad), sin_yaw = sinf(camera_yaw_rad);
float cos_pitch = cosf(camera_pitch_rad);
float sin_pitch = sinf(camera_pitch_rad);
/* set final values */
scene->a1 = 128.0 * cos_yaw;
scene->a2 = 128.0 * -sin_yaw;
scene->a3 = 0.0;
scene->a4 = 128.0 * cos_pitch * sin_yaw;
scene->a5 = 128.0 * cos_pitch * cos_yaw;
scene->a6 = 128.0 * -sin_pitch;
scene->a7 = 128.0 * sin_pitch * sin_yaw;
scene->a8 = 128.0 * sin_pitch * cos_yaw;
scene->a9 = 128.0 * cos_pitch;
}
/**
* wml_update_viewport:
* Update the viewport.
*
* @arg scene the scene to update.
*/
void wml_update_viewport(wml_scene_t *scene)
{
free(scene->z_buffer);
scene->shift_x = (scene->viewport_x1 + scene->viewport_x2 - 128) / 2;
scene->shift_y = (scene->viewport_y1 + scene->viewport_y2 - 64) / 2;
scene->z_buffer_size = (scene->viewport_x2 - scene->viewport_x1)
* (scene->viewport_y2 -scene->viewport_y2);
scene->z_buffer = (unsigned short*)calloc(scene->z_buffer_size, 2);
scene->z_buffer_width = scene->viewport_x2 - scene->viewport_x1;
scene->z_buffer_offset = 64 - scene->viewport_x1
+ scene->z_buffer_width * (32 - scene->viewport_y1);
memset(scene->z_buffer, 0xFF, scene->z_buffer_size * 2);
}